//ライセンス情報はAgeOnフォルダのLISENCEフォルダを参照してください

/*
 * ★ウィンドウキャプチャのメソッドの参考にさせていただいたサイト
 * http://dobon.net/vb/dotnet/graphics/invokepaint.html
 * Copyright(C) DOBON!. All rights reserved.
 */

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Threading;
using System.Linq;
using System.Text.RegularExpressions;

using MecInfoDll;
using System.Runtime.InteropServices;

using nispi.controlclass;

namespace nispi
{
    class HtmlPopUpWindowWidget
    {
        public List<HtmlPopUpWindow> popUpList = null;
        public static Mutex mutex = new Mutex(false, "threadtabwidget");

        public HtmlPopUpWindowWidget()
        {
            popUpList = new List<HtmlPopUpWindow>();

            HtmlPopUpWindow.mutex = mutex;
        }
        public void AddPopUp(Point point, ThreadViewCommon threadView, string datUrl, string number)
        {
            Const.form.mainForm.Name = "isPopUp";
            HtmlPopUpWindow popUp;

            mutex.WaitOne();

            popUp = new HtmlPopUpWindow(point, threadView, datUrl, number);

            popUpList.Add(popUp);
            mutex.ReleaseMutex();
        }
        public void AddPopUp(Point point, ThreadViewCommon threadView, string datUrl, string number, string type)
        {
            Const.form.mainForm.Name = "isPopUp";
            HtmlPopUpWindow popUp;

            mutex.WaitOne();

            popUp = new HtmlPopUpWindow(point, threadView, datUrl, number, type);

            popUpList.Add(popUp);
            mutex.ReleaseMutex();
        }
        public void RemoveAllPopUp()
        {
            try
            {
                while (true)
                {
                    popUpList[0].RemovePopUp();
                }
            }
            catch (System.Exception ex)
            {
                Const.debugForm.OutPutDebug("HtmlPopUp", ex);
            }
            Const.form.mainForm.Name = "Form";
            HtmlPopUpWindow.beforeHtmlPopUpWindow = null;
        }
    }

    class HtmlPopUpWindow
    {
        public static BrowserParts browserPartsInsider;

        public BrowserParts browserParts;
        public PictureBoxParts picBoxParts;

        public static HtmlPopUpWindow beforeHtmlPopUpWindow;

        public HtmlPopUpFormParts popUp;

        public static Mutex mutex;
        public static MainForm form = null;
        public string datUrl;
        public string number;
        public string type;

        public HtmlPopUpWindow(Point point, ThreadViewCommon threadView, string datUrl, string number)
        {
            if (browserPartsInsider == null)
            {
                browserPartsInsider = new BrowserParts();
                browserPartsInsider.ownerForm = Const.form.mainForm;
            }

            //ポップアップウィンドウにスレッドクラスを渡す
            browserPartsInsider.threadViewProperty = threadView;
            browserPartsInsider.nonTextMenuOn = false;

            this.datUrl = datUrl;
            this.number = number;
            this.type = "one";
            SetUpOne(point);
            //HTMLデータを読み込む
            ShowData();
            SetUpTwo();
        }

