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

namespace カブラウザもどき
{
    /// <summary>
    /// YahooTextreamに対応した掲示板クラス。
    /// 2012年11月以降運用開始
    /// </summary>
    public class GetYahooTextream : GetYahoo
    {

        bool isLogin = false;
        /// <summary>
        /// コンストラクタ
        /// </summary>
        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 GetPostUrl()
        {
            if (context.GetCode() == "") return "";
            return this.GetBaseUrl() + "#commentEntryForm";
        }

        public override string GetReplyUrl(string mid)
        {
            if (context.GetCode() == "") return "";
            return "http://textream.yahoo.co.jp/message/" + GetBoard(context.GetCode()) + "/" + GetTid(context.GetCode()) + "?comment=" + mid + "#commentList";
        }
        public override string GetThreadUrl(string mid)
        {
            //textreamではスレッド表示は廃止されたため、空文字を返す
            return "";
        }
        public override string GetBaseUrl()
        {
            if (context.GetCode() == "") return "";
            return "http://textream.yahoo.co.jp/message/" + GetBoard(context.GetCode()) + "/" + GetTid(context.GetCode());
        }
        public override string GetMassageUrl(string mid)
        {
            if (context.GetCode() == "") return "";
            return "http://textream.yahoo.co.jp/message/" + GetBoard(context.GetCode()) + "/" + GetTid(context.GetCode())+ "?comment=" + mid;
        }
        public string GetPostedSelf()
        {
            return "http://textream.yahoo.co.jp/personal/history/comment";
        }
        public override string GetDailyRankingUrl()
        {
            if (context.GetCode() == "") return "";
            return "http://textream.yahoo.co.jp/ranking/finance";
        }
        public override string GetWeeklyRankingUrl()
        {
            if (context.GetCode() == "") return "";
            return "http://textream.yahoo.co.jp/ranking/finance";
        }
        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 "";
        }
        public override string GetLoginUrl()
        {
            return "https://login.yahoo.co.jp/config/login" ;
        }
        

        /// <summary>
        ///　無条件にtrueを返す
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        public override bool IsValidYahooCode(string code)
        {
            return isValidYahooCode;
        }

