using System;
using System.IO;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Xml;
using System.Collections;
using System.Diagnostics;

namespace カブラウザもどき
{
    public class GetYahooTextream : GetYahoo
    {
        /*
        private CurrentContext context = null;
        private TextBox console = null;
        private ToolStripStatusLabel console2 = null;
        private Hashtable edinetlist;
        private WebBrowserController ndbControl = null;
         * */

        public GetYahooTextream(カブラウザもどき.CurrentContext context, TextBox console, StatusStrip console2, WebBrowserController ndbControl, Hashtable edinetlist)
        {
            this.context = context;
            this.console = console;
            this.console2 = console2;
            this.ndbControl = ndbControl;
            this.edinetlist = edinetlist;
            this.context.SetYahooInstance(this);
        }
        
        public override string GetReplyUrl(string mid)
        {
            if (context.GetCode() == "") return "";
            return "http://textream.yahoo.co.jp/message/"+context.board+"/"+context.tid+"?comment="+mid;
        }
        public override string GetThreadUrl(string mid)
        {
            //textreamではスレッド表示は廃止されたため、空文字を返す
            return "";
        }
        public override string GetBaseUrl()
        {
            if (context.GetCode() == "") return "";
            return "http://textream.yahoo.co.jp/message/" + context.board + "/" + context.tid;
        }
        public override string GetMassageUrl(string mid)
        {
            if (context.GetCode() == "") return "";
            return "http://textream.yahoo.co.jp/message/" + context.board + "/" + context.tid + "?comment=" + mid;
        }
        public string GetPostedSelf()
        {
            return "http://textream.yahoo.co.jp/personal/history/comment";
        }
        public override string GetMessageListFromUserId(string sender)
        {
            if (sender == "") return "";
            foreach (TitleLists t in context.t) {
                if (t.sender == sender) {
                    return "http://textream.yahoo.co.jp/personal/history/comment?user=" + t.user;
                }
            }
            return "";
        }
        /// <summary>
        ///　無条件にtrueを返す
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        public override bool IsValidYahooCode(string code)
        {
            return true;
        }

        /// <summary>
        /// TitleListに表示する件数
        /// Textream Yahoo掲示板では20件
        /// </summary>
        /// <returns></returns>
        public override uint GetDisplayRows()
        {
            return 20;
        }

        public override string GetContents(string mid )
        {
            YahooSkin skin = context.GetSkin();
            skin.ContextToSkin(context);
            TitleLists thisTitle = null;
            TitleLists[] titles = null;
            string s = "";

            if (context.tFlag) {
                titles = context.t;
            } else {
                titles = context.s;
            }

            foreach (TitleLists t in titles) {
                if (t.titleNo == mid) {
                    thisTitle = t;
                    break;
                }
            }

            if (thisTitle != null) {
                skin.set("&MESSAGE", thisTitle.content);
                skin.set("&RESURL", GetReplyUrl(mid));
                skin.set("&NUMBER", thisTitle.titleNo);
                skin.set("&TITLE", thisTitle.title);
                skin.set("&NAME", thisTitle.sender);
                skin.set("&FEELINGS", thisTitle.emotion);
                skin.set("&DATE", thisTitle.sendTime);
                skin.set("&M_FINDMSG", GetMessageListFromUserId(thisTitle.sender));
                skin.set("&M_COMMENT_THM", thisTitle.userIcon);
                
            }
            //ニックネームはひとまず置いておく
            //                            skin.set("&M_NICKNAME", e.GetAttribute("HREF").Replace("http://search.messages.yahoo.co.jp/search/?p=", ""));
            return "";
        }


