using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using ZionSchematics.Models.Boundaries;
using ZionSchematics.Models.SearchConstraintTypes;
using ZionSchematics.Models.SearchContentTypes;
using ZionSchematics.Models.SearchModes;
using ZionSchematics.Models.SearchNearestTypes;
using ZionSchematics.Models.SearchRelationTypes;

namespace ZionSchematics.Models
{
    [Serializable]
    public class SearchElements
    {
        public Header Header { get; set; }
        public Footer Footer { get; set; }
        public Fields Fields { get; set; }

        public List<Field> All
        {
            get
            {
                return Header.Elements.Union(Footer.Elements).Union(Fields.Elements).ToList();
            }
        }

        public XmlElement Save(XmlDocument context)
        {

            XmlElement search_elements = context.CreateElement(@"search-elements");

            if (this.Header != null)
                search_elements.AppendChild(this.Header.Save(context));
            if (this.Fields != null)
                search_elements.AppendChild(this.Fields.Save(context));
            if (this.Footer != null)
                search_elements.AppendChild(this.Footer.Save(context));

            return search_elements;
        }

        public SearchElements()
        {
            this.Header = new Header();
            this.Footer = new Footer();
            this.Fields = new Fields();
        }

        public SearchElements(XmlNode node)
        {
            this.Header = new Models.Header();
            this.Footer = new Models.Footer();
            this.Fields = new Models.Fields();

            this.Header.Elements = LoadFields(node.SelectSingleNode(@"header"));
            this.Footer.Elements = LoadFields(node.SelectSingleNode(@"footer"));
            this.Fields.Elements = LoadFields(node.SelectSingleNode(@"fields"));
        }

