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

namespace カブラウザもどき
{
    /// <summary>
    /// 旧ヤフー掲示板から情報取得を受け持つクラス
    /// Form1クラスとはcontextクラスを介して情報の受け渡しを行う
    /// ヤフー掲示板の仕様に依存する実装を行う。
    /// このクラスはtextream以前のもの。
    /// </summary>
    public class GetYahoo : AbstractGetYahoo
    {
        /*
        private CurrentContext context = null;f
        private TextBox console = null;
        private ToolStripStatusLabel console2 = null;
        private Hashtable edinetlist;
        private WebBrowserController ndbControl = null;
        */
        private static NonDispBrowser ndbLocal = null;  // 裏で動く非表示のブラウザ(ActiveX制御あり)
        private WebBrowserController ndbLocalControl = null;

        public GetYahoo()
        {
            return;
        }
        /// <summary>
        /// 通常はこちらを使用
        /// </summary>
        /// <param name="context"></param>
        /// <param name="console">左下ウィンドウ</param>
        /// <param name="console2">一番下ステータスウィンドウ</param>
        /// <param name="ndbControl"></param>
        /// <param name="edinetlist"></param>
        public GetYahoo(カブラウザもどき.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);
            ndbLocal = new NonDispBrowser(console2);
            ndbLocalControl = new WebBrowserController(ndbLocal);
        }
        /// 返信用のURLを返す
        /// </summary>
        /// <param name="mid"></param>
        /// <returns></returns>
        public override string GetReplyUrl(string mid)
        {
            if (context.GetCode() == "") return "";
            return "http://post.messages.yahoo.co.jp/bbs?mm=FN&action=r&board=1" + context.GetPad() + context.GetCode() + "&tid=" + context.tid + "&sid=1" + context.GetPad() + context.GetCode() + "&mid=" + mid;
        }
        /// <summary>
        /// スレッドで表示URLを返す
        /// </summary>
        /// <param name="mid"></param>
        /// <returns></returns>
        public override string GetThreadUrl(string mid)
        {
            if (context.GetCode() == "") return "";
            return "http://post.messages.yahoo.co.jp/bbs?mm=FN&action=m&board=1" + context.GetPad() + context.GetCode() + "&tid=" + context.tid + "&sid=1" + context.GetPad() + context.GetCode() + "&mid=" + mid + "&thr=" + mid + "&cur=" + mid;
        }

        public override string GetHalfYearChartUrl()
        {
            if (context.GetCode() == "") return "";
            return "http://stocks.finance.yahoo.co.jp/stocks/chart/?code=" + context.GetCodeAndExchange() + "&ct=z&t=6m&q=c&l=off&z=m&p=m5,m25,s&a=v";
        }
        public override string GetNewsUrl()
        {
            if (context.GetCode() == "") return "";
            return "http://stocks.finance.yahoo.co.jp/stocks/news/?code=" + context.GetCode();
        }
        public override string GetColum()
        {
            if (context.GetCode() == "") return "";
            return "http://news.finance.yahoo.co.jp/search/?q=" + context.GetCode();
        }
        public override string GetCompanyInfo()
        {
            if (context.GetCode() == "") return "";
            return "http://stocks.finance.yahoo.co.jp/stocks/profile/?code=" + context.GetCode();
        }
        public override string GetDailyRankingUrl()
        {
            if (context.GetCode() == "") return "";
            return "http://messages.yahoo.co.jp/ranking/stocks/postranking_daily.html";
        }
        public override string GetWeeklyRankingUrl()
        {
            if (context.GetCode() == "") return "";
            return "http://messages.yahoo.co.jp/ranking/stocks/postranking_weekly.html";
        }
        public override string GetMonthlyRankingUrl()
        {
            if (context.GetCode() == "") return "";
            return "http://messages.yahoo.co.jp/ranking/stocks/postranking_monthly.html";
        }
        public override string GetBaseUrl()
        {
            if (context.GetCode() == "") return "";
            return "http://messages.yahoo.co.jp/bbs?action=topics&board=1" + context.GetPad() + context.GetCode() + "&tid=" + context.tid + "&sid=1" + context.GetPad() + context.GetCode() ;
        }
        public override string GetMassageUrl(string mid)
        {
            if (context.GetCode() == "") return "";
            return "http://messages.yahoo.co.jp/bbs?.mm=FN&action=m&board=1" + context.GetPad() + context.GetCode() + "&tid=" + context.tid + "&sid=1" + context.GetPad() + context.GetCode() + "&mid=" + mid;
        }
        public override string GetMessageListFromUserId(string sender)
        {
            //like this http://search.messages.yahoo.co.jp/search/?p=ayakai0116 
            if (context.GetCode() == "") return "";
            return "http://search.messages.yahoo.co.jp/search/?p=" + sender;
        }
        public string GetLoadUrl()
        {
            return "http://messages.yahoo.co.jp/bbs?.mm=FN&action=l&board=1003864&sid=1003864&tid=bb0ia9c0bdbbf";
        }
        public string GetMatomeUrl(string mid)
        {
            //for example: http://messages.yahoo.co.jp/bbs?.mm=FN&action=5&board=1001720&tid=1720&sid=1001720&mid=1968
            return "http://messages.yahoo.co.jp/bbs?.mm=FN&action=5&board="+context.board+"&tid="+context.tid+"&sid="+context.sid+"&mid=" + mid;
        }