        public HtmlPopUpWindow(Point point, ThreadViewCommon threadView, string datUrl, string number, string type)
        {
            if (browserPartsInsider == null)
            {
                browserPartsInsider = new BrowserParts();
                browserPartsInsider.ownerForm = Const.form.mainForm;
            }

            //ポップアップウィンドウにスレッドクラスを渡す
            browserPartsInsider.threadViewProperty = threadView;
            browserPartsInsider.nonTextMenuOn = false;

            this.datUrl = datUrl;
            this.number = number;

            if (type.Equals("fronttree") == true)
                this.type = "fronttree";
            else if (type.Equals("backtree") == true)
                this.type = "backtree";
            else if (type.Equals("alltree") == true)
                this.type = "alltree";
            else if (type.Equals("name") == true)
                this.type = "name";
            else if (type.Equals("id") == true)
                this.type = "id";
            else if (type.Equals("idFromID") == true)
                this.type = "idFromID";
            else if (type.Equals("POPNUM") == true)
                this.type = "POPNUM";
            else if (type.Equals("WORD") == true)
                this.type = "WORD";
            else if (type.Equals("ABON") == true)
                this.type = "ABON";
            else if (type.Equals("BE") == true)
                this.type = "BE";
            else
                ;// Const.debugForm.OutPutDebug("htmlPopUp", "HtmlPopUpWindow.cs");

            SetUpOne(point);
            //HTMLデータを読み込む
            ShowData();
            SetUpTwo();
        }
        private void SetUpOne(Point point)
        {
            picBoxParts = new PictureBoxParts();

            //ポップアップウィンドウの一つ目
            if (beforeHtmlPopUpWindow == null)
            {
                browserParts = browserPartsInsider;
                beforeHtmlPopUpWindow = this;
            }
            //ポップアップウィンドウの二つ目以降
            else
            {
                beforeHtmlPopUpWindow.picBoxParts = new PictureBoxParts();
                //メモリ節約のために前のウィンドウのキャプチャをブラウザコントロールの代わりに使う
                beforeHtmlPopUpWindow.picBoxParts.Image = CaptureControl(beforeHtmlPopUpWindow.popUp);
                beforeHtmlPopUpWindow.picBoxParts.SetDockFill();
                beforeHtmlPopUpWindow.picBoxParts.MouseDown += new MouseEventHandler(beforeHtmlPopUpWindow.picBox_Browser_MouseDown);

                //画像コントロールを加える
                beforeHtmlPopUpWindow.popUp.AddControl(beforeHtmlPopUpWindow.picBoxParts);

                //ブラウザコントロールを前のフォームから削除する
                beforeHtmlPopUpWindow.popUp.ControlsRemove(beforeHtmlPopUpWindow.browserParts);

                //BrowserPartを得る
                browserParts = beforeHtmlPopUpWindow.browserParts;

                //元のリンクを消す
                beforeHtmlPopUpWindow.browserParts = null;
                beforeHtmlPopUpWindow = this;
            }
            //HtmlPartInit();
            //名前を設定する。イベントの判別に使う
            browserParts.Document_Window_Name = "PopUp";

            popUp = HtmlPopUpFormPartsManager.Pop();
            //point.Y = point.Y - 4;
            //point.X = point.X - 4;
            popUp.Location = point;
        }


        private void SetUpTwo()
        {
            try
            {
                //ポップアップウィンドウの大きさをページの大きさに合わせる。
                popUp.Size =
                    new Size(/*MainForm.threadListTabControl.Size.Width - 6*/640,
                    browserParts.Document_Body_ScrollRectangle_Size.Height);

                //ウィンドウの外に出ないように調節する
                if ((popUp.Size.Height + popUp.Location.Y) > Const.DisplayY)
                {
                    popUp.Location =
                        new Point(popUp.Location.X,
                        popUp.Location.Y - ((popUp.Size.Height + popUp.Location.Y) - Const.DisplayY));

                    if (popUp.Size.Height > Const.DisplayY)
                    {
                        popUp.Location = new Point(popUp.Location.X, 0);
                        popUp.Size = new Size(popUp.Size.Width, Const.DisplayY);
                    }
                }
                if ((popUp.Size.Width + popUp.Location.X) > Const.DisplayX)
                {
                    popUp.Location =
                        new Point(popUp.Location.X - ((popUp.Size.Width + popUp.Location.X) - Const.DisplayX),
                        popUp.Location.Y);
                }

                browserParts.SetDockFill();

                popUp.AddControl(browserParts);

                popUp.Show();
            }
            catch (System.Exception ex)
            {
                Const.debugForm.OutPutDebug("HtmlPopUp", ex);
            }
        }

        private const int SRCCOPY = 13369376;
        private const int CAPTUREBLT = 1073741824;

        [DllImport("gdi32.dll")]
        private static extern int BitBlt(IntPtr hDestDC,
            int x,
            int y,
            int nWidth,
            int nHeight,
            IntPtr hSrcDC,
            int xSrc,
            int ySrc,
            int dwRop);

