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

namespace UniversalEditor.Classes
{
    class ShineTable
    {
        public String FilePath = String.Empty;
        public List<Table> Tables = new List<Table>();

        private Boolean Stop = false;
        private Boolean EOf = false;
        private List<String> FileHeaders = new List<String>();
        private List<String> HeaderComments = new List<String>();
        private StreamWriter Writer = null;
        private StreamReader Reader = null;
        private Int32 CurrentTable = 0;

        private void NextTable()
        {
            ShineTable ST = this;
            ST.CurrentTable = (ST.CurrentTable + 1);

            if (CurrentTable >= Tables.Count) { CurrentTable = (Tables.Count - 1); }
        }

        public void Open(String Path)
        {
            FilePath = Path;

            Reader = new StreamReader(FilePath);
            ReadFile();

            CurrentTable = 0;
        }

        private void ReadFile()
        {
            while (IsReading())
            {
                String CurrentLine = Reader.ReadLine();

                if (CurrentLine.Contains(";"))
                {
                    CurrentLine = CurrentLine.Split(new Char[] { ';' })[0];

                    if (CurrentLine.Length == 0) { continue; }
                }

                CurrentLine = Regex.Replace(CurrentLine, "\t+", "\t");
                CurrentLine = CurrentLine.TrimEnd('\t');

                if (CurrentLine == null) { continue; }

                String[] Array = CurrentLine.Split(new Char[] { '\t' });

                Int32 TempNumber = 0;

                for (Int32 Counter = 0; Counter < Array.Length; Counter++)
                {
                    if (Array[Counter].StartsWith("#")) { TempNumber = Counter; }
                }

                String TabTextLower = Array[TempNumber].ToLower();

                if (TabTextLower != null)
                {
                    switch (TabTextLower)
                    {
                        case "#end":
                            {
                                EOf = true;

                                continue;
                            }
                        case "#columntype":
                            {
                                ProcessColumnType(CurrentLine);

                                continue;
                            }
                        case "#columnname":
                            {
                                ProcessColumnName(CurrentLine);

                                continue;
                            }
                        case "#table":
                            {
                                ProcessTable(CurrentLine, Array, TempNumber);

                                continue;
                            }
                        case "#recordin":
                            {
                                ProcessRecordin(Array);

                                continue;
                            }
                        case "#record":
                            {
                                ProcessRecord(Array, TempNumber);

                                continue;
                            }
                    }
                }

                ProcessDefault(CurrentLine, Array, TempNumber);
            }

            Reader.Close();
        }

        public void Save(String Path)
        {
            if(File.Exists(String.Format("{0}.bak", FilePath))) { File.Delete(String.Format("{0}.bak", FilePath)); }

            File.Copy(FilePath, String.Format("{0}.bak", FilePath));
            File.Delete(FilePath);
            File.Create(Path).Close();

            Writer = new StreamWriter(Path);

            foreach(var FileHeader in FileHeaders) { Writer.WriteLine(FileHeader); }

            foreach (var CommentHeader in HeaderComments) { Writer.WriteLine(CommentHeader); }

            Writer.Flush();
            Writer.AutoFlush = true;

            foreach(Table CurrentTable in Tables)
            {
                Writer.WriteLine();
                Writer.WriteLine(CurrentTable.NameLine);
                Writer.WriteLine(CurrentTable.TypeLine);
                Writer.WriteLine(CurrentTable.ColumnNameLine);

                foreach(DataRow CurrentRow in CurrentTable.Content.Rows)
                {
                    Writer.Write("#Record");

                    Object[] Array = CurrentRow.ItemArray;

                    for(Int32 Counter = 0; Counter < Array.Length; Counter++)
                    {
                        Object ObjectItem = Array[Counter];

                        if(ObjectItem != DBNull.Value) { Writer.Write(String.Concat("\t", (String)ObjectItem)); }
                        else { Writer.Write("\t"); }
                    }
                    Writer.WriteLine();
                }

                foreach(String Comment in CurrentTable.Comments) { Writer.WriteLine(Comment); }

                Writer.Flush();
            }

            Writer.WriteLine("#end");
            Writer.Close();
        }

