using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Ciloci.Flee;

namespace ThinkGeo.MapSuite.Core
{
    public class FleeBooleanStyle : Style
    {
        private string fleeExpression;
        private Collection<Style> customTrueStyles;
        private Collection<Style> customFalseStyles;
        private Dictionary<string, object> userVariables;
        private Collection<string> columnVariables;
        private Collection<Type> staticTypes;

        public FleeBooleanStyle()
            : this(string.Empty, new Collection<Style>(), new Collection<Style>())
        {
        }

        public FleeBooleanStyle(string fleeExpression)
            : this(fleeExpression, new Collection<Style>(), new Collection<Style>())
        {
        }

        private FleeBooleanStyle(string fleeExpression, Collection<Style> trueCustomStyles, Collection<Style> falseCustomStyles)
        {
            this.fleeExpression = fleeExpression;
            this.customTrueStyles = trueCustomStyles;
            this.customFalseStyles = falseCustomStyles;
            userVariables = new Dictionary<string, object>();
            columnVariables = new Collection<string>();
            staticTypes = new Collection<Type>();
        }

        public string FleeExpression
        {
            get { return fleeExpression; }
            set { fleeExpression = value; }
        }

        public Collection<Type> StaticTypes
        {
            get { return staticTypes; }            
        }

        public Collection<string> ColumnVariables
        {
            get { return columnVariables; }            
        }

        public Dictionary<string, object> UserVariables
        {
            get { return userVariables; }            
        }

        public Collection<Style> CustomTrueStyles
        {
            get { return customTrueStyles; }
        }

        public Collection<Style> CustomFalseStyles
        {
            get { return customFalseStyles; }
        }

        protected override void DrawCore(IEnumerable<Feature> features, GeoCanvas canvas, Collection<SimpleCandidate> labelsInThisLayer, Collection<SimpleCandidate> labelsInAllLayers)
        {
            ExpressionContext context = new ExpressionContext();

            // Add all of the user variables
            foreach (string customVariableKey in userVariables.Keys)
            {
                context.Variables.Add(customVariableKey, userVariables[customVariableKey]);
            }

            // Add all of the column variables
            foreach (string columnVariable in columnVariables)
            {
                context.Variables.Add(columnVariable, string.Empty);
            }

            // Add all of our static types we need
            foreach (Type staticType in staticTypes)
            {
                context.Imports.AddType(staticType);
            }

            IGenericExpression<bool> e = context.CompileGeneric<bool>(fleeExpression);

            foreach (Feature feature in features)
            {
                // update the variables we get from the feature
                foreach (string columnName in columnVariables)
                {
                    context.Variables[columnName] = feature.ColumnValues[columnName];
                }

                bool evaluatedTrue = e.Evaluate();

                if (evaluatedTrue)
                {
                    foreach (Style style in customTrueStyles)
                    {
                        style.Draw(new Collection<Feature>() { feature }, canvas, labelsInThisLayer, labelsInAllLayers);
                    }
                }
                else
                {
                    foreach (Style style in customFalseStyles)
                    {
                        style.Draw(new Collection<Feature>() { feature }, canvas, labelsInThisLayer, labelsInAllLayers);
                    }
                }
            }
        }

        protected override Collection<string> GetRequiredColumnNamesCore()
        {
            Collection<string> requiredFieldNames = new Collection<string>();

            // Column Variables
            foreach (string columnName in columnVariables)
            {
                if (!requiredFieldNames.Contains(columnName))
                {
                    requiredFieldNames.Add(columnName);
                }
            }

            // Custom True Styles
            foreach (Style style in customTrueStyles)
            {
                Collection<string> tmpCollection = style.GetRequiredColumnNames();

                foreach (string name in tmpCollection)
                {
                    if (!requiredFieldNames.Contains(name))
                    {
                        requiredFieldNames.Add(name);
                    }
                }
            }

            // Custom False Styles
            foreach (Style style in customFalseStyles)
            {
                Collection<string> tmpCollection = style.GetRequiredColumnNames();

                foreach (string name in tmpCollection)
                {
                    if (!requiredFieldNames.Contains(name))
                    {
                        requiredFieldNames.Add(name);
                    }
                }
            }

            return requiredFieldNames;
        }
    }
}