        /// <summary>
        /// 自分の投稿
        /// </summary>
        /// <returns></returns>
        public override string GetPostedSelf() {
            return "http://messages.yahoo.co.jp/my.html";
        }

        public override bool IsValidYahooCode(string code)
        {
            bool ret = false;
            string chkUrl = "http://m.finance.yahoo.co.jp/stock/bbs?code=" + code;

            HtmlDocument doc = null;
            try {
                ndbLocal.NavigateAndWait(chkUrl);
                doc = ndbLocal.Document;

                // エラーチェック
                if (doc.Title.ToString() == "エラー - Y!ファイナンス") {

                    console.AppendText("( ・益・)ﾉ > そんなもんねぇよ。　 " + code + Form1.csCrLf);

                } else {

                    // 会社名を解析
                    string companyName = doc.Title.ToString();
                    context.comapnyName = companyName.Split('【')[0];
                    console.AppendText(doc.Title.ToString() + Form1.csCrLf);

                    string sLink = "";
                    HtmlElementCollection el = doc.GetElementsByTagName("A");
                    foreach (HtmlElement e in el) {
                        sLink = e.GetAttribute("href");
                        context.SetCode(code);
                        if (sLink.ToString() == "http://m.finance.yahoo.co.jp/stock?code=" + context.GetCode() + ".T" ||
                            sLink.ToString() == "http://m.finance.yahoo.co.jp/stock?code=" + context.GetCode() + ".O" ||
                            sLink.ToString() == "http://m.finance.yahoo.co.jp/stock?code=" + context.GetCode() + ".Q") {
                            context.SetCodeAndExchange(e.GetAttribute("href").Replace("http://m.finance.yahoo.co.jp/stock?code=", ""));
                        }
                    }

                    ret = true;
                }
            }
            finally {
                //何もしない
            }
            return ret;
        }

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

        /// <summary>
        /// チャートのhtmlを取得する
        /// </summary>
        /// <returns></returns>
        public override string GetChartHtml(WebBrowser webBrowser1)
        {
            string ret = "";
            if (webBrowser1.Version.Major > 6) {
                ret = "<style type='text/css'>TD.y_chart { font-size: 12px; background: #EEEEDD; border: 1px; }</style>";
                ret += "<br><table border='1' cellspacing='0'><tr>";
                ret += "<td class='y_chart'>日足</td><td class='y_chart'>1週間</td></tr><tr>";
                ret += "<td rowspan='3'><img src='http://rchart.yahoo.co.jp/z?s=" + context.GetCodeAndExchange() + "&t=6m&l=off&z=m&q=c&a=v&c=' width='400'></img>";
                ret += "</td><td rowspan='1'>";
                ret += "<img src='http://rchart.yahoo.co.jp/g?s=" + context.GetCodeAndExchange() + "&t=6m&l=off&z=m&q=c&a=v&c=' width='200'></img>";
                ret += "</tr><tr><td class='y_chart'>日中足</td></tr><tr><td rowspan='1'>";
                ret += "<img src='http://rchart.yahoo.co.jp/f?s=" + context.GetCodeAndExchange() + "&t=6m&l=off&z=m&q=c&a=v&c=' width='200'></img>";
                ret += "</td></tr></table>";
            } else  // IE6以下はアンチエイリアスが効かなくて汚い
            {
                ret = "<style type='text/css'>TD.y_chart { font-size: 12px; background: #EEEEDD; border: 1px; }</style>";
                ret += "<br><table border='1' cellspacing='0'><tr>";
                ret += "<td class='y_chart'>日足</td><td class='y_chart'>1週間</td></tr><tr>";
                ret += "<td rowspan='3'><img src='http://rchart.yahoo.co.jp/z?s=" + context.GetCodeAndExchange() + "&t=6m&l=off&z=m&q=c&a=v&c='></img>";
                ret += "</td><td rowspan='1'>";
                ret += "<img src='http://rchart.yahoo.co.jp/g?s=" + context.GetCodeAndExchange() + "&t=6m&l=off&z=m&q=c&a=v&c=' ></img>";
                ret += "</tr><tr><td class='y_chart'>日中足</td></tr><tr><td rowspan='1'>";
                ret += "<img src='http://rchart.yahoo.co.jp/f?s=" + context.GetCodeAndExchange() + "&t=6m&l=off&z=m&q=c&a=v&c=' ></img>";
                ret += "</td></tr></table>";
            }
            return ret;
        }


