using System.Text;
using System;
using System.Collections;
using System.Text.RegularExpressions;
namespace Kuineator.Components
{
    class PwrLexer
    {
        private Fireball.Windows.Forms.CodeEditorControl control;
        private Fireball.Syntax.SyntaxDocument doc;
        private string[] lines;
        private bool flag = false;

        public PwrLexer(Fireball.Syntax.SyntaxDocument document, Fireball.Windows.Forms.CodeEditorControl editor)
        {
            control = editor;
            doc = document;
            editor.AutoListClear();
            editor.ShowTabGuides = true;
            editor.ShowWhitespace = true;
            lines = document.Lines;
            
        }

        public void TextChanged()
        {
            if(doc.Lines==lines) return;
            int row = Matches(doc.Lines, lines);
            int pos = MatchesWord(row);
            if (row < doc.Lines.Length)
            {
                if (pos < doc.Lines[row].Length)
                {
                    if (2 < Encoding.UTF8.GetByteCount(doc.Lines[row].Substring(pos, 1)))
                    {
                        if (flag) flag = false;
                        else
                        {
                            flag = true;
                            doc.DeleteRange(new Fireball.Syntax.TextRange(pos,row,pos+1,row));
                        }
                    }

                }

            }
            ParserText(row, pos);
            lines = doc.Lines;
            if (control.AutoListVisible)
                control.AutoListPosition = new Fireball.Syntax.TextPoint(pos, row);
        }

        private void ParserText(int row, int pos)
        {
            try
            {
                int action = ActionJudge(row, pos);
                char ch;
                if (action == LexerPrim.ANOMALY)
                {
                    if (control.AutoListVisible)
                        control.AutoListVisible = false;
                    return;
                }
                if (action == LexerPrim.INSERT)
                {
                    if (doc.Lines[row] == "") ch = '\r';
                    else ch = doc.Lines[row][pos];
                    Console.Write(ch+"\n");
                    if (!InJudge(row, pos))
                    {
                        if(ch == '\r'){
                            Console.Write(row + "\n");
                            parseNewLine(row);
                        }
                        else if (!control.AutoListVisible)
                            control.AutoListVisible = true;
                    }
                    else
                    {
                        if (control.AutoListVisible)
                            control.AutoListVisible = false;
                    }
                }
                else
                {
                    if (lines[row] == "") ch = '\r';
                    else ch = lines[row][pos];
                    Console.Write(ch + "\n");
                    if (!InJudge(row, pos))
                    {
                        if (!control.AutoListVisible)
                            control.AutoListVisible = true;
                    }
                    else
                    {
                        if (control.AutoListVisible)
                            control.AutoListVisible = false;
                    }
                }
            }
            catch
            {
                control.AutoListVisible = false;
                return;
            }
        }

        private void ParserAllText()
        {

        }

        private void SyntaxHighLight(int row, int start, int end)
        {
        }

        private void SyntaxHighLightALL()
        {

        }

        private int Matches(string[] a, string[] b)
        {
            int length;
            if (a.Length < b.Length) length = a.Length;
            else length = b.Length;
            for (int i = 0; i < length; i++)
            {
                if (a[i].Replace("\r","") != b[i].Replace("\r","")) return i;
            }
            return length;
        }

        private int MatchesWord(int row)
        {
            if (doc.Lines.Length == row)
            {
                return 0;
            }
            else if (lines.Length == row)
            {
                return 0;
            }
            else
            {
                int length;
                if (doc.Lines[row].Length < lines[row].Length) length = doc.Lines[row].Length;
                else length = lines[row].Length;
                for (int i = 0; i < length; i++)
                {
                    if (doc.Lines[row][i] != lines[row][i]) 
                        return i;
                }
                return length;
            }
        }

        private int LinesTextConvert(int row, int pos)
        {
            if (doc.Lines.Length <= row)
            {
                return doc.Text.Length;
            }
            int length = 0;
            for (int i = 0; i < row; i++)
            {
                length += (doc.Lines[row].Length+1);
            }
            if (doc.Lines[row].Length <= pos) return length + doc.Lines[row].Length;
            return length + pos;
        }

        private int[] LinesTextConvert(int pos)
        {
            if(doc.Text.Length<=pos)return new int[2]{doc.Lines.Length-1,doc.Lines[doc.Lines.Length-1].Length};
            int i=0;
            for (; i < doc.Lines.Length && pos > doc.Lines[i].Length; i++)
            {
                pos -= (doc.Lines[i].Length+1);
            }
            if (i == doc.Lines.Length) return new int[2] { doc.Lines.Length - 1, doc.Lines[doc.Lines.Length - 1].Length };
            return new int[2] { i, pos };
        }

