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

namespace Kuineator.Tools
{
    public class Project
    {
        public static int T_APPLICATION = 0;

        private string filepath;
        public string currentpath;
        private List<string> configs;
        //OutputOptions
        private int outputtype;
        private string input;
        public string Input
        {
            get
            {
                return this.input;
            }
            set
            {
                this.input = value;
            }
        }
        private string compiletarget;
        public string CompileTarget
        {
            get
            {
                return this.compiletarget;
            }
            set
            {
                this.compiletarget = value;
            }
        }
        private string outputpath;
        public string OutputPath
        {
            get
            {
                return this.outputpath;
            }
            set
            {
                this.outputpath = value;
            }
        }
        private bool iconuse;
        public bool IconUse
        {
            get
            {
                return this.iconuse;
            }
            set
            {
                this.iconuse = value;
            }
        }
        private string iconpath;
        public string IconPath
        {
            get
            {
                return this.iconpath;
            }
            set
            {
                this.iconpath = value;
            }
        }
        private string sdkver;
        public string SdkVersion
        {
            get
            {
                return this.sdkver;
            }
            set
            {
                this.sdkver = value;
            }
        }
        private bool customuse;
        public bool CustomUse
        {
            get
            {
                return this.customuse;
            }
            set
            {
                this.customuse = value;
            }
        }
        private string custompath;
        public string CustomPath
        {
            get
            {
                return this.custompath;
            }
            set
            {
                this.custompath = value;
            }
        }
        private bool commanduse;
        public bool CommandUse
        {
            get
            {
                return this.commanduse;
            }
            set
            {
                this.commanduse = value;
            }
        }
        //ClassPaths
        private List<string> classpaths;
        public string[] ClassPaths
        {
            get
            {
                return this.classpaths.ToArray();
            }
            set
            {
                classpaths = new List<string>();
                foreach (string str in value)
                {
                    classpaths.Add(str);
                }
            }
        }
        //BuildOptions
        private bool warning;
        public string Warning
        {
            get
            {
                return this.warning?"True":"False";
            }
            set
            {
                this.warning = (value=="True");
            }
        }
        //IncludeLibraries
        private List<string> inclibpaths;
        public string[] IncLibPaths
        {
            get
            {
                return this.inclibpaths.ToArray();
            }
            set
            {
                inclibpaths = new List<string>();
                foreach (string str in value)
                {
                    inclibpaths.Add(str);
                }
            }
        }
        //Libraries
        private List<string> libpaths;
        public string[] LibPaths
        {
            get
            {
                return this.libpaths.ToArray();
            }
            set
            {
                libpaths = new List<string>();
                foreach (string str in value)
                {
                    libpaths.Add(str);
                }
            }
        }
        //ExternalLibraries
        private List<string> extlibpaths;
        public string[] ExtLibPaths
        {
            get
            {
                return this.extlibpaths.ToArray();
            }
            set
            {
                extlibpaths = new List<string>();
                foreach (string str in value)
                {
                    extlibpaths.Add(str);
                }
            }
        }
        //HiddenPaths
        private List<string> hiddenpaths;
        public string[] HiddenPaths
        {
            get
            {
                return this.hiddenpaths.ToArray();
            }
            set
            {
                hiddenpaths = new List<string>();
                foreach (string str in value)
                {
                    hiddenpaths.Add(str);
                }
            }
        }
        //Command Lines
        private List<string> commandlines;
        public string CommandLines
        {
            get
            {
                string str = "";
                foreach (string line in commandlines)
                {
                    str += line + "\n";
                }
                return str;
            }
            set
            {
                commandlines = new List<string>();
                int iswap = 0;
                for (int i = 0; i == -1; i = value.IndexOf('\n', i))
                {
                    if (i == 0) continue;
                    commandlines.Add(value.Substring(iswap, i - iswap));
                    iswap = i;
                }
                commandlines.Add(value.Substring(iswap,value.Length-iswap));
            }
        }
        //PreBuildCommand
        private List<string> prebuildcomlines;
        public string PreBuildCommand
        {
            get
            {
                string str = "";
                foreach (string line in prebuildcomlines)
                {
                    str += line+"\n";
                }
                return str;
            }
            set
            {
                prebuildcomlines = new List<string>();
                int iswap = 0;
                for (int i = 0; i == -1; i = value.IndexOf('\n', i))
                {
                    if(i == 0) continue;
                    prebuildcomlines.Add(value.Substring(iswap, i - iswap));
                    iswap = i;
                }
                prebuildcomlines.Add(value.Substring(iswap, value.Length - iswap));
            }
        }
        //PostBuildCommand
        private List<string> postbuildcomlines;
        public string PostBuildCommand
        {
            get
            {
                string str = "";
                foreach (string line in postbuildcomlines)
                {
                    str += line + "\n";
                }
                return str;
            }
            set
            {
                postbuildcomlines = new List<string>();
                int iswap = 0;
                for (int i = 0; i == -1; i = value.IndexOf('\n', i))
                {
                    if (i == 0) continue;
                    postbuildcomlines.Add(value.Substring(iswap, i - iswap));
                    iswap = i;
                }
                postbuildcomlines.Add(value.Substring(iswap, value.Length - iswap));
            }
        }
        //OtherOptions
        private List<string> otheroptions;
        public string OtherOptions
        {
            get
            {
                string str = "";
                foreach (string line in otheroptions)
                {
                    str += line + "\n";
                }
                return str;
            }
            set
            {
                otheroptions = new List<string>();
                int iswap = 0;
                for (int i = 0; i == -1; i = value.IndexOf('\n', i))
                {
                    if (i == 0) continue;
                    otheroptions.Add(value.Substring(iswap, i - iswap));
                    iswap = i;
                }
                otheroptions.Add(value.Substring(iswap, value.Length - iswap));
            }
        }
        //PluginStorages
        private List<string> storages;
        public string Storages
        {
            get
            {
                string str = "";
                foreach (string line in storages)
                {
                    str += line + "\n";
                }
                return str;
            }
            set
            {
                storages = new List<string>();
                int iswap = 0;
                for (int i = 0; i == -1; i = value.IndexOf('\n', i))
                {
                    if (i == 0) continue;
                    storages.Add(value.Substring(iswap, i - iswap));
                    iswap = i;
                }
                storages.Add(value.Substring(iswap, value.Length - iswap));
            }
        }
        public Project(string path)
        {
            filepath = path;
            currentpath = path.Remove(path.LastIndexOf("\\")+1);
            configs = new List<string>();
            classpaths = new List<string>();
            inclibpaths = new List<string>();
            libpaths = new List<string>();
            extlibpaths = new List<string>();
            hiddenpaths = new List<string>();
            prebuildcomlines = new List<string>();
            postbuildcomlines = new List<string>();
            otheroptions = new List<string>();
            storages = new List<string>();
            commandlines = new List<string>();
            parseProjectFile();
            saveProjectFile();
        }