        public Bitmap CaptureControl(HtmlPopUpFormParts parts)
        {
            System.Windows.Forms.Control ctrl = (System.Windows.Forms.Control)parts.control;
            Graphics g = ctrl.CreateGraphics();
            Bitmap img = new Bitmap(ctrl.ClientRectangle.Width,
                ctrl.ClientRectangle.Height, g);
            Graphics memg = Graphics.FromImage(img);
            IntPtr dc1 = g.GetHdc();
            IntPtr dc2 = memg.GetHdc();
            BitBlt(dc2, 0, 0, img.Width, img.Height, dc1, 0, 0, SRCCOPY);
            g.ReleaseHdc(dc1);
            memg.ReleaseHdc(dc2);
            memg.Dispose();
            g.Dispose();
            return img;
        }

        private void picBox_Browser_MouseDown(object sender, MouseEventArgs e)
        {
            try
            {
                //メモリ節約のために前のウィンドウのキャプチャをブラウザコントロールの代わりに使う
                beforeHtmlPopUpWindow.picBoxParts = new PictureBoxParts();
                beforeHtmlPopUpWindow.picBoxParts.Image = CaptureControl(beforeHtmlPopUpWindow.popUp);
                beforeHtmlPopUpWindow.picBoxParts.SetDockFill();
                beforeHtmlPopUpWindow.picBoxParts.MouseDown += new MouseEventHandler(beforeHtmlPopUpWindow.picBox_Browser_MouseDown);

                //画像コントロールを加える
                beforeHtmlPopUpWindow.popUp.AddControl(beforeHtmlPopUpWindow.picBoxParts);

                //ブラウザコントロールを前のフォームから削除する
                beforeHtmlPopUpWindow.popUp.ControlsRemove(beforeHtmlPopUpWindow.browserParts);

                //BrowserPartを得る
                browserParts = beforeHtmlPopUpWindow.browserParts;
                //元のリンクを消す
                beforeHtmlPopUpWindow.browserParts = null;

                //現在のフォームを書き換える
                this.popUp.AddControl(this.browserParts);
                this.popUp.ControlsRemove(this.picBoxParts);
                this.picBoxParts.MouseDown -= new MouseEventHandler(beforeHtmlPopUpWindow.picBox_Browser_MouseDown);
                this.picBoxParts.ResetControl();
                this.picBoxParts = null;

                beforeHtmlPopUpWindow = this;

                ShowData();
            }
            catch (System.Exception ex)
            {
                Const.debugForm.OutPutDebug("HtmlPopUp", ex);
            }
        }

        //現在のクラスを削除する
        public void RemovePopUp()
        {
            MainFormConst.htmlPopUpWindowWidget.popUpList.Remove(this);
            try
            {
                this.picBoxParts.MouseDown -=
                    new MouseEventHandler(this.picBox_Browser_MouseDown);
            }
            catch (System.Exception ex)
            {
                Const.debugForm.OutPutDebug("HtmlPopUp", ex);
            }
            try
            {
                this.popUp.ControlsRemove(browserParts);
            }
            catch (System.Exception ex)
            {
                Const.debugForm.OutPutDebug("HtmlPopUp", ex);
            }
            try
            {
                this.popUp.ControlsRemove(this.picBoxParts);
                this.picBoxParts.ResetControl();
                this.picBoxParts = null;
            }
            catch (System.Exception ex)
            {
                Const.debugForm.OutPutDebug("HtmlPopUp", ex);
            }
            this.popUp.Hide();// control.Close();
            HtmlPopUpFormPartsManager.Push(this.popUp);
            this.popUp = null;
        }

        //表示
        public void ShowData()
        {
            try
            {
                DatInfo dat = new DatInfo(this.datUrl);
                dat.LoadFromFile();
                write(dat);
            }
            catch (System.Exception ex)
            {
                Const.debugForm.OutPutDebug("HtmlPopUp", ex);
            }
        }

        delegate void write_Delegate(DatInfo dat);

        public void write(DatInfo dat)
        {
            /* ロック */
            mutex.WaitOne();

            try
            {
                WriteToBrowser(dat, browserParts);
            }
            catch (System.Exception ex)
            {
                Const.debugForm.OutPutDebug("HtmlPopUp", ex);
            }

            /* ロック開放 */
            mutex.ReleaseMutex();
        }