        /// <summary>
        ///  Yahoo掲示板のTopic ID (tid=部分)、最大TitleNo を取得する.取得値は状態変数に格納する
        ///  この値は変則で、単に銘柄コード(ex.2432)もあれば、ランダム？(8136 -> a55a5sa5jaaa) 
        ///  パターンもある。取得した値はコンテキストに格納する
        ///  セットする値(context):  Code, Tid , maxTilteNo
        /// </summary>
        /// <returns>0:正常 -1:異常</returns>
        public override int GetTopicId(string code)
        {
            int ret = 0;         // 戻り値
            // ローカルにコードが存在するならそのまま返す
            if (edinetlist.ContainsKey(code)) {
                context.tid = ((string)edinetlist[code]).Split(',')[3];
                return ret;
            } else {
                context.tid =  code;
            }
            return ret;
        }


        /**
         * 引数docにはyahoo.GetBaseUrl()をnavigateした結果を渡すこと
         * */
        public int GetTopicId(HtmlDocument doc, bool isCheckLock)
        {

            int iMaxTitleNo = 0;
            bool breakFlag = false;
            bool titleFlag = false;
            string sComp = "";

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

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

            try {
                // Topic id取得
                foreach (HtmlElement e in doc.GetElementsByTagName("LINK")) {
                    string text = e.OuterHtml.Replace("&amp;", "&"); // リンク文字列
                    string[] aTmp;
                    if (text.IndexOf("rel=alternate") != -1) {
                        aTmp = text.Split('&');
                        int iCnt = 0;
                        foreach (string s in aTmp) {
                            if (s.Length > 3 && s.Substring(0, 3) == "tid") {
                                string regularTid = s.Split('=')[1];
                                regularTid = regularTid.Split('"')[0];
                                context.tid = regularTid;

                                // デバッグ用
                                System.Console.WriteLine(context.GetCode() + ": " + GetBaseUrl() + "&tid=" + context.tid);
                                using (StreamWriter sw = new StreamWriter(Form1.csDatDir + "TitleList.txt", true)) {
                                    sw.WriteLine(context.GetCode() + ": " + GetBaseUrl() + "&tid=" + context.tid);
                                    sw.Close();
                                }
                                breakFlag = true;
                            }
                            if (breakFlag) break;
                        }

                    }
                    if (breakFlag) break;

                }

            }
            finally {
                if (isCheckLock) {
                    context.UnLock();
                }
            }
            return 0;
        }

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

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

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