        private void ProcessColumnType(String Line)
        {
            Tables[CurrentTable].TypeLine = Line;

            while (Tables[CurrentTable].TypeLine.StartsWith("\t")) { Tables[CurrentTable].TypeLine = Tables[CurrentTable].TypeLine.Remove(0, 1); }
        }

        private void ProcessColumnName(String Line)
        {
            String[] Array = Line.Split("\t\n".ToCharArray());

            Int32 TempNumber = 0;

            for (Int32 Counter = 0; Counter < Array.Length; Counter++)
            {
                String TempString = Array[Counter];

                if (!TempString.StartsWith("#") && !Tables[CurrentTable].Content.Columns.Contains(TempString) && !TempString.StartsWith(";"))
                {
                    if (TempString != String.Empty) { Tables[CurrentTable].Content.Columns.Add(TempString); }
                    else
                    {
                        Tables[CurrentTable].Content.Columns.Add(String.Concat("Empty", TempNumber));

                        TempNumber++;
                    }
                }
            }

            Tables[CurrentTable].ColumnNameLine = Line;

            while (Tables[CurrentTable].ColumnNameLine.StartsWith("\t")) { Tables[CurrentTable].ColumnNameLine = Tables[CurrentTable].ColumnNameLine.Remove(0, 1); }
        }

        private void ProcessTable(String Line, String[] Array, Int32 Index)
        {
            Table TableProcess = new Table()
            {
                Name = Array[(Index + 1)],
                Content = new DataTable()
            };

            Tables.Add(TableProcess);

            NextTable();

            Tables[CurrentTable].NameLine = Line;

            while(Tables[CurrentTable].NameLine.StartsWith("\n")) { Tables[CurrentTable].NameLine = Tables[CurrentTable].NameLine.Remove(0, 1); }
        }

        private void ProcessRecordin(String[] Array)
        {
            Int32 TempNumber = 1;

            while (TempNumber < Array.Length && !(Array[TempNumber] != String.Empty)) { TempNumber++; }

            Table TableProcess = new Table();

            foreach (var CurrentTable in Tables)
            {
                if (CurrentTable.Name != Array[TempNumber]) { continue; }

                TableProcess = CurrentTable;
            }

            DataRow TableRow = TableProcess.Content.NewRow();

            Int32 TempCounter = 0;

            for (Int32 Counter = (TempNumber + 1); Counter < Array.Length; Counter++)
            {
                if (TempCounter < TableProcess.Content.Columns.Count)
                {
                    TableRow[(TempCounter + 1)] = Array[Counter];

                    TempCounter++;
                }
            }
        }

        private void ProcessRecord(String[] Array, Int32 Index)
        {
            DataRow TableRow = Tables[CurrentTable].Content.NewRow();

            Int32 TempNumber = 0;

            for (Int32 Counter = (Index + 1); Counter < Array.Length; Counter++)
            {
                if (TempNumber < Tables[CurrentTable].Content.Columns.Count)
                {
                    TableRow[TempNumber] = Array[Counter];

                    TempNumber++;
                }
            }

            Tables[CurrentTable].Content.Rows.Add(TableRow);
        }

        private void ProcessDefault(String Line, String[] Array, Int32 Index)
        {
            if (Tables.Count < 1)
            {
                if (Array[Index].StartsWith(";"))
                {
                    HeaderComments.Add(Line);

                    return;
                }

                FileHeaders.Add(Line);
            }
            else if (Array[Index].StartsWith(";") || Array[Index].Contains(";")) { Tables[CurrentTable].Comments.Add(Line); }
        }

        private Boolean IsReading()
        {
            if (EOf || Stop) { return false; }

            return !Reader.EndOfStream;
        }
    }
}