        /// <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_USER", thisTitle.user);
                
            }
            //ニックネームはひとまず置いておく
            //                            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;

            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 {
                ComConstants now = ndbControl.DlControl;
                NonDispBrowser ndb = (NonDispBrowser)ndbControl.GetBrowser();
                ComConstants filter = ComConstants.DLCTL_NO_JAVA
                                    | ComConstants.DLCTL_NO_SCRIPTS
                                    | ComConstants.DLCTL_NO_DLACTIVEXCTLS
                                    | ComConstants.DLCTL_NO_RUNACTIVEXCTLS
                                    | ComConstants.DLCTL_DLIMAGES;
                ndbControl.DlControl = filter;
                //int chk = GetTid(code);

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

                // 銘柄情報
                sw.WriteLine("0" + Form1.delimiter + GetTid(context.GetCode()) + 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;

                }

                sw.Close();
                sw = null;
                ndbControl.DlControl = now;
                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 string GetTid(string code)
        {
            string ret = "-1";
            if (edinetlist.ContainsKey(code)) {
                ret = ((string)edinetlist[code]).Split(',')[3];
            } else {
                ret = code;
            }
            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 string GetSid(string code)
        {
            string ret = "-1";
            if (edinetlist.ContainsKey(code)) {
                ret = ((string)edinetlist[code]).Split(',')[2];
            } else {
                ret  =  "100" + code;
            }
            return ret;
        }
        public override string GetBoard(string code)
        {
            string ret = "-1";
            if (edinetlist.ContainsKey(code)) {
                ret = ((string)edinetlist[code]).Split(',')[1];
            } else {
                ret = "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();
                    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);
                        this.isValidYahooCode = false;
                        return ;
                    }
                    //sw.Stop();
                    //this.textBox2.AppendText("DL時間2：" + sw.ElapsedMilliseconds + csCrLf);
                    HtmlDocument doc = ndb.Document;
                    if (!IsValidUrl(doc)) {
                        console.AppendText("( ｡・-・) 失敗ｼﾀﾖｳﾀﾞ...もう一回やって！" + Form1.csCrLf);
                        this.isValidYahooCode = false;
                        return;
                    } else {
                        console.AppendText("( *´∀｀) ｱﾘｶﾞﾄｳ ぼくらのTextream! " + doc.Title.ToString() + Form1.csCrLf);
                    }
                    SetTitleListsFromHtml(doc);
                    this.isValidYahooCode = true;
                }
                finally {
                    context.UnLock();
                    ndbControl.DlControl = now;
                }
            } else // GetTid() の戻り値 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;

            HtmlElement t1 = null;
            HtmlElement t2 = null;
            HtmlElement t3 = null;
            HtmlElement t4 = null;
            HtmlElement t5 = null;
            HtmlElement t6 = null;

            
            // title no :  .commentBox > .commentTxt cf > input type=hidden name=commentInfo
            // title no :  (li).commentBox > (div).commentTxt cf > (div).ttlArea cf > (div)commentHeaderInfo > (dl).ttlInfo cf > (span).commentNumber 
            // title :  (li).commentBox > (div).commentTxt cf > (div).ttlArea cf > (div)commentHeaderInfo > (dl).ttlInfo cf > (h2).commentTitleArea > (a).commentTitle
            // sender : (li).commentBox > (div).commentTxt cf > (div).ttlArea cf > (div)commentHeaderInfo > (dl).ttlInfo cf > .userNameArea > .userName
            // user   : (li).commentBox > (div).commentTxt cf > (div).ttlArea cf > (div)commentHeaderInfo > (dl).ttlInfo cf > .userNameArea > a href
            // emotion :  (li).commentBox > (div).commentTxt cf > (div).ttlArea cf > (div)commentHeaderInfo > (dl).ttlInfo cf > .labelEmotion
            // sendTime :  (li).commentBox > (div).commentTxt cf > (div).ttlArea cf > (div)commentHeaderInfo > (dl).ttlInfo cf > (div).ttlInfoDateNum > (p)[0]
            // content :  (li).commentBox > (div).commentTxt cf > (div).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") {
                    t1 = e.Parent.Parent.Parent.Parent.Parent.Parent.Parent;
                    t2 = e.Parent.Parent.Parent.Parent.Parent.Parent;
                    t3 = e.Parent.Parent.Parent.Parent.Parent;
                    t4 = e.Parent.Parent.Parent.Parent;
                    t5 = e.Parent.Parent.Parent;
                    t6 = e.Parent.Parent;

                    // 投稿時間
                    elm = Utils.GetElementByClassName(t5, "ttlInfoDateNum", "div");
                    if (elm != null) context.t[rowCnt].sendTime = elm.GetElementsByTagName("p")[0].InnerText;

                    // タイトルNo
                    elm = Utils.GetElementByClassName(t6, "commentNumber");
                    if ( elm != null ) context.t[rowCnt].titleNo = elm.InnerText.Replace("No.","");

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

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

                    // 投稿者
                    elm = Utils.GetElementByClassName(t6, "userName");
                    if (elm != null) context.t[rowCnt].sender = elm.InnerText;
                    //if (elm != null) {
                    //    elm2 = 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;
                            }
                        }
                    }
                     * */

                    // 投稿内容
                    elm = Utils.GetElementByClassName(t3, "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";
                    if (t3 != null) {
                        // ユーザーアイコン
                        elms2 = t3.GetElementsByTagName("img");
                        if (elms2.Count > 0) {
                            elm2 = elms2[0];
                            if (elm2 != null) {
                                context.t[rowCnt].userIcon = elm2.GetAttribute("src");
                            }
                        }
                        // ユーザーID？
                        elms2 = t3.GetElementsByTagName("a");
                        if (elms2.Count > 0) {
                            elm2 = elms2[2];
                            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 (context.t[0].titleNo != null && context.t[0].titleNo != "" &&
                    context.maxTilteNo != null && context.maxTilteNo != "") {
                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 (!IsValidUrl(doc)) {
                console.AppendText("( ｡・-・) ﾖｲﾖｲ...変な値が返ってるよ..." + Form1.csCrLf);
                this.isValidYahooCode = false;
                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;
                                this.isValidYahooCode = true;
                                break;

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


        public override bool IsValidUrl(HtmlDocument doc)
        {
            bool ret = true;
            if (doc.Title.ToString().Equals("エラー - textream")) {
                this.isValidYahooCode = false;
                ret=false;
            }
            return ret;
        }
        public override void AutoLogin(DispBrowser browser)
        {
            //if (isLogin) return; 

            StringBuilder sb = new StringBuilder(1024);
            if (userId == "" && password == "") {
                IniFileHandler.GetPrivateProfileString("YahooID", "UserId", "", sb, (uint)sb.Capacity, Form1.csIniFile);
                userId = sb.ToString() ;
                IniFileHandler.GetPrivateProfileString("YahooID", "Password", "", sb, (uint)sb.Capacity, Form1.csIniFile);
                password = sb.ToString() ;
                if ( userId == "" && password == "" ) { 
                    return ;
                }
            }

            // 最新の一覧
            browser.NavigateAndWait(this.GetLoginUrl());
            browser.Visible = false;
            HtmlDocument doc1 = browser.Document;

            if (doc1.GetElementById("login") != null &&
                doc1.GetElementById("login").InnerText == null && 
                doc1.GetElementById("passwd") != null &&
                doc1.GetElementById("passwd").InnerText == null) {

                doc1.GetElementById("login").SetAttribute("value", userId);
                doc1.GetElementById("passwd").SetAttribute("value", password);

                System.Threading.Thread.Sleep(1000);

                doc1.Forms[0].InvokeMember("submit");
                System.Threading.Thread.Sleep(1000);
                isLogin = true;
            }

            return;
        }
    }
}
