//ライセンス情報はAgeOnフォルダのLISENCEフォルダを参照してください
using System.Collections.Generic;
using System.Text;
using System;
using System.Linq;
using System.IO;
using System.Drawing.Imaging;
using System.Drawing;
using mshtml;
using System.Threading;
//using System.Threading.Tasks;

using MecInfoDll;
using nispi.OptionControl;

namespace nispi
{
    class tempParamThread
    {
        public ThreadViewCommon view = null;
        public string str = null;

        public tempParamThread(ThreadViewCommon view, string str)
        {
            this.view = view;
            this.str = str;
        }
    }

    class ThreadViewCommon
    {
        public string datUrl;
        public string threadName;
        public string resNum = "0";

        /*コントロール含む*/
        public ThreadListControls threadViewControls;

        //public Mutex mutex;
        public AgeonMutex ageonMutex;
        public int threadLocalCount;

        //時間指定のためのデータ
        public int withInNum = 0;
        public string pinPointData = "";
        public string pinPointJPData = "";

        public Shiori shiori;

        public DatInfo dat;

        public int preSize = 0;

        //public List<Point> resPoints;

        public ThreadViewCommon()
        {
            ageonMutex = new AgeonMutex();
            ageonMutex.Init();
            preSize = 0;
        }

        public virtual void Control_Removed(object sender, EventArgs e)
        {
        }

        public virtual void dispoose()
        {
        }
        public virtual void dispooseAll()
        {
        }
        delegate void ShowToolTipDelegate(string text, BrowserParts BrowserParts);