            try {
                // 最大TitleNo取得
                foreach (HtmlElement e in doc.GetElementsByTagName("A")) {
                    string sLink = e.GetAttribute("href");

                    if (sLink.Length > 33 && sLink.Substring(0, 33) == "http://post.messages.yahoo.co.jp/") {
                        context.postUrl = sLink.ToString();
                    }

                    if (sLink.Length > 50 && sLink.Substring(0, 47) == "http://messages.yahoo.co.jp/bbs?.mm=FN&action=m") {
                        string[] de = { "mid=", "\">" };
                        string[] tmp = e.OuterHtml.Split(de, StringSplitOptions.None);
                        if (tmp.Length > 1) {
                            sComp = tmp[1];
                            int test = 0;
                            if (int.TryParse(sComp, out test)) {
                                if (iMaxTitleNo < test) {
                                    iMaxTitleNo = test;
                                }
                            }
                        }
                    }
                }
                context.maxTilteNo = iMaxTitleNo.ToString();
            }
            finally {
                if (isCheckLock) {
                    context.UnLock();
                }
            }
            return iMaxTitleNo;
        }
        /// <summary>
        ///  Yahoo掲示板のその他の情報を取得する
        ///  セットする値(context):  codeAndExchange, comapnyName
        ///  セットする値(yahoo):  &DATE, &CLOSE, &CHANGE 
        /// </summary>
        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("DIV")) {

                    if (itemCnt == 4) break;
                    switch (e.GetAttribute("className")) {
                        case "kabu_meigara":
                            context.title = e.InnerText;
                            if (e.GetElementsByTagName("A").Count > 0) {
                                context.comapnyName = e.GetElementsByTagName("A")[0].InnerText;
                                itemCnt++;
                            }
                            break;
                        case "kabu_date":
                            context.GetSkin().set("&DATE", e.InnerHtml);
                            itemCnt++;
                            break;
                        case "kabu_number_price":
                            context.GetSkin().set("&CLOSE", e.InnerHtml);
                            context.close = e.InnerText;
                            itemCnt++;
                            break;
                        case "kabu_number_change":
                            context.GetSkin().set("&CHANGE", e.InnerHtml);
                            context.change = e.InnerText;
                            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>
        /// 該当銘柄コードのTitle一覧の取得を行う
        /// 投稿タイトル一覧を取得して配列に格納する
        /// </summary>
        /// <param name="pageNo">ぺジー番号 0:最新 -1:前の40件 1:次の40件</param>
        public override void GetTitleLists(string longCode, int pageNo)
        {
            string url = "";
            int ret = 0;
            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:
                    if (!context.Lock()) { MessageBox.Show("銘柄コードは現在ロックされています\nしばらくお待ちください"); return ; }
                    try {
                        url = GetBaseUrl();
                        ret = GetTopicId(context.GetCode());
                    }
                    finally {
                        context.UnLock();
                    }
                    break;
            }

            ComConstants now = ndbControl.DlControl;

            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://messages.yahoo.co.jp/bbs?.mm=FN&action=l&board=1006758&sid=1006758&tid=a5bda5ka1bc&start=281236
                    // Page2: http://messages.yahoo.co.jp/bbs?.mm=FN&action=l&board=1006758&sid=1006758&tid=a5bda5ka1bc&start=281196
                    //  ※tidあり、tidを入れたら、startは必須？
                    //または、
                    // Page(最新): http://messages.yahoo.co.jp/bbs?.mm=FN&action=topic&board=1006758&sid=1006758

                    //Stopwatch sw = new Stopwatch();
                    //sw.Start();
                    if (!ndb.NavigateAndWait(url)) {
                        console.AppendText("（｡・-・）失敗ｼﾀﾖｳﾀﾞ...もう一回やって！" + Form1.csCrLf);
                    }
                    //sw.Stop();
                    //this.textBox2.AppendText("DL時間：" + sw.ElapsedMilliseconds + csCrLf);
                    console.AppendText("( ･∀･)ﾉ > げっと！　 " + context.GetCode() + Form1.csCrLf);
                    HtmlDocument doc = ndb.Document;
                    if (doc.Title.ToString().Equals("Yahoo!掲示板 - エラー")) {
                        console.AppendText("（｡・-・）ﾖｲﾖｲ...変な値が返ってるよ..." + Form1.csCrLf);
                        return ;
                    }

                    // テーブル内の文字列を構造体に格納する
                    // タイトル一覧はHTMLの四重にネストされたテーブル配下にある.
                    int tblCnt = 0;
                    int rowCnt = 0;
                    foreach (HtmlElement e in doc.GetElementsByTagName("TABLE")) {
                        if (e.InnerText != null && e.InnerText.IndexOf("投稿時間") != -1) {
                            tblCnt++;
                            if (tblCnt == 4) {
                                HtmlElementCollection rows = e.GetElementsByTagName("TR");
                                foreach (HtmlElement row in rows) {
                                    HtmlElementCollection cols = row.GetElementsByTagName("TD");
                                    int chkelm = 0;
                                    bool bChk = int.TryParse(cols[0].InnerText, out chkelm);
                                    if (cols.Count == 9 && bChk && chkelm > 1 ) {
                                        context.t[rowCnt].titleNo = chkelm.ToString();
                                        context.t[rowCnt].title = cols[1].InnerText;
                                        context.t[rowCnt].sender = cols[4].InnerText;
                                        context.t[rowCnt].emotion = cols[5].InnerText;
                                        context.t[rowCnt].sendTime = cols[8].InnerText;
                                        rowCnt++;
                                    }
                                }
                            }
                        }
                    }

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

                        if (e.InnerText == "前の40件") context.prevPage = e.GetAttribute("href");
                        if (e.InnerText == "次の40件") context.nextPage = e.GetAttribute("href");

                    }

                    // yahoo掲示板その他の情報の取得
                    if (context.comapnyName == "") {
                        GetOtherInfo(context.GetCode(), doc);
                    }
                }
                finally {
                    context.UnLock();
                    ndbControl.DlControl = now;
                }
            } else // GetTopicId() の戻り値 not 0 
            {
                console.AppendText("( ・益・)　ﾉ > ﾖｲﾖｲわかんねぇよ。" + Form1.csCrLf);
            }
            return ;
        }

        /// <summary>
        /// 引数のURLのメッセージコンテンツを取得する 
        /// URL例) http://messages.yahoo.co.jp/bbs?.mm=FN&action=m&board=1005214&tid=ffckdcee5a4bekbbr&sid=1005214&mid=10331
        /// </summary>
        /// <returns></returns>
        public override string GetContents(string mid)
        {
            string content = "";
            // 画像、ActiveXのダウンロードを抑止
            //WebBrowserController ctl = new WebBrowserController(this.webBrowser1);
            ComConstants now = ndbLocalControl.DlControl;
            ComConstants filter = ComConstants.DLCTL_NO_DLACTIVEXCTLS
                                | ComConstants.DLCTL_NO_JAVA
                                | ComConstants.DLCTL_NO_SCRIPTS
                                | ComConstants.DLCTL_NO_DLACTIVEXCTLS
                                | ComConstants.DLCTL_NO_RUNACTIVEXCTLS
                                & ~ComConstants.DLCTL_DLIMAGES;
            ndbLocalControl.DlControl = filter;
            NonDispBrowser ndbLocal = (NonDispBrowser)ndbLocalControl.GetBrowser();

            try {
                // メッセージ内容はhtmlの中から"class=s130"をキーとして取得する
                string pad = "";
                string url = GetMassageUrl(mid);
                console2.Text = url;

                //DL時間計測
                //Stopwatch watch = new Stopwatch();
                //watch.Start();
                if (!ndbLocal.NavigateAndWait(url)) {
                    console.AppendText("（｡・-・）失敗ｼﾀﾖｳﾀﾞ...もう一回やって！" + Form1.csCrLf);
                    return "Navigate 失敗";
                }
                HtmlDocument doc = ndbLocal.Document;
                if (doc.Title == "Yahoo!掲示板 - エラー") {
                    return doc.Title;
                }
                context.title = doc.Title;
                //watch.Stop();
                //console.AppendText("計測時間: " + watch.ElapsedMilliseconds + Form1.csCrLf);


                // コンテンツの取得方法１ (skin利用時はこれを採用)
                HtmlElementCollection all = doc.All;
                HtmlElementCollection ec = doc.GetElementsByTagName("TD");
                YahooSkin skin = context.GetSkin();
                skin.ContextToSkin(context);
                bool findflag = false;
                foreach (HtmlElement e in ec) {
                    switch (e.GetAttribute("className")) {
                        case "s130":
                            content = e.InnerHtml.Replace(Form1.csCrLf, "<BR>");
                            findflag = true;
                            /*
                            //skinファイルに内容を格納
                            skin.set("&MESSAGE", e.InnerHtml);
                            skin.set("&RESURL", GetReplyUrl(mid));
                            // titlelistからskin変数格納
                            foreach ( TitleLists item in context.t ) {
                                if (mid == item.titleNo) {
                                    skin.set("&NUMBER", item.titleNo);
                                    skin.set("&TITLE", item.title);
                                    skin.set("&NAME", item.sender);
                                    skin.set("&FEELINGS", item.emotion);
                                    skin.set("&DATE", item.sendTime);
                                    findflag = true;
                                    break;
                                }
                            }
                             * */
                            break;
                        default:
                            break;

                    }
                    if (findflag) break;
                }

                // コンテンツの取得方法２　早いが失敗する可能性あり
                /*  skin対応前はこれを使用する */
                /*
                string retHtml = "";
                if (doc.GetElementsByTagName("TABLE").Count >= 25) {
                    HtmlElement eRet = doc.GetElementsByTagName("TABLE")[25];
                    retHtml = eRet.OuterHtml;
                    eRet = null;
                    doc = null;
                } else retHtml = "contents get error!";
                return retHtml;
                 */

                /**
                 * 今はコメント
                 * 投稿者のメッセージ一覧用IURL取得
                ec = doc.GetElementsByTagName("A");
                foreach (HtmlElement e in ec) {
                    switch (e.GetAttribute("className")) {

                        case "findMessage":
                            //like this http://search.messages.yahoo.co.jp/search/?p=ayakai0116 
                            skin.set("&M_FINDMSG", e.GetAttribute("HREF"));
                            skin.set("&M_NICKNAME", e.GetAttribute("HREF").Replace("http://search.messages.yahoo.co.jp/search/?p=", ""));
                            break;
                        default:
                            break;

                    }
                }
                **/
            }
            catch (NullReferenceException e) {
                console.AppendText(e.ToString() + Form1.csCrLf);
                return "contents get error!";
            }
            finally {
                //ndbControl.DlControl = now;
                //ndbLocal.Dispose();
                //ndbLocal = null;
            }

            return content;
        }


        /// <summary>
        /// 引数のURLのメッセージコンテンツをYahooモバイルから取得する 
        /// 例) http://m.finance.yahoo.co.jp/stock/bbs?code=6255
        /// </summary>
        /// <param name="mid"></param>
        /// <returns></returns>
        private string GetContentsFromMobileSite(string mid)
        {
            NonDispBrowser ndb = (NonDispBrowser)ndbControl.GetBrowser();

            try {
                // メッセージ内容はhtmlの中から"class=s130"をキーとして取得する
                string url = "http://m.finance.yahoo.co.jp/stock/bbs?code=" + context.GetCode();
                // toolStripStatusLabel1.Text = url;
                ndb.NavigateAndWait(url);

                bool bThisMessage = false;

                HtmlDocument doc = ndb.Document;
                HtmlElementCollection all = doc.All;
                HtmlElementCollection articles = doc.GetElementsByTagName("article");
                HtmlElementCollection titles = doc.GetElementsByTagName("h3");
                HtmlElementCollection texts = doc.GetElementsByTagName("p");

                Console.WriteLine("message id: " + mid);

                for (int i = 0; i < all.Count; i++) {
                    if (all[i].GetAttribute("classname") == "title" && (all[i].InnerText.IndexOf(mid) != -1)) {
                        for (int j = 0; j < 10; j++) {
                            Console.WriteLine(all[i + j].InnerText);
                            if (all[i + j].GetAttribute("classname") == "text") {
                                return all[i + j].InnerText;
                            }
                        }
                    }
                }

                for (int i = 0; i < titles.Count; i++) {
                    if (titles[i].InnerText.IndexOf(mid) != -1) {
                        return articles[i].InnerHtml;
                    }
                }

                // 引数のmidのメッセージを探し出して戻す
                foreach (HtmlElement article in articles) {
                    //                foreach (HtmlElement e in article)
                    //                {
                    HtmlElement e = article;
                    if (e.GetAttribute("className") == "title") {
                        if (e.InnerText.IndexOf(mid) != -1) {
                            bThisMessage = true;
                        };
                    }
                    if (e.GetAttribute("className") == "text" && bThisMessage == true) {
                        if (e.InnerText.IndexOf(mid) != -1) {
                            return e.InnerHtml;
                        };
                    }
                    //                }
                }
            }
            finally {
            }
            return "contents get error!";
        }


        ///<summary>
        /// HTMLから投稿タイトル一覧を全部取得してファイルに保存する
        /// 最新titleIDからmaxRow分はTitleListsクラスに格納する
        ///</summary>
        public void SaveAllTitleList2(string code)
        {
            int maxTitleNo = 0;  // 取得済みのtitle


            if (code == "" || code == null) { return; }
            
            NonDispBrowser ndb = (NonDispBrowser)ndbControl.GetBrowser();
            bool bReadExitFlag = false; // キャッシュされた最新まで達したので読込み終了する

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

            if (File.Exists(Form1.csDatDir + code + ".dat")) {
                return;
                /*
                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 ; }
            context.Lock();
            try {

                int tid = GetTopicId(code);

                TitleLists data = new TitleLists();

                // 最新の一覧
                ndb.NavigateAndWait(GetBaseUrl());
                string path = Form1.csDatDir + code + ".dat";

                //if (File.Exists(path))
                //{
                //    SortUniqTitleList(path);
                //}
                StreamWriter sw = new StreamWriter(path, true);
                sw.WriteLine("0" + Form1.delimiter + context.tid + Form1.delimiter + context.GetCodeAndExchange() + Form1.delimiter + context.comapnyName);

                context.maxTilteNo = GetMaxTitleNo(ndb.Document, false).ToString();

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

                    console2.Text = ndb.Url.ToString();
                    HtmlDocument doc = ndb.Document;

                    context.prevPage = "";
                    foreach (HtmlElement e in doc.GetElementsByTagName("A")) {
                        if (e.InnerText == "前の40件") {
                            context.prevPage = e.GetAttribute("href");
                            break;
                        }
                    }
                        
                    // 前の40件リンクを辿ってyahoo掲示板をクロール
                    // タイトル一覧はHTMLの四重にネストされたテーブル配下にある.
                    int tblCnt = 0;
                    int flushCnt = 0;
                    foreach (HtmlElement e in doc.GetElementsByTagName("TABLE")) {
                        if (e.InnerText != null && e.InnerText.IndexOf("投稿時間") != -1) {
                            tblCnt++;
                            if (tblCnt == 4) {
                                HtmlElementCollection rows = e.GetElementsByTagName("TR");
                                foreach (HtmlElement row in rows) {
                                    HtmlElementCollection cols = row.GetElementsByTagName("TD");
                                    int chkelm = 0;
                                    bool bChk = false;
                                    if ( cols.Count > 0 )
                                        bChk = int.TryParse(cols[0].InnerText, out chkelm);
                                    if (cols.Count == 9 && bChk && chkelm > 1 && chkelm <= context.GetMaxTitleNo()) {
                                        data.titleNo = chkelm.ToString();
                                        data.title = cols[1].InnerText;
                                        data.sender = cols[4].InnerText;
                                        data.emotion = cols[5].InnerText;
                                        data.sendTime = cols[8].InnerText;
                                        data.content = GetContents(data.titleNo);
                                        data.WriteLine2(sw);
                                        flushCnt++;
                                        if (flushCnt % 100 == 0) {
                                            sw.Flush();
                                        }
                                        /*
                                        if (chkelm <= maxTitleNo) {
                                            bReadExitFlag = true;
                                            break;
                                        }
                                            * */
                                    }
                                }
                            }
                        }
                        if (bReadExitFlag) break;
                    }
                    if (bReadExitFlag) break;
                    console.AppendText(context.prevPage + Form1.csCrLf);

                    if (context.prevPage != "") {
                        ndb.NavigateAndWait(context.prevPage);
                    } else {
                        break;
                    }
                } // 読込みループ終了
                sw.Close();
                sw = null;
                Utils.SortUniqTitleList(path);
            }
            finally {
                context.UnLock();
            }