        public void WriteToBrowser(DatInfo dat, BrowserParts browserParts)
        {
            int countMatch = 0;
            //this.resNum = dat.comments.Count.ToString();
            System.Text.StringBuilder sb = new System.Text.StringBuilder();

            CommentUtil commentUtil = new CommentUtil();

            sb.Append("<html><head><style type=\"text/css\">");
            /*string cssHeader = string.Format(
                "body {{ font-size: {0}pt;color:#{1};background-color:#{2};font-family:'{3}';}}",
                Const.opt.outWardBrowser.BrowserFontSize,
                Const.opt.outWardBrowser.BrowserForeColor,
                Const.opt.outWardBrowser.BrowserBackColor,
                Const.opt.outWardBrowser.BrowserFontName);*/
            string cssHeader = "";
            if (Const.opt.outWardBrowser.BrowserFontType.Equals("installed") == true)
            {
                cssHeader = string.Format(
                    "body {{ font-size: {0}pt;color:#{1};background-color:#{2};font-family:'{3}';}}",
                    Const.opt.outWardBrowser.BrowserFontSize,
                    Const.opt.outWardBrowser.BrowserForeColor,
                    Const.opt.outWardBrowser.BrowserBackColor,
                    Const.opt.outWardBrowser.BrowserFontName);
            }
            else
            {
                cssHeader = string.Format(
                    "body {{ font-size: {0}pt;color:#{1};background-color:#{2};font-family:'{3}';src: url(\"file:///{4}\");}}",
                    Const.opt.outWardBrowser.BrowserOriginalFontSize,
                    Const.opt.outWardBrowser.BrowserForeColor,
                    Const.opt.outWardBrowser.BrowserBackColor,
                    Const.opt.outWardBrowser.BrowserOriginalFontName,
                    Const.opt.outWardBrowser.BrowserOriginalFontPath);
            }
            sb.Append(cssHeader);

            sb.Append(Const.Default_Style_Sheet);
            sb.Append("</style></head>");

            string htmlHeader = string.Format("<body link='#{0}' vlink='#{1}'>",
                Const.opt.outWardBrowser.BrowserLinkColor,
                Const.opt.outWardBrowser.BrowserLinkedColor);

            sb.Append(htmlHeader);

            if (this.type.Equals("one") == true)
            {
                string typeTemp = "";
                string begin = "";
                string end = "";
                if (AnchorMethod.GetAnchor(number, ref typeTemp, ref begin, ref end) == true)
                {

                    if (typeTemp.Equals("ln") == true)
                    {
                        //beginにはレスの数が仮に代入されている
                        int num = dat.comments.Count - Int32.Parse(begin);
                        Comment[] comment = dat.comments.Skip(num).ToArray();
                        foreach (Comment temp in comment)
                            SbAppend(commentUtil, sb, temp, dat.dat_url);
                    }
                    else if (typeTemp.Equals("l") == true)
                    {
                        SbAppend(commentUtil, sb, dat.comments[0], dat.dat_url);
                        //beginにはレスの数が仮に代入されている
                        int num = dat.comments.Count - Int32.Parse(begin);
                        Comment[] comment = dat.comments.Skip(num).ToArray();
                        foreach (Comment temp in comment)
                            SbAppend(commentUtil, sb, temp, dat.dat_url);
                    }
                    /*else if (type.Equals("n") == true)
                    {
                        ;
                    }*/
                    else if (typeTemp.Equals("one") == true)
                    {
                        if (dat.comments.Count >= Int32.Parse(number))
                        {
                            try
                            {
                                //sb.Append(commentUtil.to_html(dat.comments[Int32.Parse(number) - 1], dat.dat_url));
                                SbAppend(commentUtil, sb, dat.comments[Int32.Parse(number) - 1], dat.dat_url);
                                countMatch += 1;
                            }
                            catch (System.Exception ex)
                            {
                                Const.debugForm.OutPutDebug("HtmlPopUp", ex);
                            }
                        }
                    }
                    else if (typeTemp.Equals("fromTop") == true)
                    {
                        Comment[] comment = dat.comments.Take(Int32.Parse(end)).ToArray();
                        foreach (Comment temp in comment)
                            SbAppend(commentUtil, sb, temp, dat.dat_url);
                    }
                    else if (typeTemp.Equals("toBottom") == true)
                    {
                        Comment[] comment = dat.comments.Skip(Int32.Parse(begin) - 1).ToArray();
                        foreach (Comment temp in comment)
                            SbAppend(commentUtil, sb, temp, dat.dat_url);
                    }
                    else if (typeTemp.Equals("between") == true)
                    {
                        int length = Int32.Parse(end) - Int32.Parse(begin) + 1;
                        Comment[] comment = dat.comments.Skip(Int32.Parse(begin) - 1).Take(length).ToArray();
                        foreach (Comment temp in comment)
                            SbAppend(commentUtil, sb, temp, dat.dat_url);
                    }
                    else
                    {
                        ;
                    }
                }
            }
            else if (this.type.Equals("fronttree") == true)
            {
                int pointNum = Int32.Parse(number) - 1;
                SbAppend(commentUtil, sb, dat.comments[pointNum], dat.dat_url);

                Regex rgx = new Regex(@"&gt;&gt;(\d*)");

                string temp = "";

                while(pointNum >= 0)
                {
                    temp = "";
                    temp = rgx.Match(dat.comments[pointNum].body).Value;
                    if (temp.Length > 8)
                    {
                        pointNum = Int32.Parse(temp.Substring(8)) - 1;
                        SbAppend(commentUtil, sb, dat.comments[pointNum], dat.dat_url);
                        countMatch += 1;
                        continue;
                    }
                    else
                        break;
                }                
            }

            else if (this.type.Equals("backtree") == true)
            {
                int pointNum = Int32.Parse(number);
                string targetText = "&gt;&gt;" + pointNum.ToString() +"<";
                int endNum = dat.comments.Count - 1;


                for (; pointNum <= endNum; ++pointNum)
                {
                    if (dat.comments[pointNum].body.Contains(targetText) == true)
                    {
                        countMatch += 1;
                        SbAppend(commentUtil, sb, dat.comments[pointNum], dat.dat_url);
                        //sb.Append(commentUtil.to_html(dat.comments[pointNum], dat.dat_url));
                    }
                }
            }
            else if (this.type.Equals("all") == true)
            {
                foreach (Comment comment in dat.comments)
                {
                    if (true == comment.num.Equals(number))
                        SbAppend(commentUtil, sb, comment, dat.dat_url);
                        //sb.Append(commentUtil.to_html(comment, dat.dat_url));
                }

            }
            else if (this.type.Equals("name") == true)
            {
                int pointNum = 0;
                string targetText = dat.comments[Int32.Parse(number) - 1].name;
                int endNum = dat.comments.Count - 1;

                for (; pointNum <= endNum; ++pointNum)
                {
                    if (dat.comments[pointNum].name.Equals(targetText) == true)
                    {
                        countMatch += 1;
                        SbAppend(commentUtil, sb, dat.comments[pointNum], dat.dat_url);
                        //sb.Append(commentUtil.to_html(dat.comments[pointNum], dat.dat_url));
                    }
                }
            }
            //特定の番号のＩＤから検索する
            else if (this.type.Equals("id") == true)
            {
                int pointNum = 0;
                string targetText = dat.comments[Int32.Parse(number) - 1].id;
                int endNum = dat.comments.Count - 1;

                for (; pointNum <= endNum; ++pointNum)
                {
                    if (dat.comments[pointNum].id.Equals(targetText) == true)
                    {
                        countMatch += 1;
                        SbAppend(commentUtil, sb, dat.comments[pointNum], dat.dat_url);
                        //temp.Append(commentUtil.to_html(dat.comments[pointNum], dat.dat_url));
                    }
                }
            }
            //BEから検索する
            else if (this.type.Equals("BE") == true)
            {
                int pointNum = 0;
                string targetText = number;
                int endNum = dat.comments.Count - 1;
                //StringBuilder temp = new StringBuilder();

                for (; pointNum <= endNum; ++pointNum)
                {
                    if (dat.comments[pointNum].beID.Equals(targetText) == true)
                    {
                        countMatch += 1;

                        SbAppend(commentUtil, sb, dat.comments[pointNum], dat.dat_url);
                        //temp.Append(commentUtil.to_html(dat.comments[pointNum], dat.dat_url));
                    }
                }
            }
            //ＩＤで全検索する
            else if (this.type.Equals("idFromID") == true)
            {
                int pointNum = 0;
                string targetText = number;
                int endNum = dat.comments.Count - 1;
                //StringBuilder temp = new StringBuilder();

                for (; pointNum <= endNum; ++pointNum)
                {
                    if (dat.comments[pointNum].id.Equals(targetText) == true)
                    {
                        countMatch += 1;

                        SbAppend(commentUtil, sb, dat.comments[pointNum], dat.dat_url);
                        //temp.Append(commentUtil.to_html(dat.comments[pointNum], dat.dat_url));
                    }
                }
            }
            //指定番号へのレスポンスを検索する
            else if (this.type.Equals("POPNUM") == true)
            {
                int pointNum = 0;
                string targetText = "&gt;&gt;" + number +"<";
                int endNum = dat.comments.Count - 1;
                //StringBuilder temp = new StringBuilder();

                for (; pointNum <= endNum; ++pointNum)
                {
                    if (dat.comments[pointNum].body.Contains(targetText) == true)
                    {
                        countMatch += 1;

                        SbAppend(commentUtil, sb, dat.comments[pointNum], dat.dat_url);
                        //sb.Append(commentUtil.to_html(dat.comments[pointNum], dat.dat_url));
                    }
                }
            }

            //ほにゃ
            // X行レスをカットする
            else if (this.type.Equals("CUT") == true)
            {
                int pointNum = 0;
                int endNum = dat.comments.Count - 1;

                for (; pointNum <= endNum; ++pointNum)
                {
                    //配列に分ける
                    char[] array = dat.comments[pointNum].body.ToCharArray();
                    //一文字ずつ調べて改行を探す。改行だけの配列が帰る。
                    array = array.Where(a => a.Equals('\n')).ToArray();
                    if (array.Length > 1)
                    {
                        countMatch += 1;

                        SbAppend(commentUtil, sb, dat.comments[pointNum], dat.dat_url);
                    }
                }
            }

            else if (this.type.Equals("WORD") == true)
            {
                int pointNum = 0;
                string targetText = number;
                int endNum = dat.comments.Count - 1;
                //StringBuilder temp = new StringBuilder();

                for (; pointNum <= endNum; ++pointNum)
                {
                    if (dat.comments[pointNum].body.Contains(targetText) == true)
                    {
                        countMatch += 1;

                        SbAppend(commentUtil, sb, dat.comments[pointNum], dat.dat_url);
                        
                        //sb.Append(commentUtil.to_html(dat.comments[pointNum], dat.dat_url));
                    }
                }
            }
            else if (this.type.Equals("ABON") == true)
            {
                if (dat.comments.Count >= Int32.Parse(number))
                {
                    try
                    {
                        sb.Append(commentUtil.to_html(dat.comments[Int32.Parse(number) - 1], dat.dat_url));
                        countMatch += 1;
                    }
                    catch (System.Exception ex)
                    {
                        Const.debugForm.OutPutDebug("HtmlPopUp", ex);
                    }
                }
            }

            if (countMatch == 0)
            {
                sb.Append("<body>該当無し</body>");
            }
            sb.Append("</html>");

            browserParts.BrowserClear();


            browserParts.Write(sb.ToString());
            browserParts.AllowNavigation = false;
            browserParts.Refresh();
            browserParts.Update();
        }

        public void SbAppend(CommentUtil commentUtil, StringBuilder sb, Comment comment, string datUrl)
        {
            //コメントを書き出す
            if (comment.abon == false)
                sb.Append(commentUtil.to_html(comment, datUrl));
            else
            {
                //アボン用の出力
                sb.Append(commentUtil.ToAbonHtml(comment, datUrl));
            }
        }

        public string CapText1(Match m)
        {
            //return m.Value.ToString();
            return m.Groups[1].Value;//string.Format("<a href='javascript:void(0);'>{1}</a>", m.Groups[1].Value, m.Value.ToString());
        }
    }
}
