using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Xml;

namespace ZionVault.Binder.Output
{
    public class Page : IDisposable
    {
        public void Dispose()
        {
            if (this.SearchElements != null)
                foreach (Field f in SearchElements)
                    f.Dispose();

            GC.SuppressFinalize(this);
        }

        public ConcurrentBag<Field> SearchElements { get; set; }

        public ConcurrentBag<Field> Header
        {
            get
            {
                return new ConcurrentBag<Field>(from Field field in SearchElements
                        where field.FullName.StartsWith(@"SearchElements.Header")
                        select field);
            }
        }

        public ConcurrentBag<Field> Footer
        {
            get
            {
                return new ConcurrentBag<Field>(from Field field in SearchElements
                        where field.FullName.StartsWith(@"SearchElements.Footer")
                        select field);
            }
        }

        public ConcurrentBag<Field> Fields
        {
            get
            {
                return new ConcurrentBag<Field>(from Field field in SearchElements
                        where field.FullName.StartsWith(@"SearchElements.Fields")
                        select field);
            }
        }

        public string FullText { get; set; }

        public int Rotation { get; set; }

        public int Index { get; set; }

        public string Status { get; set; }

        public string Type { get; set; }

        public Page()
        {
            SearchElements = new ConcurrentBag<Field>();
            Rotation = 0;
            Status = string.Empty;
            Type = string.Empty;
            FullText = string.Empty;
        }

        public Page(string fullText, int rotation, int index, string status, string type, ConcurrentBag<Field> searchElements)
        {
            SearchElements = searchElements;
            FullText = fullText;
            Rotation = rotation;
            Index = index;
            Status = status;
            Type = type;
        }

        public Page(string text)
        {
            this.FullText = text;
            SearchElements = new ConcurrentBag<Field>();
            Rotation = 0;
            Status = string.Empty;
            Type = string.Empty;
        }

        public Page(XmlElement element)
        {
            SearchElements = new ConcurrentBag<Field>();
            Type = element.Attributes[@"Type"]?.Value ?? string.Empty;
            Index = int.Parse(element.Attributes[@"Index"].Value);
            Rotation = int.Parse(element.Attributes[@"Rotation"].Value);
            Status = element.Attributes[@"Status"]?.Value ?? string.Empty;

            var nodeList = element.SelectSingleNode(@"fields").ChildNodes;

            if (nodeList.Count > 0)
            {
                ConcurrentBag<XmlElement> bag = new ConcurrentBag<XmlElement>(nodeList.Cast<XmlElement>());

                Parallel.ForEach(
                    bag,
                    new ParallelOptions { MaxDegreeOfParallelism = 4 },
                    item =>
                    {
                        SearchElements.Add(new Field(item));
                    });
            }
        }

        public XmlElement Export(XmlDocument context)
        {
            XmlElement tag = context.CreateElement(@"page");
            XmlElement fields = context.CreateElement(@"fields");

            tag.SetAttribute(@"Type", Type);
            tag.SetAttribute(@"Index", Index.ToString());
            tag.SetAttribute(@"Rotation",  Rotation.ToString());
            tag.SetAttribute(@"Status", Status);

            foreach (Field field in SearchElements)
                if (field.Exportable)
                    fields.AppendChild(field.Export(context));

            tag.AppendChild(fields);
            return tag;
        }
        
        public Page Clone()
        {
            return new Page(this.FullText, this.Rotation, this.Index, this.Status, this.Type,
                new ConcurrentBag<Field>(this.SearchElements.Select(f => f.Clone())));
        }
    }
}
