using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Irony.Parsing;
using Irony.Interpreter;
using Irony.Interpreter.Ast;
using Gecko;
using System.Diagnostics;
using myBuiltInMethod;

namespace myScriptableBrowser
{
    public partial class Form1 : Form
    {
        private myBuiltInMethod.BrowserScriptInterfaces weblib = null;
        private myBuiltInMethod.FormScriptInterfaces formlib = null;
        myScriptEvaluator Interpreter;

        public Form1()
        {
            InitializeComponent();
            Xpcom.Initialize(@"c:\xulrunner\12\xulrunner");
            InitInterfaces();
            InitScript();

        }

        
        
        private void InitScript()
        {


            Interpreter = new myScriptEvaluator(new myScriptGrammar());

            //プリントイベント拾う
            Interpreter.App.ConsoleWrite += new EventHandler<ConsoleWriteEventArgs>(App_ConsoleWrite);


            //組み込み関数をDLLから読み込む
            var dllpath = System.IO.Path.GetDirectoryName(Application.ExecutablePath).Replace(@"\" , @"\\") + @"\\myBuiltInMethod.dll";
            var className = "myBuiltInMethod.ScriptBuiltInMethod";
            var loaddllstr = string.Format(@"loadDLL(""{0}"",""{1}"")" , dllpath , className);


            //DLL読み込みすると、返値として指定したクラスのインスタンスがobjectとして返却される。
            //今回は、ScriptBuiltInMethodのインスタンス
            var ret = Interpreter.App.Evaluate(loaddllstr) as myBuiltInMethod.ScriptBuiltInMethod;
            //アクセス用のクラスインスタンスを渡す。
            ret.Init(this.weblib , this.formlib);




        }

        //スクリプトでプリントを使った時の対応
        void App_ConsoleWrite(object sender , ConsoleWriteEventArgs e)
        {
            this.textBox_info.Text += e.Text;
        }


        private void InitInterfaces()
        {
            formlib = new FormScriptInterfaces();
            formlib.Add(this.textBox_info.Name , this.textBox_info);

            weblib = new BrowserScriptInterfaces(this.geckoWebBrowser1);

        }





        public void Suspend(ScriptThread thread)
        {
            var s = thread.CurrentNode.AsString;
            this.textBox_info.Text = s + " " + DateTime.Now.ToString();

            while (Interpreter.App.SuspendRequested)
            {
                Application.DoEvents();
                System.Threading.Thread.Sleep(100);
            }
        }



        private void toolStripButton_run_Click(object sender, EventArgs e)
        {
            Interpreter.App.OutputBuffer.Clear();
            Interpreter.App.SuspendRequested = false;

            var sw = new Stopwatch();
            sw.Start();

            try
            {
                //テキストを渡すEvaluateではなく、parsetreenodeを渡すを使う。
                var parsedScript = Interpreter.Parser.Parse(this.textBox1.Text);
                if(parsedScript.HasErrors())
                {
                    throw new ScriptException("Syntax errors found.");
                }

                Interpreter.App.Evaluate(parsedScript);
                //var printvisitor = new PrintVisitor();
                //astnode.AcceptVisitor(printvisitor);

                this.textBox_info.Text = Interpreter.App.GetOutput();

                //this.textBox2.Text += Environment.NewLine + printvisitor.s;
            }
            catch(ScriptException ex)
            {
                MessageBox.Show(ex.Location.ToUiString() + ex.Message);
            }

            sw.Stop();

        }

        private void toolStripButton_reset_Click(object sender, EventArgs e)
        {
            InitScript();
            //Interpreter.Evaluate(this.textBox1.Text);
        }

        private void toolStripButton_suspend_Click(object sender, EventArgs e)
        {
            if(Interpreter.App != null)
            {
                //実行中ならサスペンド／再開する
                if(Interpreter.App.Status == AppStatus.Evaluating)
                    Interpreter.App.SuspendRequested = !Interpreter.App.SuspendRequested;
            }
            else
            {
                Interpreter.App.SuspendRequested = false;
            }
        }

        private void toolStripButton_test_Click(object sender, EventArgs e)
        {
            MessageBox.Show("ボタンクリックされました");

        }

        private void toolStripButton_go_Click(object sender, EventArgs e)
        {
            this.weblib.Navigate(this.toolStripTextBox_URL.Text);
        }
    }//class


    //デバッグ用
    public class PrintVisitor : IAstVisitor
    {
        public string s = "";
        int indentation = 0;

        public void BeginVisit(IVisitableNode node)
        {
            var ast = node as AstNode;
            if (ast == null) return;

            for (int i = 0 ; i < indentation ; i++)
            {
                s += "    ";
            }
            s += ast.AsString;

            if (ast.DependentScopeInfo != null)
            {
                foreach (SlotInfo slotinfo in ast.DependentScopeInfo.GetSlots())
                {
                    s += "          " + slotinfo.Name + " ";
                }
            }
            else
            {
                s += " * ";
            }
            s +=  Environment.NewLine;

            indentation++;
        }

        public void EndVisit(IVisitableNode node)
        {
            indentation--;
        }


    }



}