        private int ActionJudge(int row, int pos)
        {
            try
            {
                if (row == doc.Lines.Length) return LexerPrim.DELETE;
                if (row == lines.Length) return LexerPrim.INSERT;
                if (pos == doc.Lines[row].Length) return LexerPrim.DELETE;
                if (pos == lines[row].Length) return LexerPrim.INSERT;
                if (lines.Length < doc.Lines.Length) return LexerPrim.INSERT;
                if (lines.Length > doc.Lines.Length) return LexerPrim.DELETE;
                if (lines[row].Length < doc.Lines[row].Length) return LexerPrim.INSERT;
                if (doc.Lines[row].Length < lines[row].Length) return LexerPrim.DELETE;
                return LexerPrim.ANOMALY;
            }
            catch
            {
                return LexerPrim.ANOMALY;
            }
        }

        private bool InJudge(int row, int pos)
        {
            bool flag2 = false;
            if (doc.Lines[row] == "")
            {
                row--;
                pos = doc.Lines[row].Length - 1;
                flag2 = true;
            }
            else if (doc.Lines[row][pos] == '{' || doc.Lines[row][pos] == '}') return true;
            else if (doc.Lines[row][pos] == '"' || doc.Lines[row][pos] == '\'') return true;
            bool flag = true;
            int swap;
            for (int i = 0; i < row; i++)
            {
                swap = 0;
                for (int j = 0; j < doc.Lines[i].Length; )
                {
                    if (flag)
                    {
                        j = doc.Lines[i].IndexOf('{', j);
                        if (j == -1) break;
                        if (!InStringJudge(i, j, swap)) flag = false;
                        j++;
                    }
                    else
                    {
                        j = doc.Lines[i].IndexOf('}', j);
                        if (j == -1) break;
                        swap = j;
                        j++;
                        flag = true;
                    }
                }
            }
            swap = 0;
            for (int j = 0; j < pos; )
            {
                if (flag)
                {
                    j = doc.Lines[row].IndexOf('{', j);
                    if (j == -1 || j > pos) break;
                    if (!InStringJudge(row, j, swap)) flag = false;
                    j++;
                }
                else
                {
                    j = doc.Lines[row].IndexOf('}', j);
                    if (j == -1 || j > pos) break;
                    swap = j;
                    j++;
                    flag = true;
                }
            }
            if (flag2) 
                return !flag;
            if (flag) return InStringJudge(row, pos, swap);
            else return true;
        }

        private bool InStringJudge(int row, int pos, int start)
        {
            if (doc.Lines[row].Length <= pos || pos == -1) return false;
            if(doc.Lines[row][pos] == '"' || doc.Lines[row][pos] == '\'') return true;
            int i = -1;
            int flag = 0;
            for (int j = start; j <= pos && j > -1; i++)
            {
                if (flag == 0)
                {
                    if (j == start) j--;
                    int sw1 = doc.Lines[row].IndexOf('"', j+1);
                    int sw2 = doc.Lines[row].IndexOf('\'', j+1);
                    if (sw1 < sw2)
                    {
                        if (-1 < sw1)
                        {
                            j = sw1;
                            flag = 1;
                        }
                        else
                        {
                            j = sw2;
                            flag = 2;
                        }
                    }
                    else if (-1 < sw2)
                    {
                        j = sw2;
                        flag = 2;
                    }
                    else
                    {
                        j = sw1;
                        flag = 1;
                    }
                }
                else if (flag == 1)
                {
                    j = doc.Lines[row].IndexOf('"', j+1);
                    flag = 0;
                }
                else
                {
                    j = doc.Lines[row].IndexOf('\'', j+1);
                    flag = 0;
                }
            }
            if (i % 2 == 1) return true;
            return false;
        }

        private void parseNewLine(int row)
        {
            Regex a = new Regex(@"^[\t\s]*block[^a-zA-Z0-9]");
            if (a.IsMatch(doc.Lines[row-1]))
            {
                lines = doc.Lines;
                this.doc.InsertText("\nend", 0, row);
            }
        }

        private void InsertString(string str, int pos, int row)
        {
            lines = doc.Lines;
            doc.InsertText(str, pos, row);
        }

        private void DeleteString(int spos, int srow, int epos, int erow)
        {
            lines = doc.Lines;
            doc.DeleteRange(new Fireball.Syntax.TextRange(spos, srow, epos, erow));
        }
    }
}