using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Xml;
using System.IO;

namespace TIAOpennessGenerator
{
    class Block
    {
        //string PathSource = @"D:\Sources\";
        //string PathObject = @"D:\";

        

        BlockType type;
        String name;
        String typename;
        XmlNode source;

        public String Name { get { return name; } }
        public String TypeName { get { return typename; } }
        public BlockType Type { get { return type; } }
        //Jméno souboru pro generování
        public String FileName { get { return name + Block.GetExtension(type); } }
        //Jméno vzorového souboru
        public String TemplateName { get { return typename + Block.GetExtension(type); } }


        Receipt receipt = new Receipt();

        /// <summary>
        /// Vytvoření souboru obsahující datový blok dle XML předpisu
        /// </summary>
        private void WriteDataBlock()
        {
            //XmlNode Block = receipt.GetBlock("DataBlock", Number);
            string path = Receipt.PathObject + this.FileName;   //Cesta k souboru
            //Pokud existuje soubor se stejnou cestou smaž jej
            if (File.Exists(path))
                File.Delete(path);

            //Votvoření souboru
            using (StreamWriter fs = new StreamWriter(path, true, Encoding.UTF8))
            {
                string[] lines = File.ReadAllLines(Receipt.PathSource + this.TemplateName);    //přečte všechny řádky souboru a uloží je do pole stringů

                foreach (string line in lines)
                {
                    if (line.Contains("Data"))              //Vyhledání slova Data
                    {
                        int number = line.IndexOf('D', 5);     //Hledání indexu kde je písmeno D, začne se od indexu 5
                                                              
                        fs.WriteLine(line.Remove(number, 5).Insert(number, this.name));
                    }
                    else
                        fs.WriteLine(line);

                }
            }
        }

        /// <summary>
        /// Vytvoření souboru obsahující organizační blok Main OB1 (Volání funkcí, podle fpočtu funkcí v XML předpisu)
        /// </summary>
        private void WriteMainBlock()
        {       
            //pokud se jedna o první funkci, zkotroluje se pouze zda je dobře typ a jméno funkce
            if(this.source.Attributes["Postfix"].Value == "1")
            {
                XmlDocument Main = new XmlDocument();
                Main.Load(Receipt.PathSource + "Main.xml");

                //nelze přistoupit rovnou k Parts, nutno přes potomky, pořadí potomků je vždy stejný v XML
                XmlNode Parts = Main.SelectSingleNode("//NetworkSource");
                Parts = Parts.FirstChild.FirstChild;

                //Pořadí potomku vždy stejný, zadaní jména 
                Parts.FirstChild.FirstChild.Attributes["Name"].Value = this.name;
                if (this.type == BlockType.FUNCTION)
                    Parts.FirstChild.FirstChild.Attributes["BlockType"].Value = "FC";   //zadání typu

                Main.Save(Receipt.PathObject + "Main.xml");
            }
            //Pokud je pořadí funkce větší jak 1, nutno vložit cele Nody s danou funkcí, přepsat ID na všech duležitých místech
            else
            {
                XmlDocument Main = new XmlDocument();
                Main.Load(Receipt.PathObject + "Main.xml");

                XmlNode Parts = Main.SelectSingleNode("//NetworkSource");
                Parts = Parts.FirstChild.FirstChild;
                int UId;

                //získání ID z poslední prvku a jeho zvětšení o jedničku
                UId = int.Parse(Parts.LastChild.Attributes["UId"].Value);
                UId++;

                //Vytvoření kolunu
                XmlNode Call = Parts.FirstChild.Clone();
                //Přepsání ID u klonu, jména a typu
                Call.Attributes["UId"].Value = UId.ToString();
                Call.FirstChild.Attributes["Name"].Value = this.name;
                if (this.type == BlockType.FUNCTION)
                    Call.FirstChild.Attributes["BlockType"].Value = "FC";
                //Vložení klonu Nodu do XML souboru
                Parts.InsertAfter(Call,Parts.LastChild);

                //Nutno přepsat ID a vložit klon Nodu Wire ještě
                XmlNode Wire = Parts.NextSibling.FirstChild;
                Call = Wire.LastChild.Clone();
                Call.Attributes["UId"].Value = UId.ToString();
                Wire.InsertAfter(Call, Wire.LastChild);

                Main.Save(Receipt.PathObject + "Main.xml");
            }            
        }