//            MessageBox.Show("ダウンロード完了！");
            return ;
        }


        ///<summary>
        /// HTMLから投稿タイトル一覧を全部取得してファイルに保存する
        /// 最新titleIDからmaxRow分はTitleListsクラスに格納する
        ///</summary>
        public override void SaveAllTitleList(string code)
        {
            int maxTitleNo = 0;  // 取得済みのtitle
            string path = "";

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

            NonDispBrowser ndb = (NonDispBrowser)ndbControl.GetBrowser();
            path = Form1.csDatDir + code + ".dat";

            if (File.Exists(Form1.csDatDir + code + ".dat")) {
                return;
            }

            context.Lock();
            try {

                // 最新の投稿
                ndb.NavigateAndWait(GetBaseUrl());
                context.maxTilteNo = GetMaxTitleNo(ndb.Document, false).ToString();

                // 最初のまとめ
                ndb.NavigateAndWait(GetMatomeUrl(context.maxTilteNo));

                // StreamWriterインスタンス　＆　最初の１行
                StreamWriter 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() / 5); i++) {

                    // 取得失敗の場合はあきらめて、次のページへ
                    console2.Text = ndb.Url.ToString();
                    HtmlDocument doc = ndb.Document;
                    if (doc.Title == "Yahoo!掲示板 - エラー") {
                        return;
                    }

                    context.prevPage = "";
                    foreach (HtmlElement e in doc.GetElementsByTagName("A")) {
                        if (e.InnerText == "前の5件") {
                            context.prevPage = e.GetAttribute("href");
                            break;
                        }
                    }

                    // 前の5件リンクを辿ってyahoo掲示板をクロール
                    int flushCnt = 0;


                    TitleLists data = new TitleLists();
                    HtmlElement elm5 = Utils.GetElementByClassName(doc, "s130", "TD", 5);
                    if (elm5 != null) {
                        HtmlElement parent5 = elm5.Parent.Parent.Parent.Parent.Parent.Parent;
                        HtmlElement title5 = parent5.GetElementsByTagName("TR")[0];
                        HtmlElement sender5 = Utils.GetElementByClassName(parent5, "nameId");
                        if (sender5 != null) {
                            data.sender = sender5.GetElementsByTagName("A")[0].InnerText.Trim();
                        }

                        HtmlElement emotion5 = Utils.GetEmotionElement(parent5);
                        if (emotion5 != null) {
                            data.emotion = emotion5.InnerText.Replace("投稿時の気持ち: ", "").Trim();
                        }
                        data.title = title5.GetElementsByTagName("TD")[1].InnerText.Trim();

                        string[] t5 = Utils.ParseTile(title5.GetElementsByTagName("TD")[2].InnerText);
                        data.sendTime = t5[0];
                        maxTitleNo = int.Parse(t5[1]);
                        data.titleNo = t5[2];
                        data.content = elm5.InnerHtml.Replace(Form1.csCrLf, "<BR>");
                        data.WriteLine2(sw);
                        emotion5 = null;
                        parent5 = null;
                        sender5 = null;
                        title5 = null;
                        elm5 = null;
                        flushCnt++;
                    }

                    data = new TitleLists();
                    HtmlElement elm4 = Utils.GetElementByClassName(doc, "s130", "TD", 4);
                    if (elm4 != null) {
                        HtmlElement parent4 = elm4.Parent.Parent.Parent.Parent.Parent.Parent;
                        HtmlElement title4 = parent4.GetElementsByTagName("TR")[0];
                        HtmlElement sender4 = Utils.GetElementByClassName(parent4, "nameId");
                        if (sender4 != null) {
                            data.sender = sender4.GetElementsByTagName("A")[0].InnerText.Trim();
                        }

                        HtmlElement emotion4 = Utils.GetEmotionElement(parent4);
                        if (emotion4 != null) {
                            data.emotion = emotion4.InnerText.Replace("投稿時の気持ち: ", "").Trim();
                        }
                        data.title = title4.GetElementsByTagName("TD")[1].InnerText.Trim();

                        string[] t4 = Utils.ParseTile(title4.GetElementsByTagName("TD")[2].InnerText);
                        data.sendTime = t4[0];
                        maxTitleNo = int.Parse(t4[1]);
                        data.titleNo = t4[2];
                        data.content = elm4.InnerHtml.Replace(Form1.csCrLf, "<BR>");
                        data.WriteLine2(sw);
                        emotion4 = null;
                        parent4 = null;
                        sender4 = null;
                        title4 = null;
                        elm4 = null;
                        flushCnt++;
                    }

                    data = new TitleLists();
                    HtmlElement elm3 = Utils.GetElementByClassName(doc, "s130", "TD", 3);
                    if (elm3 != null) {
                        HtmlElement parent3 = elm3.Parent.Parent.Parent.Parent.Parent.Parent;
                        HtmlElement title3 = parent3.GetElementsByTagName("TR")[0];
                        HtmlElement sender3 = Utils.GetElementByClassName(parent3, "nameId");
                        if (sender3 != null) {
                            data.sender = sender3.GetElementsByTagName("A")[0].InnerText.Trim();
                        }

                        HtmlElement emotion3 = Utils.GetEmotionElement(parent3);
                        if (emotion3 != null) {
                            data.emotion = emotion3.InnerText.Replace("投稿時の気持ち: ", "").Trim();
                        }
                        data.title = title3.GetElementsByTagName("TD")[1].InnerText;

                        string[] t3 = Utils.ParseTile(title3.GetElementsByTagName("TD")[2].InnerText);
                        data.sendTime = t3[0];
                        maxTitleNo = int.Parse(t3[1]);
                        data.titleNo = t3[2];
                        data.content = elm3.InnerHtml.Replace(Form1.csCrLf, "<BR>");
                        data.WriteLine2(sw);
                        parent3 = null;
                        sender3 = null;
                        emotion3 = null;
                        title3 = null;
                        elm3 = null;
                        flushCnt++;
                    }

                    data = new TitleLists();
                    HtmlElement elm2 = Utils.GetElementByClassName(doc, "s130", "TD", 2);
                    if (elm2 != null) {
                        HtmlElement parent2 = elm2.Parent.Parent.Parent.Parent.Parent.Parent;
                        HtmlElement title2 = parent2.GetElementsByTagName("TR")[0];
                        HtmlElement sender2 = Utils.GetElementByClassName(parent2, "nameId");
                        if (sender2 != null) {
                            data.sender = sender2.GetElementsByTagName("A")[0].InnerText.Trim();
                        }

                        HtmlElement emotion2 = Utils.GetEmotionElement(parent2);
                        if (emotion2 != null) {
                            data.emotion = emotion2.InnerText.Replace("投稿時の気持ち: ", "").Trim();
                        }
                        data.title = title2.GetElementsByTagName("TD")[1].InnerText.Trim();

                        string[] t2 = Utils.ParseTile(title2.GetElementsByTagName("TD")[2].InnerText);
                        data.sendTime = t2[0];
                        maxTitleNo = int.Parse(t2[1]);
                        data.titleNo = t2[2];
                        data.content = elm2.InnerHtml.Replace(Form1.csCrLf, "<BR>");
                        data.WriteLine2(sw);
                        emotion2 = null;
                        parent2 = null;
                        sender2 = null;
                        title2 = null;
                        elm2 = null;
                        flushCnt++;
                    }

                    data = new TitleLists();
                    HtmlElement elm1 = Utils.GetElementByClassName(doc, "s130", "TD", 1);
                    if (elm1 != null) {
                        HtmlElement parent1 = elm1.Parent.Parent.Parent.Parent.Parent.Parent;
                        HtmlElement title1 = parent1.GetElementsByTagName("TR")[0];
                        HtmlElement sender1 = Utils.GetElementByClassName(parent1, "nameId");
                        if (sender1 != null) {
                            data.sender = sender1.GetElementsByTagName("A")[0].InnerText.Trim();
                        }

                        HtmlElement emotion1 = Utils.GetEmotionElement(parent1);
                        if (emotion1 != null) {
                            data.emotion = emotion1.InnerText.Replace("投稿時の気持ち: ", "").Trim();
                        }
                        data.title = title1.GetElementsByTagName("TD")[1].InnerText.Trim();

                        string[] t1 = Utils.ParseTile(title1.GetElementsByTagName("TD")[2].InnerText);
                        data.sendTime = t1[0];
                        maxTitleNo = int.Parse(t1[1]);
                        data.titleNo = t1[2];
                        data.content = elm1.InnerHtml.Replace(Form1.csCrLf,"<BR>");
                        data.WriteLine2(sw);
                        parent1 = null;
                        emotion1 = null;
                        sender1 = null;
                        title1 = null;
                        elm1 = null;
                        flushCnt++;
                    }

                    
                    if (flushCnt % 100 == 0) {
                        sw.Flush();
                    }

                    console.AppendText(context.prevPage + Form1.csCrLf);
                    if (context.prevPage != "") {
                        ndb.NavigateAndWait(context.prevPage);
                    } else {
                        break;
                    }
                } // 読込みループ終了
                sw.Close();
                sw = null;
                Utils.SortUniqTitleList(path);
            }
            finally {
                context.UnLock();
            }
            //            MessageBox.Show("ダウンロード完了！");
            return;
        }

    
    
    }
}
