using System;
using System.Collections.Generic;
using System.Xml;
using System.IO.Compression;
using System.IO;
using System.Text;

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

        public Competition(string _name, DataBase dataBase) {
            data = new Orienteering.Data.Competition(_name);
            this.Save(dataBase);
        }

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

        public Competition(XmlNode xml, DataBase dataBase) {
            data = new Orienteering.Data.Competition();
            foreach (XmlAttribute xmlattr in xml.Attributes)
                if (xmlattr.Name == "name")
                    Name = xmlattr.Value;
            this.Save(dataBase);

            foreach (XmlNode node in xml.ChildNodes) {
                if (node.Name == "stage")
                    new Stage(node, this, dataBase);
                if (node.Name == "club")
                    new Club(node, this, dataBase);
            }
        }

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

        public List<Club> Clubs(string abbr, DataBase dataBase) {
            List<Club> res = new List<Club>();
            foreach (Orienteering.Data.Club club in data.Clubs(abbr, dataBase.data))
                res.Add(new Club(club));
            return res;
        }

        public List<Club> Clubs(DataBase dataBase) {
            List<Club> res = new List<Club>();
            foreach (Orienteering.Data.Club club in data.Clubs(dataBase.data))
                res.Add(new Club(club));
            return res;
        }

        public List<Stage> Stages(DataBase dataBase) {
            List<Stage> res = new List<Stage>();
            foreach (Orienteering.Data.Stage stage in data.Stages(dataBase.data))
                res.Add(new Stage(stage));
            return res;
        }

        public Stage Stage(int num, DataBase dataBase) {
            return new Stage(data.Stage(num, dataBase.data));
        }

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

        public void Save(string path, DataBase dataBase) {
            XmlDocument file = new XmlDocument(); 
            XmlNode compElement = file.CreateNode("element", "competition", "");
            XmlAttribute nameAttr = (XmlAttribute)file.CreateNode("attribute", "name", "");
            nameAttr.Value = Name;
            compElement.Attributes.Append(nameAttr);

            foreach (Stage stage in Stages(dataBase))
                compElement.AppendChild(stage.Xml(file, dataBase));

            foreach (Club club in Clubs(dataBase))
                compElement.AppendChild(club.Xml(file, dataBase));
            file.AppendChild(compElement);

            MemoryStream ms1 = new MemoryStream();
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
            settings.OmitXmlDeclaration = false;
            settings.Encoding = Encoding.UTF8;

            XmlWriter writer = XmlWriter.Create(ms1, settings);
            file.WriteTo(writer);
            writer.Flush();

            byte[] tmp = new byte[ms1.Length];
            ms1.Seek(0, SeekOrigin.Begin);
            ms1.Read(tmp, 0, (int)ms1.Length);
            ms1.Close();

            MemoryStream ms = new MemoryStream();
            GZipStream compressedZipStream = 
                new GZipStream(ms, CompressionMode.Compress, true);
            compressedZipStream.Write(tmp, 0, tmp.Length);
            compressedZipStream.Close();

            if (File.Exists(path)) File.Delete(path);
            FileStream outfile = File.Create(path);
            tmp = new byte[ms.Length];
            ms.Seek(0, SeekOrigin.Begin);
            ms.Read(tmp, 0, (int)ms.Length);
            outfile.Write(tmp, 0, tmp.Length);
            outfile.Close();
        }

        public static Competition Open(string path, DataBase dataBase) {
            FileStream infile = new FileStream(path, FileMode.Open, FileAccess.Read);
            GZipStream compressedzipStream = new GZipStream(infile, CompressionMode.Decompress, true);

            MemoryStream ms = new MemoryStream();
            int tmp;
            while (true) {
                try {
                    tmp = compressedzipStream.ReadByte();
                    if (tmp == -1) break;
                    ms.WriteByte((byte)tmp);
                }
                catch {
                    break;
                }
            }
            compressedzipStream.Close();
            infile.Close();

            ms.Seek(0, SeekOrigin.Begin);
            XmlDocument file = new XmlDocument();
            file.Load(ms);
            ms.Close();

            return new Competition(file.DocumentElement, dataBase);
        }
    }
}