        public void ShowThread(string dat_url)
        {

            /* ロック */
            if (this.ageonMutex.WaitOne() == false)
            {
                this.ageonMutex.ReleaseMutex();
                return;
            }

            try
            {
                this.datUrl = dat_url;

                //2ch.netを2ch.scにリダイレクトするかどうか
                if (Const.opt.otherOption.Redirect.Equals("redirect") == true)
                {
                    this.datUrl = Redirect2chSC(this.datUrl);
                }

                Const.form.mainForm.Invoke(new ShowToolTipDelegate(this.threadViewControls.toolTipParts.ShowToolTip),
                    this.datUrl + "を読み込み中...", this.threadViewControls.browserParts);

                if ((Const.opt.otherOption.ModeType2ch.Equals("IEMode") == true) && (Util.BoardType(this.datUrl) == Util.TYPE_2CH))
                {
                    string threadUrl = Util.DatUrlToThreadUrl(this.datUrl);

                    Const.form.mainForm.Invoke((Action)(() => this.threadViewControls.browserParts.control.AllowNavigation = true));
                    Const.form.mainForm.Invoke((Action)(() => this.threadViewControls.browserParts.control.Navigate(threadUrl)));
                    Const.form.mainForm.Invoke((Action)(() => this.threadViewControls.browserParts.type = "2ch"));
                    //Const.form.mainForm.Invoke((Action)(() => this.threadViewControls.browserParts.control.AllowNavigation = false));
                }
                else
                {

                    try
                    {
                        dat.comments.Clear();
                        dat = null;
                    }
                    catch {; }
                    dat = new DatInfo(this.datUrl);


                    dat.Load();

                    if (dat.thread_name == null)
                        ;
                    else if (dat.thread_name.Length == 0)
                        ;
                    else
                    {
                        //スレッドの名前をタブに設定
                        //if (this.threadViewControls.tabPageExParts != null)
                        //Const.form.mainForm.Invoke((Action)(() => this.threadViewControls.tabPageExParts.Text = dat.thread_name));
                        //this.threadViewControls.tabPageExParts.Text = dat.thread_name;
                        Const.form.mainForm.Invoke(new SetThreadNameDele(SetThreadName), dat.thread_name);
                        write(dat);

                        Const.form.mainForm.Invoke((Action)(() => this.threadViewControls.browserParts.type = "other"));
                    }

                }

                Const.form.mainForm.Invoke(new Action(this.threadViewControls.toolTipParts.HideToolTip));
            }

            catch {; }
            /* ロック開放 */
            this.ageonMutex.ReleaseMutex();
        }
        public delegate void SetThreadNameDele(string text);
        public void SetThreadName(string text)
        {
            try
            {
                this.threadViewControls.tabPageExParts.Text = "   " + text;
                if (this.threadViewControls.tabPageExParts.Text.Length == 0)
                    this.threadViewControls.tabPageExParts.Text = this.threadViewControls.tabPageExParts.ToolTipText;
            }
            catch (NullReferenceException e)
            {
                Thread.Sleep(1);
            }
            catch { ;}
        }
        public void ReShowThread()
        {
            /* ロック */
            if (this.ageonMutex.WaitOne() == false)
            {
                this.ageonMutex.ReleaseMutex();
                return;
            }

            try
            {
                if (dat.thread_name == null)
                    return;
                write(dat);
            }
            catch
            {
                //Const.debugForm.OutPutDebug("ThreadList", ex);
            }

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


        public virtual void write(DatInfo dat)
        {
        }
        public void Reload()
        {
            Thread t = new Thread(new ThreadStart(ReloadThread));
            t.IsBackground = true;
            t.Start();

            return;
        }
        public void reload(object sender, EventArgs e)
        {
            Thread t = new Thread(new ThreadStart(ReloadThread));
            t.IsBackground = true;
            t.Start();

            return;
        }

        public void ReloadThread()
        {
            /* ロック */
            if (this.ageonMutex.WaitOne() == false)
            {
                this.ageonMutex.ReleaseMutex();
                return;
            }

            try
            {
                //2ch.netを2ch.scにリダイレクトするかどうか
                if (Const.opt.otherOption.Redirect.Equals("redirect") == true)
                {
                    this.datUrl = Redirect2chSC(this.datUrl);
                }


                Const.form.mainForm.Invoke(new ShowToolTipDelegate(this.threadViewControls.toolTipParts.ShowToolTip),
                    this.datUrl + "を読み込み中...", this.threadViewControls.browserParts);

                if ((Const.opt.otherOption.ModeType2ch.Equals("IEMode") == true) && (Util.BoardType(this.datUrl) == Util.TYPE_2CH))
                {
                    string threadUrl = Util.DatUrlToThreadUrl(this.datUrl);

                    Const.form.mainForm.Invoke((Action)(() => this.threadViewControls.browserParts.control.AllowNavigation = true));
                    Const.form.mainForm.Invoke((Action)(() => this.threadViewControls.browserParts.control.Navigate(threadUrl)));
                    Const.form.mainForm.Invoke((Action)(() => this.threadViewControls.browserParts.type = "2ch"));
                    //Const.form.mainForm.Invoke((Action)(() => this.threadViewControls.browserParts.control.AllowNavigation = false));
                }
                else
                {

                    try
                    {
                        dat.comments.Clear();
                        dat = null;
                    }
                    catch {; }
                    dat = new DatInfo(datUrl);

                    dat.Load();

                    if (dat.thread_name == null)
                        ;
                    else if (dat.thread_name.Length == 0)
                        ;
                    else
                    {
                        //スレッドの名前をタブに設定
                        if (this.threadViewControls.tabPageExParts != null)
                            Const.form.mainForm.Invoke((Action)(() => this.threadViewControls.tabPageExParts.Text = "   " + dat.thread_name));
                        ReWrite(dat);
                        this.threadViewControls.browserParts.type = "other";
                    }
                }
            }
            catch {; }

            try
            {
                Const.form.mainForm.Invoke((Action)(() => this.threadViewControls.toolTipParts.HideToolTip()));
            }
            catch {; }
            /* ロック開放 */
            try
            {
                this.ageonMutex.ReleaseMutex();
            }
            catch {; }
        }

        delegate void ReWrite_Delegate(DatInfo dat);

        public void SimpleReWrite()
        {
            /* ロック */
            if (this.ageonMutex.WaitOne() == false)
            {
                this.ageonMutex.ReleaseMutex();
                return;
            }

            try
            {
                ReWrite(dat);
            }
            catch {; }
            /* ロック開放 */
            this.ageonMutex.ReleaseMutex();
        }

        public virtual void ReWrite(DatInfo dat)
        {
        }

        public void ReWriteToBrowser(DatInfo dat, Point point)
        {
            //datUrlの長さがゼロ（＝閉じられている）の場合には実行しない
            this.ageonMutex.WaitOne();
            if (this.datUrl.Length == 0)
            {
                this.ageonMutex.ReleaseMutex();
                return;
            }
            this.ageonMutex.ReleaseMutex();

            try
            {

                if (preSize < dat.comments.Count())
                {
                    preSize = dat.comments.Count();
                    SetIcon(this);
                }
                //アクセス履歴のため
                int type = Util.BoardType(this.datUrl);
                string title = dat.thread_name;// this.threadName;
                this.threadName = dat.thread_name;
                string address = this.datUrl;
                nispi.Controls.UsefulAddress.UsefulThread.Add(type, title, address);


                this.resNum = dat.comments.Count.ToString();

                //Abonを検索してフラグを立てる。
                dat.AbonSearch();

                //ヘッダの分部を作成
                System.Text.StringBuilder sb = new System.Text.StringBuilder();

                sb.Append("<html><head><style type=\"text/css\">");

                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>");
                sb.Append(string.Format(Const.ScrollJavaScript, point.X, point.Y));
                sb.Append("</head>");

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

                sb.Append(htmlHeader);

                sb.Append(string.Format("<h4>{0}</h4>\r\n", dat.thread_name));

                if ((this.withInNum == 0) && (this.pinPointData.Length == 0) &&
                    (this.threadViewControls.analysisMagic.oneLineCut == false) &&
                    (this.threadViewControls.analysisMagic.twoLineCut == false) &&
                    (this.threadViewControls.analysisMagic.threeLineCut == false) &&
                    (this.threadViewControls.analysisMagic.fourLineCut == false) &&
                    (this.threadViewControls.analysisMagic.kusaCut == false) &&
                    (this.threadViewControls.analysisMagic.noAnchorCut == false))
                {
                    CommentUtil commentUtil = new CommentUtil();

                    //コメントひとつづつを処理する
                    foreach (Comment comment in dat.comments)
                    {
                        //コメントを書き出す
                        if (comment.abon == false)
                            sb.Append(commentUtil.to_html(comment, dat.dat_url));
                        else
                        {
                            //アボン用の出力
                            sb.Append(commentUtil.ToAbonHtml(comment, dat.dat_url));
                        }
                    }
                }
                else
                    ResponseExtraction(sb, dat);

                sb.Append("</body>");
                sb.Append("</html>");

                Const.form.mainForm.Invoke((Action)(() => this.threadViewControls.browserParts.Size =
                    new Size(this.threadViewControls.tabPageExParts.Size.Width,
                        this.threadViewControls.tabPageExParts.Size.Height - 27)));

                Const.form.mainForm.Invoke((Action)(() => this.threadViewControls.browserParts.BrowserClear()));

                Const.form.mainForm.Invoke((Action)(() => this.threadViewControls.browserParts.Write(sb.ToString())));
                Const.form.mainForm.Invoke((Action)(() => this.threadViewControls.browserParts.AllowNavigation = false));

                //しおりを挿む
                shiori.GetXMLData(this.datUrl);
                Const.form.mainForm.Invoke((Action)(() => shiori.SetShiori(shiori.BeforeShioriStr)));
            }

            catch {; }
        }

        private void ResponseExtraction(StringBuilder sb, DatInfo dat)
        {
            try
            {
                PlusTime plusTime = null;
                string withInResponseDate = "";

                CommentUtil commentUtil = new CommentUtil();

                //日限
                if (this.withInNum > 0)
                {
                    //選択された番号から時間データを得る
                    plusTime = this.threadViewControls.withInCBoxParts.GetTimeStructure();
                    //範囲から日時の文字列を得る
                    withInResponseDate = UnixTime.GetResponseDateByPlusTime(plusTime);

                    foreach (Comment comment in dat.comments)
                    {
                        if (comment.date.Equals("[過去ログ]") == true)
                            continue;

                        //打ち止めのレス（1001番目）
                        if (comment.date.Length < 21)
                            continue;

                        string date = comment.date.Substring(0, 10) + "/" + comment.date.Substring(13, 8);

                        if (date.CompareTo(withInResponseDate) < 0)
                            comment.cutFlag = true;
                    }
                }
                //ピンポイント
                else if (this.pinPointData.Length > 0)
                {
                    foreach (Comment comment in dat.comments)
                    {
                        if (comment.date.Equals("[過去ログ]") == true)
                            continue;
                        //打ち止めのレスの場合（１００１番目）
                        if (comment.date.Length < 21)
                            continue;

                        string date = comment.date.Substring(0, 10) + "/" + comment.date.Substring(13, 8);

                        if (comment.date.Substring(0, 10).Equals(this.pinPointData) == true)
                        {
                        }
                        else
                        {
                            comment.cutFlag = true;
                        }
                    }
                }
                if ((this.threadViewControls.analysisMagic.oneLineCut == true) ||
                    (this.threadViewControls.analysisMagic.twoLineCut == true) ||
                    (this.threadViewControls.analysisMagic.threeLineCut == true) ||
                    (this.threadViewControls.analysisMagic.fourLineCut == true))
                {
                    int cutNum = 0;
                    if (this.threadViewControls.analysisMagic.oneLineCut == true)
                        cutNum = 1;
                    if (this.threadViewControls.analysisMagic.twoLineCut == true)
                        cutNum = 2;
                    if (this.threadViewControls.analysisMagic.threeLineCut == true)
                        cutNum = 3;
                    if (this.threadViewControls.analysisMagic.fourLineCut == true)
                        cutNum = 4;

                    foreach (Comment comment in dat.comments)
                    {
                        int count = 0;
                        int num = 0;
                        while (true)
                        {
                            num = comment.body.IndexOf("<br>", num);
                            if (num == -1) break;
                            num += 4;
                            count += 1;
                        }
                        if (count < cutNum)
                        {
                            //コメントにマークする
                            comment.cutFlag = true;
                        }
                    }
                }

                if (this.threadViewControls.analysisMagic.kusaCut == true)
                {
                    foreach (Comment comment in dat.comments)
                    {
                        int num = 0;
                        while (true)
                        {
                            num = comment.body.IndexOf("w", num);
                            if (num == -1) break;
                            if (num == 0)
                            {
                                comment.cutFlag = true;
                            }
                            //一つ前の文字列を取り出す
                            string data = comment.body[num - 1].ToString();
                            //shift-jisのバイトに変換
                            Byte[] byteData = Encoding.GetEncoding("shift_jis").GetBytes(data);
                            //文字を文字コードで比較
                            if (byteData.Length > 1)
                                break;
                            byte a = Byte.Parse(byteData[0].ToString());
                            if ((a >= 40) && (a <= 122))
                                break;
                            comment.cutFlag = true;

                            num += 1;
                        }
                        //大文字に対応
                        num = 0;
                        num = comment.body.IndexOf("ｗ", num);
                        if (num != -1)
                            comment.cutFlag = true;
                    }
                }

                if (this.threadViewControls.analysisMagic.noAnchorCut == true)
                {
                    foreach (Comment comment in dat.comments)
                    {
                        int num = 0;
                        num = comment.body.IndexOf("&gt;&gt;", num);
                        if (num == -1)
                            comment.cutFlag = true;
                    }
                }

                if (dat.comments.Where(a => a.cutFlag == false).Count() == 0)
                    sb.Append("*見つかりませんでした。");
                else
                {
                    foreach (Comment comment in dat.comments)
                    {
                        if (comment.cutFlag == true) continue;
                        //コメントを書き出す
                        if (comment.abon == false)
                            sb.Append(commentUtil.to_html(comment, dat.dat_url));
                        else
                        {
                            //アボン用の出力
                            sb.Append(commentUtil.ToAbonHtml(comment, dat.dat_url));
                        }
                    }
                }
                //カットを元に戻す
                foreach (Comment comment in dat.comments)
                {
                    comment.cutFlag = false;
                }
            }
            catch { ;}
        }

        public void SetExtractionData(int withInNum, string pinPointData, string pinPointJPData)
        {
            /* ロック */
            if (this.ageonMutex.WaitOne() == false)
            {
                this.ageonMutex.ReleaseMutex();
                return;
            }
            this.withInNum = withInNum;
            this.pinPointData = pinPointData;
            this.pinPointJPData = pinPointJPData;

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

        public void ReSetExtractionData()
        {
            if (this.ageonMutex.WaitOne() == false)
            {
                this.ageonMutex.ReleaseMutex();
                return;
            }
            this.withInNum = 0;
            this.pinPointData = "";
            this.pinPointJPData = "";

            this.threadViewControls.analysisMagic.oneLineCut = false;
            this.threadViewControls.analysisMagic.twoLineCut = false;
            this.threadViewControls.analysisMagic.threeLineCut = false;
            this.threadViewControls.analysisMagic.fourLineCut = false;
            this.threadViewControls.analysisMagic.kusaCut = false;
            this.threadViewControls.analysisMagic.noAnchorCut = false;

            this.threadViewControls.analysisMagic.analysisMagicControls.oneLineCutCBoxParts.Checked = false;
            this.threadViewControls.analysisMagic.analysisMagicControls.twoLineCutCBoxParts.Checked = false;
            this.threadViewControls.analysisMagic.analysisMagicControls.threeLineCutCBoxParts.Checked = false;
            this.threadViewControls.analysisMagic.analysisMagicControls.fourLineCutCBoxParts.Checked = false;
            this.threadViewControls.analysisMagic.analysisMagicControls.kusaCutCBoxParts.Checked = false;
            this.threadViewControls.analysisMagic.analysisMagicControls.noAnchorCutCBoxParts.Checked = false;

            this.ageonMutex.ReleaseMutex();
        }

        public string get_thread_name()
        {
            return this.threadName;
        }

        private void SetIcon(ThreadViewCommon view)
        {

            string type = Util.BoardUrlToBoardTypeName(view.datUrl);
            if (true == type.Equals("2chsc"))
                Const.form.mainForm.Invoke((Action)(() => view.threadViewControls.tabPageExParts.control.ImageIndex = 13));
            else if (true == type.Equals("2ch"))
                Const.form.mainForm.Invoke((Action)(() => view.threadViewControls.tabPageExParts.control.ImageIndex = 14));
            else if (true == type.Equals("open2ch"))
                Const.form.mainForm.Invoke((Action)(() => view.threadViewControls.tabPageExParts.control.ImageIndex = 15));
            else if (true == type.Equals("next2ch"))
                Const.form.mainForm.Invoke((Action)(() => view.threadViewControls.tabPageExParts.control.ImageIndex = 16));
            else if (true == type.Equals("jikkyo"))
                Const.form.mainForm.Invoke((Action)(() => view.threadViewControls.tabPageExParts.control.ImageIndex = 17));
            else if (true == type.Equals("blogban"))
                Const.form.mainForm.Invoke((Action)(() => view.threadViewControls.tabPageExParts.control.ImageIndex = 18));
            else if (true == type.Equals("shizu"))
                Const.form.mainForm.Invoke((Action)(() => view.threadViewControls.tabPageExParts.control.ImageIndex = 19));

            else if (true == type.Equals("vip2ch"))
                Const.form.mainForm.Invoke((Action)(() => view.threadViewControls.tabPageExParts.control.ImageIndex = 20));
            else if (true == type.Equals("machibbs"))
                Const.form.mainForm.Invoke((Action)(() => view.threadViewControls.tabPageExParts.control.ImageIndex = 21));
            else if (true == type.Equals("jbbs"))
                Const.form.mainForm.Invoke((Action)(() => view.threadViewControls.tabPageExParts.control.ImageIndex = 22));
            else
                Const.form.mainForm.Invoke((Action)(() => view.threadViewControls.tabPageExParts.control.ImageIndex = -1));
        }

        private string Redirect2chSC(string datUrl)
        {
            string urlSave = datUrl.ToString();
            try
            {
                if (Util.TYPE_2CH == Util.BoardType(datUrl))
                {
                    //アドレスの所属元BBSを得る
                    //string datUrl = Util.ThreadUrlToDatUrl(url);
                    string boardUrl = Util.DatUrlToBoardBBSUrl(datUrl);
                    //BoardDataBaseからscの同じ名前の板を探す
                    string threadID = Util.DatUrlToThreadID(datUrl);
                    string boardName = Util.BoardUrlToBoardID(boardUrl);

                    boardName = "2chsc" + boardName;
                    if (BoardDataBase.urlDic.ContainsKey(boardName))
                    {
                        string scBoardUrl = BoardDataBase.urlDic[boardName];
                        ThreadInfo thread = DownloadToSetSC(scBoardUrl + "subject.txt", scBoardUrl);
                        if (thread != null)
                        {
                            int num = thread.threadDataList.FindLastIndex(a => a.datUrl.EndsWith(threadID + ".dat") == true);
                            datUrl = thread.threadDataList[num].datUrl;
                            //url = Util.DatUrlToThreadUrl(url);
                        }
                    }
                }
            }
            catch
            {
                datUrl = urlSave;
            }
            return datUrl;
        }

        public ThreadInfo DownloadToSetSC(string subjectTextUrl, string boardUrl)
        {
            try
            {
                string str;
                DownloadSubject ds = new DownloadSubject();
                if (true == ds.DownloadSubjectText(subjectTextUrl))
                {
                    str = ds.httpResData;
                }
                else
                    return null;

                if (str.Length <= 0)
                    return null;

                ThreadInfo newInfo = SubjectUtil.ParseSubjectLines(str, boardUrl);
                return newInfo;
            }
            catch { ;}
            return null;
        }

    }
}