        public string getFilePath()
        {
            return filepath;
        }

        public void ProjectClose()
        {
            saveProjectFile();
        }

        private void parseProjectFile()
        {
            StreamReader f = null;
            try
            {
                f = new StreamReader(filepath);
                string line;
                Regex re = new Regex(@"<.*>$");
                while ((line = f.ReadLine()) != null)
                {
                    configs.Add(re.Match(line).Value);
                }
            }
            catch
            {
                return;
            }
            finally
            {
                if (f != null)
                    f.Close();
            }

            XmlDocument doc = new XmlDocument();
            doc.Load(filepath);
            foreach (XmlNode pnode in doc.DocumentElement.ChildNodes)
            {
                switch (pnode.Name)
                {
                    case "output":
                        foreach (XmlNode snode in pnode.ChildNodes)
                        {
                            switch (snode.Name)
                            {
                                case "app":
                                    switch (snode.Attributes[0].Name)
                                    {
                                        case "outputType":
                                            switch (snode.Attributes[0].Value)
                                            {
                                                case "Application": outputtype = T_APPLICATION;
                                                    break;
                                            }
                                            break;
                                        case "input":
                                            input = snode.Attributes[0].Value;
                                            break;
                                        case "version":
                                            sdkver = snode.Attributes[0].Value;
                                            break;
                                    }
                                    break;
                                case "compile":
                                    switch (snode.Attributes[0].Name)
                                    {
                                        case "path":
                                            compiletarget = snode.Attributes[0].Value;
                                            break;
                                    }
                                    break;
                                case "outexe":
                                    switch (snode.Attributes[0].Name)
                                    {
                                        case "path":
                                            outputpath = snode.Attributes[0].Value;
                                            break;
                                    }
                                    break;
                                case "icon":
                                    switch (snode.Attributes[0].Name)
                                    {
                                        case "path":
                                            iconpath = snode.Attributes[0].Value;
                                            break;
                                        case "use":
                                            iconuse = (snode.Attributes[0].Value == "True");
                                            break;
                                    }
                                    break;
                                case "custom":
                                    switch (snode.Attributes[0].Name)
                                    {
                                        case "path":
                                            custompath = snode.Attributes[0].Value;
                                            break;
                                        case "use":
                                            customuse = (snode.Attributes[0].Value == "True");
                                            break;
                                    }
                                    break;
                                case "command":
                                    switch (snode.Attributes[0].Name)
                                    {
                                        case "use":
                                            commanduse = (snode.Attributes[0].Value == "True");
                                            break;
                                    }
                                    break;
                                default: Console.Write("#comment: " + snode.InnerText+ "\n");
                                    break;
                            }
                        }
                        break;
                    case "classpaths":
                        foreach (XmlNode snode in pnode.ChildNodes)
                        {
                            switch (snode.Name)
                            {
                                case "class":
                                    switch (snode.Attributes[0].Name)
                                    {
                                        case "path":
                                            classpaths.Add(snode.Attributes[0].Value);
                                            break;
                                    }
                                    break;
                                default: Console.Write("#comment: " + snode.InnerText+ "\n");
                                    break;
                            }
                        }
                        break;
                    case "build":
                        foreach (XmlNode snode in pnode.ChildNodes)
                        {
                            switch (snode.Name)
                            {
                                case "option":
                                    switch (snode.Attributes[0].Name)
                                    {
                                        case "warning":
                                            warning = (snode.Attributes[0].Value == "True");
                                            break;
                                    }
                                    break;
                                default: Console.Write("#comment: " + snode.InnerText+ "\n");
                                    break;
                            }
                        }
                        break;
                    case "includeLibraryPaths":
                        foreach (XmlNode snode in pnode.ChildNodes)
                        {
                            switch (snode.Name)
                            {
                                case "lib":
                                    switch (snode.Attributes[0].Name)
                                    {
                                        case "path":
                                            inclibpaths.Add(snode.Attributes[0].Value);
                                            break;
                                    }
                                    break;
                                default: Console.Write("#comment: " + snode.InnerText+ "\n");
                                    break;
                            }
                        }
                        break;
                    case "LibraryPaths":
                        foreach (XmlNode snode in pnode.ChildNodes)
                        {
                            switch (snode.Name)
                            {
                                case "lib":
                                    switch (snode.Attributes[0].Name)
                                    {
                                        case "path":
                                            libpaths.Add(snode.Attributes[0].Value);
                                            break;
                                    }
                                    break;
                                default: Console.Write("#comment: " + snode.InnerText+ "\n");
                                    break;
                            }
                        }
                        break;
                    case "externalLibraryPaths":
                        foreach (XmlNode snode in pnode.ChildNodes)
                        {
                            switch (snode.Name)
                            {
                                case "lib":
                                    switch (snode.Attributes[0].Name)
                                    {
                                        case "path":
                                            extlibpaths.Add(snode.Attributes[0].Value);
                                            break;
                                    }
                                    break;
                                default: Console.Write("#comment: " + snode.InnerText+ "\n");
                                    break;
                            }
                        }
                        break;
                    case "hiddenPaths":
                        foreach (XmlNode snode in pnode.ChildNodes)
                        {
                            switch (snode.Name)
                            {
                                case "hidden":
                                    switch (snode.Attributes[0].Name)
                                    {
                                        case "path":
                                            hiddenpaths.Add(snode.Attributes[0].Value);
                                            break;
                                    }
                                    break;
                                default: Console.Write("#comment: " + snode.InnerText+ "\n");
                                    break;
                            }
                        }
                        break;
                    case "commandlines":
                        foreach (XmlNode snode in pnode.ChildNodes)
                        {
                            switch (snode.Name)
                            {
                                case "command":
                                    switch (snode.Attributes[0].Name)
                                    {
                                        case "line":
                                            commandlines.Add(snode.Attributes[0].Value);
                                            break;
                                    }
                                    break;
                                default: Console.Write("#comment: " + snode.InnerText + "\n");
                                    break;
                            }
                        }
                        break;
                    case "preBuildCommand":
                        foreach (XmlNode snode in pnode.ChildNodes)
                        {
                            switch (snode.Name)
                            {
                                case "command":
                                    switch (snode.Attributes[0].Name)
                                    {
                                        case "line":
                                            prebuildcomlines.Add(snode.Attributes[0].Value);
                                            break;
                                    }
                                    break;
                                default: Console.Write("#comment: " + snode.InnerText+ "\n");
                                    break;
                            }
                        }
                        break;
                    case "postBuildCommand":
                        foreach (XmlNode snode in pnode.ChildNodes)
                        {
                            switch (snode.Name)
                            {
                                case "command":
                                    switch (snode.Attributes[0].Name)
                                    {
                                        case "line":
                                            postbuildcomlines.Add(snode.Attributes[0].Value);
                                            break;
                                    }
                                    break;
                                default: Console.Write("#comment: " + snode.InnerText+ "\n");
                                    break;
                            }
                        }
                        break;
                    case "options":
                        foreach (XmlNode snode in pnode.ChildNodes)
                        {
                            switch (snode.Name)
                            {
                                case "option":
                                    switch (snode.Attributes[0].Name)
                                    {
                                        case "option":
                                            otheroptions.Add(snode.Attributes[0].Value);
                                            break;
                                    }
                                    break;
                                default: Console.Write("#comment: " + snode.InnerText + "\n");
                                    break;
                            }
                        }
                        break;
                    case "storage":
                        foreach (XmlNode snode in pnode.ChildNodes)
                        {
                            switch (snode.Name)
                            {
                                case "plugin":
                                    switch (snode.Attributes[0].Name)
                                    {
                                        case "storage":
                                            storages.Add(snode.Attributes[0].Value);
                                            break;
                                    }
                                    break;
                                default: Console.Write("#comment: " + snode.InnerText + "\n");
                                    break;
                            }
                        }
                        break;
                    default:
                        Console.Write("#comment: " + pnode.InnerText + "\n");
                        break;
                }
            }
        }