        public override void SaveAllTitleList(string code)
        {
            int maxTitleNo = 0;  // 取得済みのtitle
            string className = "";
            string path = "";
            StreamWriter sw = null;
            NonDispBrowser ndb = (NonDispBrowser)ndbControl.GetBrowser();

            if (code == "") { return ; }

            bool bReadExitFlag = false; // キャッシュされた最新まで達したので読込み終了する

            if ((MessageBox.Show("この処理を行うとタイトルによる「全文検索」が可能となりますが、\n処理は５分から１０分程度の時間がかかります。続行しますか？", "ダウンロード確認",
                    MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.No)) { return ; }

            if (File.Exists(Form1.csDatDir + code + ".dat")) {
                string line = "";
                using (StreamReader sr = new StreamReader(Form1.csDatDir + code + ".dat")) {
                    line = sr.ReadLine();
                    if (line != null && line.Split(Form1.delimiter).Length > 1) {
                        maxTitleNo = int.Parse(line.Split(Form1.delimiter)[0]);
                        MessageBox.Show(maxTitleNo + "以降を取得して保存します。");
                    }
                }
            }

            if (!context.Lock()) { MessageBox.Show("銘柄コードは現在ロックされています\nしばらくお待ちください"); return ; }
            try {

                int chk = GetTopicId(code);

                // 最新の一覧
                ndb.NavigateAndWait(this.GetBaseUrl());
                path = Form1.csDatDir + code + ".dat";
                sw = new StreamWriter(path, true);

                // 銘柄情報
                sw.WriteLine("0" + Form1.delimiter + context.tid + Form1.delimiter + context.GetCodeAndExchange() + Form1.delimiter + context.comapnyName);

                for (int i = 0; i <= (context.GetMaxTitleNo() / GetDisplayRows()); i++) {

                    HtmlDocument doc = ndb.Document;

                    SetTitleListsFromHtml(doc);

                    foreach (TitleLists t in context.t) {
                        if (t.titleNo != "") {
                            t.WriteLine(sw, true);
                        }
                    }

                    if (context.prevPage != "") {
                        console.AppendText("(*･ ｘ･ )ﾂｷﾞ>" + context.prevPage + Form1.csCrLf);
                        ndb.NavigateAndWait(context.prevPage);
                    } else {
                        //次のページが存在しない
                        bReadExitFlag = true;
                    }
                    if (bReadExitFlag) break;

                }
                /*

                TitleLists data = new TitleLists();
                HtmlElement elm = null;
                HtmlElement elm2 = null;
                HtmlElement ttl = null;
                HtmlElement commentTxt = null;
                HtmlElement commentThm = null;
                HtmlElementCollection tmp = null;
                HtmlElementCollection elms = null;
                HtmlElementCollection elms2 = null;
                for (int i = 0; i <= (context.GetMaxTitleNo() / GetDisplayRows()); i++) {

                    console2.Text = ndb.Url.ToString();
                    HtmlDocument doc = ndb.Document;
                    foreach (HtmlElement e in doc.GetElementsByTagName("A")) {
                        if (e.InnerText == "次のページ") {
                            context.prevPage = e.GetAttribute("href");
                            break;
                        }
                    }
                    // 取得方法は GetTitleLists()と同じ
                    foreach (HtmlElement e in doc.GetElementsByTagName("a")) {

                        className = e.GetAttribute("className");
                        System.Console.WriteLine(className);
                        if (className == "commentTitle") {

                            ttl = e.Parent.Parent.Parent;
                            if (ttl.GetElementsByTagName("dt").Count > 0) {
                                if (ttl.GetElementsByTagName("dt")[0].GetElementsByTagName("span").Count > 0) {
                                    data.titleNo = ttl.GetElementsByTagName("dt")[0].GetElementsByTagName("span")[0].InnerText.Replace("No.", "");
                                    if (maxTitleNo == 0) {
                                        maxTitleNo = int.Parse(data.titleNo);
                                    }
                                }
                            }

                            elm = Utils.GetElementByClassName(ttl, "commentTitle");
                            if (elm != null) data.title = elm.InnerHtml;

                            elm = Utils.GetElementByClassName(ttl, "labelEmotion", "p");
                            if (elm != null) data.emotion = elm.InnerText;

                            elm = Utils.GetElementByClassName(ttl, "name cf");
                            if (elm != null) {
                                tmp = elm.GetElementsByTagName("a");
                                if (tmp.Count > 0) {
                                    data.sender = tmp[0].InnerText;
                                } else {
                                    // A tagに存在しない場合は p タグの場合もある
                                    tmp = elm.GetElementsByTagName("p");
                                    if (tmp.Count > 0) {
                                        data.sender = tmp[0].InnerText;
                                    }
                                }
                            }

                            elm = Utils.GetElementByClassName(ttl, "date");
                            if (elm != null) data.sendTime = elm.InnerHtml;

                            commentTxt = ttl.Parent.Parent;

                            // userIcon, user
                            commentThm = commentTxt.Parent;
                            elm = Utils.GetElementByClassName(commentThm, "commentThm", "p");
                            if (elm != null) {
                                elms2 = elm.GetElementsByTagName("img");
                                if (elms2.Count > 0) {
                                    elm2 = elms2[0];
                                    if (elm2 != null) data.userIcon = elm2.GetAttribute("src");
                                }
                                elms2 = elm.GetElementsByTagName("a");
                                if (elms2.Count > 0) {
                                    elm2 = elms2[0];
                                    if (elm2 != null) data.user =
                                        elm2.GetAttribute("href").Replace("http://textream.yahoo.co.jp/personal/history/comment?user=", "");
                                }

                            } else {
                                data.userIcon = "http://i.yimg.jp/images/mb/textream/pc/thumb02.png";
                                data.user = "";
                            }
                            data.WriteLine(sw, true);

                            if (int.Parse(data.titleNo) > maxTitleNo) {
                                bReadExitFlag = true;
                                break;
                            }

                        }
                        if (bReadExitFlag) break;
                    }
                    if (context.prevPage != "") {
                        ndb.NavigateAndWait(context.prevPage);
                    } else {
                        //次のページが存在しない
                        bReadExitFlag = true;
                    }
                    if (bReadExitFlag) break;
                } // 読込みループ終了
                 * */
                sw.Close();
                sw = null;
                Utils.SortUniqTitleList(path);
            }
            finally {
                context.UnLock();
            }

            MessageBox.Show("ダウンロード完了！");
            return ;
        }

        /// <summary>
        ///  Yahoo掲示板のTopic ID (tid=部分)、最大TitleNo を取得する.取得値は状態変数に格納する
        ///  この値は変則で、単に銘柄コード(ex.2432)もあれば、ランダム？(8136 -> a55a5sa5jaaa) 
        ///  パターンもある。
        ///  ・textreamの場合はどこからTIDを取ってくればいいのかわからない
        ///  　とりあえず、固定値を使用する。
        ///  　存在しない場合は銘柄コードで推定する。
        /// </summary>
        /// <returns>0:正常 -1:異常</returns>
        public override int GetTopicId(string code)
        {
            int ret = -1;
            if (edinetlist.ContainsKey(code)) {
                context.tid = ((string)edinetlist[code]).Split(',')[3];
            }
            if (context.tid != "") {
                ret = 0;
            } else {
                context.tid = code;
            }
            context.postUrl = GetBaseUrl() + "#commentEntryForm";
            return ret;
        }

        /// <summary>
        ///  Yahoo掲示板のその他の情報を取得する
        ///  HtmlDocument docには正常なDocumentオブジェクトを渡すこと.
        ///  此処ではチェックしない
        ///  セットする値(context):  codeAndExchange, comapnyName
        ///  セットする値(yahoo):  &DATE, &CLOSE, &CHANGE 
        /// </summary>
        /// <returns>0:正常 -1:異常</returns>
        public override void GetOtherInfo(string code, HtmlDocument doc)
        {

            try {
                // IMG用の市場コードを含んだ銘柄コード
                foreach (HtmlElement e in doc.GetElementsByTagName("IMG")) {
                    string sLink = e.GetAttribute("src");
                    try {
                        if (sLink.Length >= 36 && (sLink.Substring(0, 30) == "http://rchart.yahoo.co.jp/t?s=" ||
                                                   sLink.Substring(0, 30) == "http://gchart.yahoo.co.jp/t?s=")) {
                            string tmp = sLink.ToString().Substring(30, sLink.Length - 30);
                            context.SetCodeAndExchange(tmp.Split('&')[0]);
                            break;
                        }
                    }
                    catch (NullReferenceException exp) {
                        context.SetCodeAndExchange("");
                    }
                }

                int itemCnt = 0;
                foreach (HtmlElement e in doc.GetElementsByTagName("meta")) {
                    
                    if (itemCnt == 1) break;

                    switch (e.GetAttribute("property")) {
                        case "og:title":
                            context.title = e.GetAttribute("content").ToString();
                            context.comapnyName = context.title.Split('-')[1].TrimStart().TrimEnd();
                            itemCnt++;
                            break;
                        default:
                            break;
                    }
                }
            }
            catch (IndexOutOfRangeException e) {
                console.AppendText(e.ToString() + Form1.csCrLf);
            }
            catch (NullReferenceException e) {
                console.AppendText(e.ToString() + Form1.csCrLf);
            }
            return ;
        }
        public override int GetSid(string code)
        {
            int ret = -1;
            if (edinetlist.ContainsKey(code)) {
                context.sid = ((string)edinetlist[code]).Split(',')[2];
            }

            if (context.sid != "") {
                ret = 0;
            } else {
                context.sid = "100" + code;
            }
            return ret;
        }
        public override int GetBorad(string code)
        {
            int ret = -1;
            if (edinetlist.ContainsKey(code)) {
                context.board = ((string)edinetlist[code]).Split(',')[1];
            }
            if (context.board != "") {
                ret = 0;
            } else {
                context.board = "100" + code;
            }
            return ret;
        }


        /// <summary>
        /// YahooTextreamから該当銘柄コードのTitle一覧の取得を行う
        /// 投稿タイトル一覧を取得して配列に格納する
        /// 履歴：
        /// </summary>
        /// <param name="pageNo">ぺジー番号 0:最新 -1:前の40件 1:次の40件</param>
        public override void GetTitleLists(string longCode, int pageNo)
        {
            string url = "";
            int ret = 0;

            //Stopwatch sw = new Stopwatch();
            NonDispBrowser ndb = (NonDispBrowser)ndbControl.GetBrowser();

            switch (pageNo) {
                case 1:
                    if (context.nextPage == null || context.nextPage == "") {
                        ret = -1;
                    } else {
                        url = context.nextPage;
                        context.ClearTitleList();
                    }
                    break;
                case -1:
                    if (context.prevPage == null || context.prevPage == "") {
                        ret = -1;
                    } else {
                        context.ClearTitleList();
                        url = context.prevPage;
                    }
                    break;
                case 0:
                default:
                    url = GetBaseUrl();
                    ret = GetTopicId(context.GetCode());
                    //yahoo.GetOtherInfo(context.GetCode(), false);
                    break;
            }

            ComConstants now = ndbControl.DlControl;
            console.AppendText("( ･∀･)ﾉ > げっと！　 " + context.GetCode() + Form1.csCrLf);

            if (ret == 0) {
                if (!context.Lock()) { MessageBox.Show("銘柄コードは現在ロックされています\nしばらくお待ちください"); return ; }
                try {
                    ComConstants filter = ComConstants.DLCTL_NO_JAVA
                                        | ComConstants.DLCTL_NO_SCRIPTS
                                        | ComConstants.DLCTL_NO_DLACTIVEXCTLS
                                        | ComConstants.DLCTL_NO_RUNACTIVEXCTLS
                                        | ComConstants.DLCTL_DLIMAGES;
                    ndbControl.DlControl = filter;

                    // URLパターン
                    // Page1: http://textream.yahoo.co.jp/message/1002432/2432?page=2&sort=d&feel=99
                    // Page2: http://textream.yahoo.co.jp/message/1008136/a55a5sa5ja5aa?page=2&sort=d&feel=99
                    //または、
                    // Page(最新): http://textream.yahoo.co.jp/message/1002432/2432

                    //sw.Start();
                    if (!ndb.NavigateAndWait(url)) {
                        console.AppendText("（｡・-・）失敗ｼﾀﾖｳﾀﾞ...もう一回やって！" + Form1.csCrLf);
                        return ;
                    }
                    //sw.Stop();
                    //this.textBox2.AppendText("DL時間2：" + sw.ElapsedMilliseconds + csCrLf);
                    HtmlDocument doc = ndb.Document;
                    console.AppendText("（ *´∀｀） ｱﾘｶﾞﾄｳ ぼくらのTextream! " + doc.Title.ToString() + Form1.csCrLf);

                    SetTitleListsFromHtml(doc);

                }
                finally {
                    context.UnLock();
                    ndbControl.DlControl = now;
                }
            } else // GetTopicId() の戻り値 not 0 
            {
                console.AppendText("( ・益・)　ﾉ > ﾖｲﾖｲわかんねぇよ。" + Form1.csCrLf);
            }
            return ;
        }

        /// <summary>
        /// HTMLドキュメントを解析して、context.TitleLists構造体に詰める
        /// </summary>
        /// <param name="doc"></param>
        private void SetTitleListsFromHtml(HtmlDocument doc)
        {
            int itemCnt = 0;

            // テーブル内の文字列を構造体に格納する
            // タイトル一覧はHTMLの四重にネストされたテーブル配下にある.
            int rowCnt = 0;
            string className = "";
            HtmlElement elm = null;
            HtmlElement elm2 = null;
            HtmlElement ttl = null;
            HtmlElement commentTxt = null;
            HtmlElement commentBox = null;
            HtmlElement commentThm = null;
            HtmlElement ttlDate = null;
            HtmlElementCollection tmp = null;
            HtmlElementCollection elms = null;
            HtmlElementCollection elms2 = null;

            // title no :  .commentBox > .commentTxt cf > input type=hidden name=commentInfo
            // title no :  (li).commentBox > (div).commentTxt cf > .textArea cf > (div).ttlArea cf > (dl).ttlInfo > (div).ttlInfoDateNum > (p)[0]
            // title :  (li).commentBox > (div).commentTxt cf > .textArea cf > (div).ttlArea cf > (dl).ttlInfo > .commentTitle
            // sender : (li).commentBox > (div).commentTxt cf > .textArea cf > (div).ttlArea cf > (dl).ttlInfo > (p).userName
            // user   : (li).commentBox > (div).commentTxt cf > .textArea cf > (div).ttlArea cf > (dl).ttlInfo > .name cf > 
            // emotion :  (li).commentBox > (div).commentTxt cf > .textArea cf > (div).ttlArea cf > (dl).ttlInfo > .name cf > .labelEmotion
            // sendTime :  (li).commentBox > (div).commentTxt cf > .textArea cf > (div).ttlArea cf > (dl).ttlInfo > (div).ttlInfoDateNum > (p)[1]
            // content :  (li).commentBox > .commentTxt cf > .hideDetail > detail
            // user : (li).commentBox > (p).commentThm > aタグ 属性href user=配下
            // userIcon : (li).commentBox > (p).commentThm > (img)

            //sw.Start();
            foreach (HtmlElement e in doc.GetElementsByTagName("a")) {

                className = e.GetAttribute("className");
                // System.Console.WriteLine(className);
                if (className == "commentTitle") {
                    ttl = e.Parent.Parent.Parent;
                    ttlDate = Utils.GetElementByClassName(ttl, "ttlInfoDateNum");
                    if (ttlDate != null) {
                        if (ttlDate.GetElementsByTagName("p").Count > 0) {
                            context.t[rowCnt].titleNo = ttlDate.GetElementsByTagName("p")[0].InnerText.Replace("No.", "");
                        }
                    }

                    // メッセージタイトル
                    elm = Utils.GetElementByClassName(ttl, "commentTitle");
                    if (elm != null) context.t[rowCnt].title = elm.InnerHtml;

                    //　投稿時の気持ち
                    elm = Utils.GetElementByClassName(ttl, "labelEmotion", "p");
                    if (elm != null) context.t[rowCnt].emotion = elm.InnerText;

                    // 投稿者
                    elm = Utils.GetElementByClassName(ttl, "userName");
                    if (elm != null) {
                        context.t[rowCnt].sender = elm.InnerText;
                    }
                    /*
                    if (elm != null) {
                        tmp = elm.GetElementsByTagName("a");
                        if (tmp.Count > 0) {
                            context.t[rowCnt].sender = tmp[0].InnerText;
                        } else {
                            // A tagに存在しない場合は p タグの場合もある
                            tmp = elm.GetElementsByTagName("p");
                            if (tmp.Count > 0) {
                                context.t[rowCnt].sender = tmp[0].InnerText;
                            }
                        }
                    }
                     * */

                    // 投稿時間
                    if (ttlDate != null) {
                        if (ttlDate.GetElementsByTagName("p").Count > 1) {
                            context.t[rowCnt].sendTime = ttlDate.GetElementsByTagName("p")[1].InnerText;
                        }
                    }


                    commentTxt = ttl.Parent;
                    elm = Utils.GetElementByClassName(commentTxt, "detail");
                    if (elm != null) context.t[rowCnt].content = elm.InnerHtml.Replace(Form1.csCrLf, "<BR>");

                    // userIcon, user
                    context.t[rowCnt].user = "";
                    context.t[rowCnt].userIcon = "http://i.yimg.jp/images/mb/textream/pc/thumb02.png";
                    commentBox = commentTxt.Parent;
                    commentThm = Utils.GetElementByClassName(commentBox, "commentThm");
                    if (commentThm != null) {
                        // ユーザーアイコン
                        elms2 = commentThm.GetElementsByTagName("img");
                        if (elms2.Count > 0) {
                            elm2 = elms2[0];
                            if (elm2 != null) {
                                context.t[rowCnt].userIcon = elm2.GetAttribute("src");
                            }
                        }
                        // ユーザーID？
                        elms2 = commentThm.GetElementsByTagName("a");
                        if (elms2.Count > 0) {
                            elm2 = elms2[0];
                            if (elm2 != null) {
                                context.t[rowCnt].user =
                                   elm2.GetAttribute("href").Replace("http://textream.yahoo.co.jp/personal/history/comment?user=", "");
                            }
                        }

                    }
                    rowCnt++;
                }
            }
            //sw.Stop();
            //this.textBox2.AppendText("DOM解析時間：" + sw.ElapsedMilliseconds + csCrLf);
            if (int.Parse(context.t[0].titleNo) > int.Parse(context.maxTilteNo)) {
                context.maxTilteNo = context.t[0].titleNo;
            }

            //sw.Start();
            context.prevPage = "";
            context.nextPage = "";
            foreach (HtmlElement e in doc.GetElementsByTagName("A")) {
                string href = e.GetAttribute("href"); // HREF属性の値
                string text = e.InnerText; // リンク文字列

                if (e.InnerText == "前のページ") {
                    context.nextPage = e.GetAttribute("href");
                    itemCnt++;
                }
                if (e.InnerText == "次のページ") {
                    context.prevPage = e.GetAttribute("href");
                    itemCnt++;
                }
                if (itemCnt == 2) break;

            }
            //sw.Stop();
            //this.textBox2.AppendText("次/前ページ検索時間：" + sw.ElapsedMilliseconds + csCrLf);

            //yahoo掲示板のその他の情報を取得する
            if (context.comapnyName == "") {
                GetOtherInfo(context.GetCode(), doc);
            }
        }

        /**
         * 引数docにはyahoo.GetBaseUrl()をnavigateした結果を渡すこと
         * */
        public override int GetMaxTitleNo(HtmlDocument doc, bool isCheckLock)
        {
            int iMaxTitleNo = 0;
            bool breakFlag = false;

            if (doc.Title.ToString().Equals("エラー - textream")) {
                console.AppendText("（｡・-・）ﾖｲﾖｲ...変な値が返ってるよ..." + Form1.csCrLf);
                return -1;
            }

            // object lcok
            if (isCheckLock) {
                if (!context.Lock()) { MessageBox.Show("銘柄コードは現在ロックされています\nしばらくお待ちください"); return -1; }
            }
            // object lock

            try {
                HtmlElementCollection elms = doc.GetElementsByTagName("div");
                foreach ( HtmlElement e in elms ) { 
                    if ( e.GetAttribute("className").ToString() == "commentTxt cf" ) {
                        foreach ( HtmlElement ee in e.GetElementsByTagName("input")) {
                            if ( ee.GetAttribute("name") == "commentInfo" ) {
                                iMaxTitleNo = int.Parse( ee.GetAttribute("value"));
                                breakFlag = true;
                                break;

                            }
                        }
                    }
                    if (breakFlag) break;
                }
                context.maxTilteNo = iMaxTitleNo.ToString();
            }
            finally {
                if (isCheckLock) {
                    context.UnLock();
                }
            }
            return 0;
        }

    }
}
