using ZionVault.Basic;
using System.Collections.Generic;
using ZionSchematics.Models.SearchRelationTypes;

namespace ZionExtractor.Controllers.LegworkFilters
{
    class Limit
    {
        /// <summary>
        /// Retorna a área de busca baseada na localização dos campos limitadores.
        /// </summary>
        /// <param name="relations">Lista de relações(campos ou coordenadas).</param>
        /// <param name="found">Lista de campos do documento.</param>
        /// <returns>Objeto do tipo ZionVault.Basic.Location</returns>
        public static Location Go(List<ZionSchematics.Models.SearchRelationTypes.IRelation> relations, List<ZionVault.Binder.Output.Field> found)
        {
            Location limit = new Location(-1, -1, -1, -1);
            if (relations != null)
            {
                foreach (IRelation relation in relations)
                    limit = LimitSearchArea(limit, found, relation);
            }
            return limit;
        }

        /// <summary>
        /// Avalia e calcula o limite.
        /// </summary>
        /// <param name="current_limit">Limite atual.</param>
        /// <param name="fields">Lista de campos do documento.</param>
        /// <param name="relation">Relação (campo ou coordenada)</param>
        /// <returns>Objeto do tipo ZionVault.Basic.Location</returns>
        private static Location LimitSearchArea(Location current_limit,
            List<ZionVault.Binder.Output.Field> fields, IRelation relation)
        {
            ZionVault.Binder.Output.Field field = Title.Go(fields, relation.Reference, true);

            if (field == null)
                return current_limit;

            switch (relation.Type)
            {
                case "Above":
                    switch (relation.Boundary.Type)
                    {
                        case "Top":
                            if (current_limit.Bottom == -1 || current_limit.Bottom > (field.Position.Top + relation.Offset))
                                current_limit.Bottom = (field.Position.Top + relation.Offset);
                            break;
                        case "Bottom":
                            if (current_limit.Bottom == -1 || current_limit.Bottom > (field.Position.Bottom + relation.Offset))
                                current_limit.Bottom = (field.Position.Bottom + relation.Offset);
                            break;
                    }
                    break;
                case "Below":
                    switch (relation.Boundary.Type)
                    {
                        case "Top":
                            if (current_limit.Top == -1 || current_limit.Top < (field.Position.Top + relation.Offset))
                                current_limit.Top = (field.Position.Top + relation.Offset);
                            break;
                        case "Bottom":
                            if (current_limit.Top == -1 || current_limit.Top < (field.Position.Bottom + relation.Offset))
                                current_limit.Top = (field.Position.Bottom + relation.Offset);
                            break;
                    }
                    break;
                case "LeftOf":
                    switch (relation.Boundary.Type)
                    {
                        case "Right":
                            if (current_limit.Right == -1 || current_limit.Right < (field.Position.Right + relation.Offset))
                                current_limit.Right = (field.Position.Right + relation.Offset);
                            break;
                        case "Left":
                            if (current_limit.Right == -1 || current_limit.Right < (field.Position.Left + relation.Offset))
                                current_limit.Right = (field.Position.Left + relation.Offset);
                            break;
                    }
                    break;
                case "RightOf":
                    switch (relation.Boundary.Type)
                    {
                        case "Right":
                            if (current_limit.Left == -1 || current_limit.Left > (field.Position.Right + relation.Offset))
                                current_limit.Left = (field.Position.Right + relation.Offset);
                            break;
                        case "Left":
                            if (current_limit.Left == -1 || current_limit.Left > (field.Position.Left + relation.Offset))
                                current_limit.Left = (field.Position.Left + relation.Offset);
                            break;
                    }
                    break;
            }

            return current_limit;
        }
    }
}
