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;
using System.Threading;
using ScriptRunner;
namespace myScriptableBrowser
{
    public partial class MainForm : Form
    {
        private myBuiltInMethod.BrowserScriptInterfaces weblib = null;
        private myBuiltInMethod.FormScriptInterfaces formlib = null;
        myScriptEvaluator Interpreter;
        public Dictionary<string , Irony.Interpreter.BuiltInMethod> methodlist;

        //非シグナル状態でManualResetEventオブジェクトを作成
        public ManualResetEvent manualEvent1 = new System.Threading.ManualResetEvent(false);
        public ManualResetEvent manualEvent2 = new System.Threading.ManualResetEvent(false);

        public MainForm()
        {
            InitializeComponent();

            //this.textbox_script.Font = new System.Drawing.Font("メイリオ" , 12F , FontStyle.Regular);

            Xpcom.Initialize(@"c:\xulrunner\12\xulrunner");
            InitInterfaces();
            InitScript();
            InitScriptTextBox();
            formlib.Add(this.toolStripButton_test);
        }

        
        
        private void InitScript()
        {


            Interpreter = new myScriptEvaluator(new myScriptGrammar());





            //Running in Grammar Explorer　グラマー定義から引用
            Interpreter.Globals.Add("null", Interpreter.Runtime.NoneValue);
            Interpreter.Globals.Add("true", true);
            Interpreter.Globals.Add("false", false);
            
            //プリントイベント拾う
            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);

            //ライブラリ読み込み用
            methodlist = new Dictionary<string, Irony.Interpreter.BuiltInMethod>();
<<<<<<< .mine

            //var tr = new ExportMethodBase(typeof(myBuiltInMethod.BrowserScriptInterfaces2), weblib);
=======
            //var tr = new ExportMethodBase(typeof(myBuiltInMethod.BrowserScriptInterfaces), weblib);
>>>>>>> .r34


            Action extmethod = 
                () => {
                        weblib.BrowserWait(false);
                      };
            var tr = new ExportMethod2(typeof(myBuiltInMethod.BrowserScriptInterfaces), weblib,
                typeof(BrowserBusyCheckAttribute), extmethod
                );
                
            methodlist = tr.CheckAttrAndExport();
            //メソッド登録
            foreach(var item in methodlist)
            {
                Interpreter.App.Runtime.BuiltIns.AddMethod(item.Value, item.Key);
            }


            //ライブラリ読み込み用(form)
            methodlist.Clear();

            var tr2 = new ExportMethodBase(typeof(myBuiltInMethod.FormScriptInterfaces) , formlib );

            methodlist = tr2.CheckAttrAndExport();
            //メソッド登録
            foreach(var item in methodlist)
            {
                Interpreter.App.Runtime.BuiltIns.AddMethod(item.Value, item.Key);
            }
            //プリント用TEXTBOX結びつけ
            formlib.SetInfoTextBox(this.textBox_info);


        }

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




        delegate void SetTextDelegate(object sender , ConsoleWriteEventArgs e);

        void App_ConsoleWrite(object sender , ConsoleWriteEventArgs e)
        {
            if (InvokeRequired)
            {
                // 別スレッドから呼び出された場合
                this.BeginInvoke(new SetTextDelegate(App_ConsoleWrite) , new object[] { sender, e });
                return;
            }
            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);

        }





        




        private void geckoWebBrowser1_DocumentCompleted(object sender, EventArgs e)
        {
            //待ってみる。
            while(this.geckoWebBrowser1.IsAjaxBusy)
            {
                System.Threading.Thread.Sleep(50);
                Application.DoEvents();
                //↓これないと固まることが。。
                Application.RaiseIdle(new EventArgs());
                System.Diagnostics.Debug.Write("#");
            }
            this.toolStripTextBox_URL.Text = weblib.getURL();
            Interpreter.App.Evaluate(weblib.strEventScript_DocComp);
            

            //ドキュメント読み込み完了後に、擬似イベント発火
            timer_afterDocComp.Enabled = true;
        }
        
        //
        private void timer_afterDocComp_Tick(object sender, EventArgs e)
        {
            timer_afterDocComp.Enabled = false;
            Interpreter.App.Evaluate(weblib.strEventScript_AfterDocComp);
            weblib.b_DocCompleted = true;
            weblib.b_navigatingFired = false;
        }



        private void geckoWebBrowser1_Navigated(object sender, GeckoNavigatedEventArgs e)
        {

        }

        #region geckoWebBrowser1_Navigating　timerイベント
        private void geckoWebBrowser1_Navigating(object sender, GeckoNavigatingEventArgs e)
        {
            Interpreter.App.Evaluate(weblib.strEventScript_Navigating);
           // mouseOverelementsStack.Clear();
            weblib.b_navigatingFired = true;
            weblib.b_DocCompleted = false;

            ////ナビゲートが発生したら、擬似イベント発火
            //this.timer1.Interval = 50;
            //this.timer1.Enabled = true;

        }

 

        private Keys modkey;
        private void textbox_script_KeyDown(object sender , KeyEventArgs e)
        {
            modkey = e.KeyData;
        }

        private void textbox_script_KeyUp(object sender , KeyEventArgs e)
        {
            modkey = e.KeyData;
        }

        private void textbox_script_MouseDown(object sender , MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Middle && modkey == Keys.Control)
            {
                var f = new Font(textbox_script.Font.FontFamily , textbox_script.Font.SizeInPoints + (float)e.Delta , textbox_script.Font.Style);

                textbox_script.Font = f;
                textbox_script.OnTextChanged();
            }
        }

        private void 上書き保存SToolStripButton_Click(object sender, EventArgs e)
        {

        }

        private void fontDialog1_Apply(object sender, EventArgs e)
        {
           //his.textbox_script.Font = this.fontDialog1.Font;
        }

        private void fontToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var ret = fontDialog1.ShowDialog();
            if(ret == System.Windows.Forms.DialogResult.OK)
                textbox_script.Font = fontDialog1.Font;
        }


        private string script_path = "";
        private void 開くOToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var ret = openFileDialog1.ShowDialog();
            if(ret == System.Windows.Forms.DialogResult.OK)
            {
                textbox_script.Text = System.IO.File.ReadAllText(openFileDialog1.FileName, Encoding.UTF8);
                script_path = openFileDialog1.FileName;
            }

        }

        private void 名前を付けて保存AToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var ret = this.saveFileDialog1.ShowDialog();
            if(ret == System.Windows.Forms.DialogResult.OK)
            {
                System.IO.File.WriteAllText(saveFileDialog1.FileName, this.textbox_script.Text, Encoding.UTF8);
                script_path = saveFileDialog1.FileName;
            }


        }

        private void 上書き保存SToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if(script_path != "")
                System.IO.File.WriteAllText(script_path, this.textbox_script.Text, Encoding.UTF8);
        }





        //private void timer1_Tick(object sender, EventArgs e)
        //{
        //    //タイマー止める
        //    this.timer1.Enabled = false;
        //    //ブラウザ待ち
        //    weblib.BrowserWait();
        //    weblib.b_navigatingFired = false;
        //    weblib.b_DocCompleted = true;
        //}


        #endregion



    }//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--;
        }


    }



}
