using System.Collections.Generic;
using System.Linq;
using BallotTemplates;
using InterpreterLibrary.Models;
using Point = InterpreterLibrary.Models.Point;

namespace InterpreterLibrary.Interpreters
{
    public abstract class AdjustmentMarkCheckerOld
    {
        public abstract AdjustmentMarkType Type { get; }

        public static AdjustmentMarkCheckerOld Create(AdjustmentMarkType type, int strokeWidth)
        {
            switch (type)
            {
                case AdjustmentMarkType.RightTack: return new RightTackMarkCheckerOld(strokeWidth);
                case AdjustmentMarkType.UpsideDownL: return new UpsideDownLMarkCheckerOld(strokeWidth);
                default: return null;
            }
        }

        public abstract bool IsMatch(IEnumerable<Point> points, CrossCutting.Rectangle bounds);
    }

    internal class RightTackMarkCheckerOld : AdjustmentMarkCheckerOld
    {
        private readonly int _strokeWidth;

        public RightTackMarkCheckerOld(int strokeWidth)
        {
            _strokeWidth = strokeWidth;
        }

        public override AdjustmentMarkType Type => AdjustmentMarkType.RightTack;

        public override bool IsMatch(IEnumerable<Point> points, CrossCutting.Rectangle bounds)
        {
            var pTopLeft = new Point(bounds.X + _strokeWidth / 2, bounds.Y + _strokeWidth / 2);
            var pBottomLeft = new Point(bounds.X + _strokeWidth / 2, bounds.Y + bounds.Height - _strokeWidth / 2);
            if (pTopLeft.Equals(pBottomLeft))
                return false;

            var pMiddleLeft = new Point(pTopLeft.X, (pBottomLeft.Y + pTopLeft.Y) / 2);
            var pMiddleRight = new Point(bounds.X + bounds.Width - _strokeWidth / 2, pMiddleLeft.Y);
            if (pMiddleLeft.Equals(pMiddleRight))
                return false;

            var segments = new List<LineSegment>
            {
                new LineSegment(pTopLeft, pBottomLeft),
                new LineSegment(pMiddleLeft, pMiddleRight)
            };

            float maxDistance = _strokeWidth;

            return points.All(p => segments.Any(s => s.DistanceToPoint(p) < maxDistance));
        }
    }

    internal class UpsideDownLMarkCheckerOld : AdjustmentMarkCheckerOld
    {
        private readonly int _strokeWidth;

        public UpsideDownLMarkCheckerOld(int strokeWidth)
        {
            _strokeWidth = strokeWidth;
        }

        public override AdjustmentMarkType Type => AdjustmentMarkType.UpsideDownL;

        public override bool IsMatch(IEnumerable<Point> points, CrossCutting.Rectangle bounds)
        {
            var pTopLeft = new Point(bounds.X + _strokeWidth / 2, bounds.Y + _strokeWidth / 2);
            var pTopRight = new Point(bounds.X + bounds.Width - _strokeWidth / 2, pTopLeft.Y);
            if (pTopRight.Equals(pTopLeft))
                return false;
            var pBottomRight = new Point(pTopRight.X, bounds.Y + bounds.Height - _strokeWidth / 2);
            if (pBottomRight.Equals(pTopRight))
                return false;

            var segments = new List<LineSegment>
            {
                new LineSegment(pTopLeft, pTopRight),
                new LineSegment(pTopRight, pBottomRight)
            };

            float maxDistance = _strokeWidth;

            foreach (var p in points)
            {
                var ok = false;
                foreach (var s in segments)
                {
                    var d = s.DistanceToPoint(p);
                    if (d <= maxDistance)
                    {
                        ok = true;
                        break;
                    }

                }

                if (!ok)
                {
                    return false;
                }
            }

            return true;
        }
    }
}