        private void saveProjectFile()
        {
            StreamReader f = null;
            try
            {
                f = new StreamReader(filepath);
                string line;
                Regex re = new Regex(@"<.*>$");
                configs = null;
                configs = new List<string>();
                while ((line = f.ReadLine()) != null)
                {
                    configs.Add(re.Match(line).Value);
                }
            }
            catch
            {
                return;
            }
            finally
            {
                if (f != null)
                    f.Close();
            }

            XmlDocument doc = new XmlDocument();
            doc.Load(filepath);
            foreach (XmlNode pnode in doc.DocumentElement.ChildNodes)
            {
                switch (pnode.Name)
                {
                    case "output":
                        foreach (XmlNode snode in pnode.ChildNodes)
                        {
                            switch (snode.Name)
                            {
                                case "app":
                                    switch (snode.Attributes[0].Name)
                                    {
                                        case "outputType":
                                            switch (outputtype)
                                            {
                                                case 0: snode.Attributes[0].Value = "Application";
                                                    break;
                                            }
                                            break;
                                        case "input":
                                            snode.Attributes[0].Value = input;
                                            break;
                                        case "version":
                                            snode.Attributes[0].Value =sdkver;
                                            break;
                                    }
                                    break;
                                case "compile":
                                    switch (snode.Attributes[0].Name)
                                    {
                                        case "path":
                                            snode.Attributes[0].Value = compiletarget;
                                            break;
                                    }
                                    break;
                                case "outexe":
                                    switch (snode.Attributes[0].Name)
                                    {
                                        case "path":
                                            snode.Attributes[0].Value = outputpath;
                                            break;
                                    }
                                    break;
                                case "icon":
                                    switch (snode.Attributes[0].Name)
                                    {
                                        case "path":
                                            snode.Attributes[0].Value = iconpath;
                                            break;
                                        case "use":
                                            snode.Attributes[0].Value = iconuse?"True":"False";
                                            break;
                                    }
                                    break;
                                case "custom":
                                    switch (snode.Attributes[0].Name)
                                    {
                                        case "path":
                                            snode.Attributes[0].Value = custompath;
                                            break;
                                        case "use":
                                            snode.Attributes[0].Value = customuse ? "True" : "False";
                                            break;
                                    }
                                    break;
                                case "command":
                                    switch (snode.Attributes[0].Name)
                                    {
                                        case "use":
                                            snode.Attributes[0].Value = commanduse?"True":"False";
                                            break;
                                    }
                                    break;
                                default: Console.Write("#comment: " + snode.InnerText+ "\n");
                                    break;
                            }
                        }
                        break;
                    case "classpaths":
                        pnode.RemoveAll();
                        if (classpaths.Count == 0)
                        {
                            XmlComment comment = doc.CreateComment("example: <class path=\"...\" />");
                            pnode.AppendChild(comment);
                        }
                        else
                        {
                            foreach (string classpath in classpaths)
                            {
                                XmlElement element = doc.CreateElement("class");
                                element.SetAttribute("path", classpath);
                                pnode.AppendChild(element);
                            }
                        }
                        break;
                    case "build":
                        foreach (XmlNode snode in pnode.ChildNodes)
                        {
                            switch (snode.Name)
                            {
                                case "option":
                                    switch (snode.Attributes[0].Name)
                                    {
                                        case "warning":
                                            snode.Attributes[0].Value = warning?"True":"False";
                                            break;
                                    }
                                    break;
                                default: Console.Write("#comment: " + snode.InnerText+ "\n");
                                    break;
                            }
                        }
                        break;
                    case "includeLibraryPaths":
                        pnode.RemoveAll();
                        if (inclibpaths.Count == 0)
                        {
                            XmlComment comment = doc.CreateComment("example: <lib path=\"...\" />");
                            pnode.AppendChild(comment);
                        }
                        else
                        {
                            foreach (string inclibpath in inclibpaths)
                            {
                                XmlElement element = doc.CreateElement("lib");
                                element.SetAttribute("path", inclibpath);
                                pnode.AppendChild(element);
                            }
                        }
                        break;
                    case "LibraryPaths":
                        pnode.RemoveAll();
                        if (libpaths.Count == 0)
                        {
                           XmlComment comment = doc.CreateComment("example: <lib path=\"...\" />");
                            pnode.AppendChild(comment);
                        }
                        else
                        {
                            foreach (string libpath in libpaths)
                            {
                                XmlElement element = doc.CreateElement("lib");
                                element.SetAttribute("path", libpath);
                                pnode.AppendChild(element);
                            }
                        }
                        break;
                    case "externalLibraryPaths":
                        pnode.RemoveAll();
                        if (extlibpaths.Count == 0)
                        {
                           XmlComment comment = doc.CreateComment("example: <lib path=\"...\" />");
                            pnode.AppendChild(comment);
                        }
                        else
                        {
                            foreach (string extlibpath in extlibpaths)
                            {
                                XmlElement element = doc.CreateElement("lib");
                                element.SetAttribute("path", extlibpath);
                                pnode.AppendChild(element);
                            }
                        }
                        break;
                    case "hiddenPaths":
                        pnode.RemoveAll();
                        if (hiddenpaths.Count == 0)
                        {
                           XmlComment comment = doc.CreateComment("example: <hidden path=\"...\" />");
                            pnode.AppendChild(comment);
                        }
                        else
                        {
                            foreach (string hiddenpath in hiddenpaths)
                            {
                                XmlElement element = doc.CreateElement("hidden");
                                element.SetAttribute("path", hiddenpath);
                                pnode.AppendChild(element);
                            }
                        }
                        break;
                    case "commandlines":
                        pnode.RemoveAll();
                        if (commandlines.Count == 0)
                        {
                            XmlComment comment = doc.CreateComment("example: <command line=\"...\" />");
                            pnode.AppendChild(comment);
                        }
                        else
                        {
                            foreach (string comline in commandlines)
                            {
                                XmlElement element = doc.CreateElement("command");
                                element.SetAttribute("line", comline);
                                pnode.AppendChild(element);
                            }
                        }
                        break;
                    case "preBuildCommand":
                        pnode.RemoveAll();
                        if (prebuildcomlines.Count == 0)
                        {
                           XmlComment comment = doc.CreateComment("example: <command line=\"...\" />");
                            pnode.AppendChild(comment);
                        }
                        else
                        {
                            foreach (string prebuildcomline in prebuildcomlines)
                            {
                                XmlElement element = doc.CreateElement("command");
                                element.SetAttribute("line", prebuildcomline);
                                pnode.AppendChild(element);
                            }
                        }
                        break;
                    case "postBuildCommand":
                        pnode.RemoveAll();
                        if (postbuildcomlines.Count == 0)
                        {
                           XmlComment comment = doc.CreateComment("example: <command line=\"...\" />");
                            pnode.AppendChild(comment);
                        }
                        else
                        {
                            foreach (string postbuildcomline in postbuildcomlines)
                            {
                                XmlElement element = doc.CreateElement("command");
                                element.SetAttribute("line", postbuildcomline);
                                pnode.AppendChild(element);
                            }
                        }
                        break;
                    case "options":
                        pnode.RemoveAll();
                        if (otheroptions.Count == 0)
                        {
                           XmlComment comment = doc.CreateComment("example: <option option=\"...\" />");
                            pnode.AppendChild(comment);
                        }
                        else
                        {
                            foreach (string otheroption in otheroptions)
                            {
                                XmlElement element = doc.CreateElement("option");
                                element.SetAttribute("option", otheroption);
                                pnode.AppendChild(element);
                            }
                        }
                        break;
                    case "storage":
                        pnode.RemoveAll();
                        if (storages.Count == 0)
                        {
                           XmlComment comment = doc.CreateComment("example: <plugin storage=\"...\" />");
                            pnode.AppendChild(comment);
                        }
                        else
                        {
                            foreach (string storage in storages)
                            {
                                XmlElement element = doc.CreateElement("plugin");
                                element.SetAttribute("storage", storage);
                                pnode.AppendChild(element);
                            }
                        }
                        break;
                    default:
                        Console.Write("#comment: " + pnode.InnerText + "\n");
                        break;
                }
            }
            doc.Save(filepath);
        }
    }
}