        private List<Field> LoadFields(XmlNode root)
        {
            List<Field> list = new List<Field>();

            foreach (XmlElement node in root)
            {
                List<string> values = new List<string>();

                if (node.SelectSingleNode(@"search-options").SelectSingleNode(@"search-values") != null)
                    foreach (XmlElement value in node.SelectSingleNode(@"search-options").SelectSingleNode(@"search-values").SelectNodes(@"value"))
                    {
                        values.Add(value.InnerText);
                    }

                List<ISearchAreaConstraints> searchareas = new List<ISearchAreaConstraints>();
                if (node.SelectSingleNode(@"search-constraints").SelectSingleNode(@"areas") != null)
                    foreach (XmlElement Area in node.SelectSingleNode(@"search-constraints").SelectSingleNode(@"areas").SelectNodes(@"area"))
                    {
                        ISearchAreaConstraints a = SearchAreaConstraintFactory.Construct(Area.SelectSingleNode(@"type").InnerText);
                        a.Ranges = Area.SelectSingleNode(@"ranges").InnerText;
                        a.Regions = Area.SelectSingleNode(@"regions").InnerText;
                        searchareas.Add(a);
                    }

                List<string> excludedelements = new List<string>();
                if (node.SelectSingleNode(@"search-constraints").SelectSingleNode(@"areas") != null)
                    foreach (XmlElement ExcludedElement in node.SelectSingleNode(@"search-constraints").SelectSingleNode(@"areas").SelectNodes(@"area"))
                    {
                        excludedelements.Add(ExcludedElement.InnerText);
                    }

                List<IRelation> relations = new List<IRelation>();
                if (node.SelectSingleNode(@"search-relations").SelectSingleNode(@"relations") != null)
                    foreach (XmlElement relation in node.SelectSingleNode(@"search-relations").SelectSingleNode(@"relations").SelectNodes(@"relation"))
                    {
                        IRelation iRelation = SearchRelationFactory.Construct(relation.SelectSingleNode(@"type").InnerText);

                        iRelation.Reference = relation.SelectSingleNode(@"reference").InnerText;
                        iRelation.Offset = int.Parse(relation.SelectSingleNode(@"offset").InnerText);
                        iRelation.Boundary = BoundaryFactory.Construct(relation.SelectSingleNode(@"boundary").InnerText);
                        relations.Add(iRelation);
                    }

                INearest nearest = null;
                if (node.SelectSingleNode(@"search-relations").SelectSingleNode(@"neighborhood") != null &&
                    node.SelectSingleNode(@"search-relations").SelectSingleNode(@"neighborhood")
                    .SelectSingleNode(@"nearest") != null)
                {
                    nearest = NearestFactory.Construct(
                        node.SelectSingleNode(@"search-relations")
                        .SelectSingleNode(@"neighborhood")
                        .SelectSingleNode(@"nearest")
                        .SelectSingleNode(@"type").InnerText);

                    if (node.SelectSingleNode(@"search-relations").SelectSingleNode(@"neighborhood").SelectSingleNode(@"nearest").SelectSingleNode(@"reference") != null &&
                        node.SelectSingleNode(@"search-relations").SelectSingleNode(@"neighborhood").SelectSingleNode(@"nearest").SelectSingleNode(@"reference").InnerText != String.Empty)
                        nearest.Reference = node.SelectSingleNode(@"search-relations").SelectSingleNode(@"neighborhood").SelectSingleNode(@"nearest").SelectSingleNode(@"reference").InnerText;

                    if (node.SelectSingleNode(@"search-relations").SelectSingleNode(@"neighborhood").SelectSingleNode(@"nearest").SelectSingleNode(@"x") != null &&
                        node.SelectSingleNode(@"search-relations").SelectSingleNode(@"neighborhood").SelectSingleNode(@"nearest").SelectSingleNode(@"x").InnerText != String.Empty)
                        nearest.X = int.Parse(node.SelectSingleNode(@"search-relations").SelectSingleNode(@"neighborhood").SelectSingleNode(@"nearest").SelectSingleNode(@"x").InnerText);

                    if (node.SelectSingleNode(@"search-relations").SelectSingleNode(@"neighborhood").SelectSingleNode(@"nearest").SelectSingleNode(@"y") != null &&
                        node.SelectSingleNode(@"search-relations").SelectSingleNode(@"neighborhood").SelectSingleNode(@"nearest").SelectSingleNode(@"y").InnerText != String.Empty)
                        nearest.Y = int.Parse(node.SelectSingleNode(@"search-relations").SelectSingleNode(@"neighborhood").SelectSingleNode(@"nearest").SelectSingleNode(@"y").InnerText);

                }

                List<string> excludedElements = new List<string>();

                if (node.SelectSingleNode(@"search-options").SelectSingleNode(@"excluded-elements") != null)
                    foreach (XmlElement element in node.SelectSingleNode(@"search-options").SelectSingleNode(@"excluded-elements").SelectNodes(@"element"))
                    {
                        excludedElements.Add(element.InnerText);
                    }

                list.Add(new Field(
                        /*Name*/(node.SelectSingleNode(@"name") != null) ? node.SelectSingleNode(@"name").InnerText : string.Empty,
                        /*FullName*/(node.SelectSingleNode(@"full-name") != null) ? node.SelectSingleNode(@"full-name").InnerText : string.Empty,
                        /*Comment*/(node.SelectSingleNode(@"comment") != null) ? node.SelectSingleNode(@"comment").InnerText : string.Empty,
                        /*Export*/(node.SelectSingleNode(@"export") != null) ? Boolean.Parse(node.SelectSingleNode(@"export").InnerText) : true,
                        /*Verification*/(node.SelectSingleNode(@"verification") != null) ? Boolean.Parse(node.SelectSingleNode(@"verification").InnerText) : true,
                        /*Script*/ (node.SelectSingleNode(@"script") != null) ? node.SelectSingleNode(@"script").InnerText : string.Empty,
                        /*Search Control*/(node.SelectSingleNode(@"search-control") != null) ?
                        new SearchControl(
                            node.SelectSingleNode(@"search-control").SelectSingleNode(@"type").InnerText,
                            int.Parse(node.SelectSingleNode(@"search-control").SelectSingleNode(@"hypotheses").InnerText)
                        ) : null,
                        /*Search Options*/(node.SelectSingleNode(@"search-options") != null) ?
                        new SearchOptions(
                            SearchModeFactory.construct(node.SelectSingleNode(@"search-options").SelectSingleNode(@"search-mode")?.InnerText),
                            ContentTypeFactory.construct(node.SelectSingleNode(@"search-options").SelectSingleNode(@"content-type")?.InnerText),
                            (node.SelectSingleNode(@"search-options").SelectSingleNode(@"rect")?.InnerText != string.Empty) ?
                            new ZionVault.Basic.Location(
                                node.SelectSingleNode(@"search-options").SelectSingleNode(@"rect")?.InnerText) : null,
                            (node.SelectSingleNode(@"search-options").SelectSingleNode(@"min-length") != null) ? int.Parse(node.SelectSingleNode(@"search-options").SelectSingleNode(@"min-length").InnerText) : 0,
                            (node.SelectSingleNode(@"search-options").SelectSingleNode(@"max-length") != null) ? int.Parse(node.SelectSingleNode(@"search-options").SelectSingleNode(@"max-length").InnerText) : 0,
                            (node.SelectSingleNode(@"search-options").SelectSingleNode(@"max-space-between-words") != null) ? int.Parse(node.SelectSingleNode(@"search-options").SelectSingleNode(@"max-space-between-words").InnerText) : 0,
                            bool.Parse(
                                (node.SelectSingleNode(@"search-options").SelectSingleNode(@"ignore-case") != null) ?
                                node.SelectSingleNode(@"search-options").SelectSingleNode(@"ignore-case").InnerText : @"true"),
                            bool.Parse(
                                (node.SelectSingleNode(@"search-options").SelectSingleNode(@"ignore-pattern-whitespace") != null) ?
                                node.SelectSingleNode(@"search-options").SelectSingleNode(@"ignore-pattern-whitespace").InnerText : @"true"),
                            bool.Parse(
                                (node.SelectSingleNode(@"search-options").SelectSingleNode(@"whole-words-only") != null) ?
                                node.SelectSingleNode(@"search-options").SelectSingleNode(@"whole-words-only").InnerText : @"true"),
                            (node.SelectSingleNode(@"search-options").SelectSingleNode(@"min-number-of-lines") != null) ? int.Parse(node.SelectSingleNode(@"search-options").SelectSingleNode(@"min-number-of-lines").InnerText) : 0,
                            (node.SelectSingleNode(@"search-options").SelectSingleNode(@"max-number-of-lines") != null) ? int.Parse(node.SelectSingleNode(@"search-options").SelectSingleNode(@"max-number-of-lines").InnerText) : 0,
                            (node.SelectSingleNode(@"search-options").SelectSingleNode(@"max-number-of-lines") != null) ? int.Parse(node.SelectSingleNode(@"search-options").SelectSingleNode(@"max-number-of-lines").InnerText) : 0,
                            (node.SelectSingleNode(@"search-options").SelectSingleNode(@"max-percentage-of-errors") != null) ? int.Parse(node.SelectSingleNode(@"search-options").SelectSingleNode(@"max-percentage-of-errors").InnerText) : 0,
                            (node.SelectSingleNode(@"search-options").SelectSingleNode(@"max-number-of-errors") != null) ? int.Parse(node.SelectSingleNode(@"search-options").SelectSingleNode(@"max-number-of-errors").InnerText) : 0,
                            values.ToArray(),
                            excludedElements
                        ) : null,

                        new SearchConstraints(searchareas, excludedelements),
                        new SearchRelations(relations, nearest)

                    ));


                /*list.Add(new Field(
                    (node.SelectSingleNode(@"name") != null) ? node.SelectSingleNode(@"name").InnerText : string.Empty,
                    (node.SelectSingleNode(@"full-name") != null) ? node.SelectSingleNode(@"full-name").InnerText : string.Empty,
                    (node.SelectSingleNode(@"comment") != null) ? node.SelectSingleNode(@"comment").InnerText : string.Empty,
                    (node.SelectSingleNode(@"export") != null) ? Boolean.Parse(node.SelectSingleNode(@"export").InnerText) : true,
                    (node.SelectSingleNode(@"verification") != null) ? Boolean.Parse(node.SelectSingleNode(@"verification").InnerText) : true,                    
                    (node.SelectSingleNode(@"script") != null) ? node.SelectSingleNode(@"script").InnerText : string.Empty,
                    (node.SelectSingleNode(@"search-control") != null) ?
                        new SearchControl(
                            node.SelectSingleNode(@"search-control").SelectSingleNode(@"type").InnerText,
                            int.Parse(node.SelectSingleNode(@"search-control").SelectSingleNode(@"hypotheses").InnerText)
                        ) : null,
                    (node.SelectSingleNode(@"search-options") != null) ?
                        new SearchOptions(
                            SearchModeFactory.construct(node.SelectSingleNode(@"search-options").SelectSingleNode(@"search-mode")?.InnerText),
                            ContentTypeFactory.construct(node.SelectSingleNode(@"search-options").SelectSingleNode(@"content-type")?.InnerText),
                            new Oracle.Usable.Location(
                                node.SelectSingleNode(@"search-options").SelectSingleNode(@"rect")?.InnerText),
                            (node.SelectSingleNode(@"search-options").SelectSingleNode(@"min-length") != null) ? int.Parse(node.SelectSingleNode(@"search-options").SelectSingleNode(@"min-length").InnerText) : 0,
                            (node.SelectSingleNode(@"search-options").SelectSingleNode(@"max-length") != null) ? int.Parse(node.SelectSingleNode(@"search-options").SelectSingleNode(@"max-length").InnerText) : 0,
                            (node.SelectSingleNode(@"search-options").SelectSingleNode(@"max-space-between-words") != null) ? int.Parse(node.SelectSingleNode(@"search-options").SelectSingleNode(@"max-space-between-words").InnerText) : 0,
                            bool.Parse(
                                (node.SelectSingleNode(@"search-options").SelectSingleNode(@"ignore-case") != null) ?
                                node.SelectSingleNode(@"search-options").SelectSingleNode(@"ignore-case").InnerText : @"true"),
                            bool.Parse(
                                (node.SelectSingleNode(@"search-options").SelectSingleNode(@"ignore-pattern-whitespace") != null) ?
                                node.SelectSingleNode(@"search-options").SelectSingleNode(@"ignore-pattern-whitespace").InnerText : @"true"),
                            bool.Parse(
                                (node.SelectSingleNode(@"search-options").SelectSingleNode(@"whole-words-only") != null) ?
                                node.SelectSingleNode(@"search-options").SelectSingleNode(@"whole-words-only").InnerText : @"true"),
                            (node.SelectSingleNode(@"search-options").SelectSingleNode(@"min-number-of-lines") != null) ? int.Parse(node.SelectSingleNode(@"search-options").SelectSingleNode(@"min-number-of-lines").InnerText) : 0,
                            (node.SelectSingleNode(@"search-options").SelectSingleNode(@"max-number-of-lines") != null) ? int.Parse(node.SelectSingleNode(@"search-options").SelectSingleNode(@"max-number-of-lines").InnerText) : 0,
                            (node.SelectSingleNode(@"search-options").SelectSingleNode(@"max-number-of-lines") != null) ? int.Parse(node.SelectSingleNode(@"search-options").SelectSingleNode(@"max-number-of-lines").InnerText) : 0,
                            (node.SelectSingleNode(@"search-options").SelectSingleNode(@"max-percentage-of-errors") != null) ? int.Parse(node.SelectSingleNode(@"search-options").SelectSingleNode(@"max-percentage-of-errors").InnerText) : 0,
                            (node.SelectSingleNode(@"search-options").SelectSingleNode(@"max-number-of-errors") != null) ? int.Parse(node.SelectSingleNode(@"search-options").SelectSingleNode(@"max-number-of-errors").InnerText) : 0,
                            values.ToArray()
                        ) : null,
                        new SearchConstraints(searchareas, excludedelements),
                        new SearchRelations(relations, nearest)
                    ));*/
            }

            return list;
        }
    }
}