        /// <summary>
        /// Vytvoření souboru obsahující funkci dle XML předpisu
        /// </summary>
        private void WriteFunction()
        {
            WriteMainBlock();
            

            string path = Receipt.PathObject + this.FileName;   //Cesta k souboru
            //Pokud existuje soubor se stejnou cestou smaž jej
            if (File.Exists(path))            
                File.Delete(path);                
            
            //Votvoření souboru
            using (StreamWriter fs = new StreamWriter(path, true, Encoding.UTF8))
            {
                string[] lines = File.ReadAllLines(Receipt.PathSource + this.TemplateName);
                //string a = Block.Attributes["Name"].Value + Block.Attributes["Postfix"].Value;//this.name
                string text;
                int number;
                foreach (string line in lines)
                {
                    //Block = receipt.GetBlock("Function", Number);
                    text = line;
                    //Overwrite inputs
                    XmlNodeList Inputs = this.source.SelectNodes("Inputs/Input");
                    foreach (XmlNode Input in Inputs)
                    {
                        //help je promena jak je ulozena v prepisu
                        string help = Input.InnerText;
                        //help2 jmeno promenne, uložená jako atribut, kterou se nahrani promena v prepisu
                        string help2 = Input.Attributes["TagName"].Value;
                        if (line.Contains(help))
                        {
                            //Ziskani cisla pozice kde se nachazi promena, ktera bude prepsana
                            number = text.IndexOf(help);
                            //Prepsani promenne dle prepisu
                            text = text.Remove(number, help.Length).Insert(number, help2);
                        }
                    }

                    //Overwrite Outputs
                    XmlNodeList Outputs = this.source.SelectNodes("Outputs/Output");
                    foreach (XmlNode Output in Outputs)
                    {
                        //help je promena jak je ulozena v prepisu
                        string help = Output.InnerText;
                        //help2 jmeno promenne, uložená jako atribut, kterou se nahrani promena v prepisu
                        string help2 = Output.Attributes["TagName"].Value;
                        if (line.Contains(help))
                        {
                            //Ziskani cisla pozice kde se nachazi promena, ktera bude prepsana
                            number = text.IndexOf(help);
                            //Prepsani promenne dle prepisu
                            text = (text.Remove(number, help.Length).Insert(number, help2));
                        }
                    }
                   
                    //Overwrite Name Function
                    if (line.Contains("Valec"))
                    {
                        //Ziskani cisla pozice kde se nachazi promena, ktera bude prepsana
                        number = text.IndexOf("Valec");
                        //fs.WriteLine(line.Remove(number, 5).Insert(number, a));
                        //Prepsani promenne dle prepisu
                        text = text.Remove(number, 5).Insert(number, this.name);
                    }

                    //Overwrite DataBlock and SystemBlock (Dependencies)
                    XmlNodeList Dependencies = this.source.SelectNodes("Dependencies/Dependency");
                    foreach (XmlNode Dependency in Dependencies)
                    {
                        //help je promena jak je ulozena v prepisu
                        string help = Dependency.InnerText;
                        //help2 jmeno promenne, kterou se nahrani promena v prepisu
                        string help2 = Dependency.Attributes["Name"].Value;
                        if (line.Contains(help))
                        {
                            //Ziskani cisla pozice kde se nachazi promena, ktera bude prepsana
                            number = text.IndexOf(help);
                            //Prepsani promenne dle prepisu
                            text = (text.Remove(number, help.Length).Insert(number, help2));
                        }
                    }

                    fs.WriteLine(text);
                }
            }
        }

        /// <summary>
        /// Vytvoření souboru obsahující systémový blok dle XML předpisu (časovač nebo čítač)
        /// </summary>
        private void WriteSystemBlock()
        {
            string path = Receipt.PathObject + this.FileName;   //Cesta k souboru
            //Pokud existuje soubor se stejnou cestou smaž jej
            if (File.Exists(path))
                File.Delete(path);

            //Votvoření souboru
            using (StreamWriter fs = new StreamWriter(path, true, Encoding.UTF8))
            {
                string[] lines = File.ReadAllLines(Receipt.PathSource + this.TemplateName);    //přečte všechny řádky souboru a uloží je do pole stringů               
                foreach (string line in lines)
                {
                    if (line.Contains(this.typename))              
                    {
                        int number = line.IndexOf(this.typename);     
                                                              

                        fs.WriteLine(line.Remove(number, this.typename.Length).Insert(number, this.name));
                    }
                    else
                        fs.WriteLine(line);

                }
            }
        }

        /// <summary>
        /// Konstruktor
        /// </summary>
        /// <param name="Name">Jméno bloku</param>  
        /// <param name="TypeName">Typové jméno bloku</param>  
        /// <param name="BlockType">Typ bloku</param> 
        /// <param name="Node">Zdrojový XmlNode bloku</param> 
        public Block(string Name, string TypeName, BlockType BlockType, XmlNode Node)
        {
            this.name = Name;
            this.type = BlockType;
            this.typename = TypeName;
            this.source = Node;
        }

        /// <summary>
        /// Vytvoří koncovky k souborům pro generování 
        /// </summary>
        /// <param name="type">Typ bloku</param> 
        /// <returns>Vrácena koncovka souboru, dle typu bloku</returns>
        public static string GetExtension(BlockType type)
        {
            switch(type)
            {
                case BlockType.COUNTER: return ".db"; //break;
                case BlockType.TIMER: return ".db"; //break;
                case BlockType.DATA_BLOCK: return ".db"; //break;
                case BlockType.FUNCTION: return ".scl"; //break;
            }
            return null;
        }

        /// <summary>
        /// Vytvoří soubor pro generování dle TypuBloku, zadaného v konstruktoru
        /// </summary>
        public void Process()
        {
            switch(type)
            {
                case BlockType.FUNCTION: WriteFunction();break;
                case BlockType.TIMER: WriteSystemBlock();break;
                case BlockType.COUNTER: WriteSystemBlock(); break;
                case BlockType.DATA_BLOCK: WriteDataBlock(); break;
            }
        }
    }
}
