using System;
using System.Collections.Generic;
using System.Xml;
using Orienteering.Standard;

namespace Orienteering.Competition {
    public class Category {
        internal Orienteering.Data.Category data;

        public Category(string _name, Course _course, DataBase dataBase) {
            data = new Orienteering.Data.Category(_name, _course.data);
            try {
                _course.Category(Name, dataBase);
            }
            catch (DoesntExist) {
                this.Save(dataBase);
            }
        }

        public Category(Orienteering.Data.Category _data) {
            data = _data;
        }

        public Category(XmlNode xml, Course cour, DataBase dataBase) {
            data = new Orienteering.Data.Category();
            foreach (XmlAttribute xmlattr in xml.Attributes) {
                if (xmlattr.Name == "name")
                    Name = xmlattr.Value;
                if (xmlattr.Name == "firstTime")
                    FirstTime = Convert.ToInt32(xmlattr.Value);
                if (xmlattr.Name == "interval")
                    Interval = Convert.ToInt32(xmlattr.Value);
            }
            Course = cour;
            try {
                cour.Category(Name, dataBase);
            }
            catch (DoesntExist) {
                this.Save(dataBase);
            }
        }

        public string Name {
            get { return data.Name; }
            set { data.Name = value; }
        }

        public Course Course {
            get { return new Course(data.Course); }
            set { data.Course = value.data; }
        }

        public int FirstTime {
            get { return data.FirstTime; }
            set { data.FirstTime = value; }
        }

        public int Interval {
            get { return data.Interval; }
            set { data.Interval = value; }
        }

        public void DrawTimes(DataBase dataBase) {
            List<Result> results = Results(dataBase);
            Random random = new Random();
            
            for (int i=0; i<results.Count; i++) {
                int y = i+random.Next(results.Count-i);

                Result tmp = results[i];
                results[i] = results[y];
                results[y] = tmp;
                results[i].Start = Course.Stage.StartTime;
                results[i].Start = results[i].Start.AddMinutes(i*Interval+FirstTime);
                results[i].Save(dataBase);
            }
        }

        public List<Result> Results(DataBase dataBase) {
            List<Result> res = new List<Result>();
            foreach (Orienteering.Data.Result result in data.Results(dataBase.data))
                res.Add(new Result(result));
            return res;
        }

        public void Save(DataBase dataBase) {
            data.Save(dataBase.data);
        }

        public XmlNode Xml(XmlDocument xml) {
            XmlNode res = xml.CreateNode("element", "category", "");
            XmlAttribute nameAttr = (XmlAttribute)xml.CreateNode("attribute", "name", "");
            nameAttr.Value = Name;
            res.Attributes.Append(nameAttr);

            XmlAttribute firstTimeAttr = (XmlAttribute)xml.CreateNode("attribute", "firstTime", "");
            firstTimeAttr.Value = FirstTime.ToString();
            res.Attributes.Append(firstTimeAttr);

            XmlAttribute intervalAttr = (XmlAttribute)xml.CreateNode("attribute", "interval", "");
            intervalAttr.Value = Interval.ToString();
            res.Attributes.Append(intervalAttr);

            return res;
        }

        private class StartComp : IComparable<StartComp> {
            public Result Result;

            public StartComp(Result result) {
                Result = result;
            }

            public int CompareTo(StartComp a) {
                if (a.Result.Start < this.Result.Start) return 1;
                else {
                    if (a.Result.Start > this.Result.Start) return -1;
                    else return this.Result.Runner.Name.CompareTo(a.Result.Runner.Name);
                }
            }
        }

        public XmlNode StartList(XmlDocument xml, DataBase dataBase) {
            XmlNode res = xml.CreateNode("element", "tr", "");
            XmlNode nameNode = (XmlNode)xml.CreateNode("element", "th", "");
            nameNode.InnerText = Name;
            res.AppendChild(nameNode);

            XmlAttribute colspanAttr = (XmlAttribute)xml.CreateNode("attribute", "colspan", "");
            colspanAttr.Value = "3";
            nameNode.Attributes.Append(colspanAttr);

            List<StartComp> zoz = new List<StartComp>();
            foreach (Result result in Results(dataBase))
                zoz.Add(new StartComp(result));

            zoz.Sort();

            for (int i = 0; i < zoz.Count; i++)
                res.AppendChild(zoz[i].Result.StartTime(xml, i+1));

            return res;
        }

        private class FinishComp : IComparable<FinishComp> {
            public Result Result;
            public TimeSpan Time;

            public FinishComp(Result result) {
                Result = result;
                Time = result.Finish - result.Start;
            }

            public int CompareTo(FinishComp a) {
                if (a.Time < this.Time) return 1;
                else {
                    if (a.Time > this.Time) return -1;
                    else return this.Result.Runner.Name.CompareTo(a.Result.Runner.Name);
                }
            }
        }

        public XmlNode Results(XmlDocument xml, DataBase dataBase) {
            XmlNode res = xml.CreateNode("element", "tr", "");
            XmlNode nameNode = (XmlNode)xml.CreateNode("element", "th", "");
            nameNode.InnerText = Name;
            res.AppendChild(nameNode);

            XmlAttribute colspanAttr = (XmlAttribute)xml.CreateNode("attribute", "colspan", "");
            colspanAttr.Value = "3";
            nameNode.Attributes.Append(colspanAttr);

            List<FinishComp> zoz = new List<FinishComp>();
            foreach (Result result in Results(dataBase))
                if (result.ResultType == ResultType.Ok)
                    zoz.Add(new FinishComp(result));

            zoz.Sort();
            for (int i = 0; i < zoz.Count; i++)
                res.AppendChild(zoz[i].Result.ResultXml(xml, i+1));

            foreach (Result result in Results(dataBase))
                if (result.ResultType == ResultType.Disq)
                    res.AppendChild(result.ResultXml(xml, -1));

            return res;
        }
    }
}
