/// <summary>
        /// コメント受信イベントハンドラ
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="comment"></param>
        private void twcasChatClient_OnCommentReceiveEach(TwcasChatClient sender, CommentStruct comment)
        {
            // コメントの追加
            UiCommentData uiCommentData = new UiCommentData();

            uiCommentData.UserThumbUrl = comment.UserThumbUrl;
            uiCommentData.UserName     = comment.UserName;
            uiCommentData.CommentStr   = comment.Text;

            System.Diagnostics.Debug.WriteLine("UserThumbUrl " + uiCommentData.UserThumbUrl);
            System.Diagnostics.Debug.WriteLine("UserName " + uiCommentData.UserName);
            System.Diagnostics.Debug.WriteLine("CommentStr " + uiCommentData.CommentStr);

            ViewModel viewModel = this.DataContext as ViewModel;
            ObservableCollection <UiCommentData> uiCommentDataList = viewModel.UiCommentDataCollection;

            uiCommentDataList.Add(uiCommentData);

            // コメントログを記録
            writeLog(uiCommentData.UserName, uiCommentData.CommentStr);

            // 棒読みちゃんへ送信
            if (comment.IsBouyomiOn)
            {
                string sendText = comment.Text;
                string bcTitle  = twcasChatClient.BcTitle;
                if (bcTitle != "")
                {
                    StringBuilder sendTextSb = new StringBuilder(sendText);
                    sendTextSb.Replace("(" + bcTitle + ")", "");
                    sendText = sendTextSb.ToString();
                }
                bouyomiChan.Talk(sendText);
            }
        }
        /// <summary>
        /// コメントをGUIに登録する
        /// </summary>
        /// <param name="workCommentList"></param>
        private void setCmntToGui(IList <CommentStruct> workCommentList)
        {
            // 登録済みの最新コメントを取得
            CommentStruct prevComment = new CommentStruct();

            if (CommentList.Count > 0)
            {
                prevComment = CommentList[CommentList.Count - 1];
            }
            // 新しいコメントから順にチェック
            int iStPos = 0; // 未登録のコメントの開始位置

            for (int iComment = workCommentList.Count - 1; iComment >= 0; iComment--)
            {
                CommentStruct tagtComment = workCommentList[iComment];

                // 登録済みかチェック
                if (tagtComment.Id == prevComment.Id)
                {
                    iStPos = iComment + 1; // 登録済みのコメントの次のコメントが未登録の開始位置
                    System.Diagnostics.Debug.WriteLine("found stored comment.");
                    break;
                }
            }
            if (iStPos == workCommentList.Count)
            {
                // すべて登録済み
                return;
            }

            // 新規分だけ登録
            for (int iComment = iStPos; iComment < workCommentList.Count; iComment++)
            {
                CommentStruct tagtComment = workCommentList[iComment];

                // 新規のコメントの場合、リストに追加する
                CommentList.Add(tagtComment);
                System.Diagnostics.Debug.WriteLine("■{0} {1} {2}", tagtComment.UserName, tagtComment.Text, tagtComment.TimeStr);
                System.Diagnostics.Debug.WriteLine("■ThumbUrl " + tagtComment.UserThumbUrl);

                // 最大コメント数チェック
                if (CommentList.Count > MaxStoredCommentCnt)
                {
                    CommentList.RemoveAt(0);
                    System.Diagnostics.Debug.Assert(CommentList.Count == MaxStoredCommentCnt);
                }

                if (OnCommentReceiveEach != null)
                {
                    OnCommentReceiveEach(this, tagtComment);
                }
            }

            if (OnCommentReceiveDone != null)
            {
                OnCommentReceiveDone(this);
            }
        }
        /// <summary>
        /// コメント一覧を取得する
        /// </summary>
        /// <returns></returns>
        private IList <CommentStruct> getBcCmntListAll()
        {
            IList <CommentStruct> workCommentList = new List <CommentStruct>();

            if (!IsBcMovieValid())
            {
                return(workCommentList);
            }

            // コメント一覧の取得
            // http://ja.twitcasting.tv/アカウント/userajax.php?c=listall&m=動画ID&k=0&f=0&n=10
            // [{"id":,"class":,"html":,"date":,"dur":,"uid":,"screen":,"statusid":"","lat":0,"lng":0,"show":true,"yomi":""},
            //     ...
            // ]
            string url     = TwcastUrl + "/" + ChannelName + "/userajax.php?c=listall&m=" + MovieId + "&k=0&f=0&n=10";
            string recvStr = doHttpRequest(url);

            //System.Diagnostics.Debug.WriteLine("recvStr:[" + recvStr + "]");
            if (recvStr == null)
            {
                // 接続エラー
                return(workCommentList);
            }
            try
            {
                // JSON形式からコメント応答オブジェクトに変換
                IList <BcCmntResponse> cmnts = JsonConvert.DeserializeObject <List <BcCmntResponse> >(recvStr);

                // コメント応答リストからコメントを取り出す
                workCommentList = parseBcCmntResponse(cmnts);

                // 直近の取得開始コメントIDをセットする
                if (workCommentList.Count > 0)
                {
                    lastBcCmntId = workCommentList[workCommentList.Count - 1].Id;
                }
                else
                {
                    lastBcCmntId = 0;
                }

                // 一覧取得の場合は棒読みちゃんに送信しないようにする
                for (int i = 0; i < workCommentList.Count; i++)
                {
                    CommentStruct tmpComment = workCommentList[i];
                    tmpComment.IsBouyomiOn = false;
                    workCommentList[i]     = tmpComment;
                }
            }
            catch (Exception exception)
            {
                System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace);
                System.Diagnostics.Debug.WriteLine("[Error]getBcCmntListAll: recvStr: " + recvStr);
                return(workCommentList);
            }
            return(workCommentList);
        }
        /// <summary>
        /// コメント応答のパース
        /// </summary>
        /// <param name="cmnts"></param>
        private IList <CommentStruct> parseBcCmntResponse(IList <BcCmntResponse> cmnts)
        {
            IList <CommentStruct> workCommentList = new List <CommentStruct>();

            if (cmnts == null)
            {
                return(workCommentList);
            }

            // コメント応答を取得
            //  日付順
            foreach (BcCmntResponse bcCmntResponse in cmnts)
            {
                //uint id = bcCmntResponse.id;
                ulong  id      = bcCmntResponse.id;
                string htmlStr = bcCmntResponse.html;
                string dateStr = bcCmntResponse.date;
                System.Diagnostics.Debug.WriteLine("htmlStr:" + htmlStr);

                HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
                doc.LoadHtml(htmlStr);
                // 最初のimgタグ:プロフィール画像
                HtmlNode profileImgTdTag = doc.DocumentNode.SelectSingleNode(@"//td[@class=""img""]");
                if (profileImgTdTag == null)
                {
                    System.Diagnostics.Debug.WriteLine("profileImgTdTag is null. id: [" + id + "] html: [" + htmlStr + "]");
                    continue;
                }
                HtmlNode profImgTag = profileImgTdTag.SelectSingleNode(@"//img[1]");
                if (profImgTag == null)
                {
                    System.Diagnostics.Debug.WriteLine("profImgTag is null. id: [" + id + "] html: [" + htmlStr + "]");
                    continue;
                }
                string profImgSrc = profImgTag.GetAttributeValue("src", "");
                // ユーザーノード
                HtmlNode userSpanTag = doc.DocumentNode.SelectSingleNode(@"//span[@class=""user""]");
                if (userSpanTag == null)
                {
                    System.Diagnostics.Debug.WriteLine("userSpanTag is null. id: [" + id + "] html: [" + htmlStr + "]");
                    continue;
                }
                if (profImgSrc.IndexOf("//") == 0)
                {
                    profImgSrc = "https:" + profImgSrc;
                }
                string userName = userSpanTag.InnerText;
                // コメントノード
                HtmlNode cmntTdTag = doc.DocumentNode.SelectSingleNode(@"//td[@class=""comment""]");
                if (cmntTdTag == null)
                {
                    System.Diagnostics.Debug.WriteLine("cmntTdTag is null. id: [" + id + "] html: [" + htmlStr + "]");
                    continue;
                }
                // コメントテキストノード
                string   cmntStr    = "";
                HtmlNode cmntTxtTag = cmntTdTag.SelectSingleNode(@"//span[@class=""comment-text""]");
                if (cmntTxtTag == null)
                {
                    System.Diagnostics.Debug.WriteLine("cmntTxtTag is null. id: [" + id + "] html: [" + htmlStr + "]");
                    continue;
                }
                cmntStr += cmntTxtTag.InnerText;

                //cmntStr = cmntStr.Replace("<br>", System.Environment.NewLine);
                HtmlNode subTitleNode = cmntTdTag.SelectSingleNode(@"//span[@class=""smallsubtitle""]");
                if (subTitleNode != null)
                {
                    cmntStr += subTitleNode.InnerText;
                }
                cmntStr = System.Web.HttpUtility.HtmlDecode(cmntStr);

                CommentStruct workComment = new CommentStruct();
                workComment.Id           = id;
                workComment.UserThumbUrl = profImgSrc;
                workComment.UserName     = userName;
                workComment.TimeStr      = dateStr;
                workComment.Text         = cmntStr;
                workComment.IsBouyomiOn  = true; // 初期値
                //System.Diagnostics.Debug.WriteLine("Id " + workComment.Id);
                //System.Diagnostics.Debug.WriteLine("UserThumbUrl " + workComment.UserThumbUrl);
                //System.Diagnostics.Debug.WriteLine("UserName " + workComment.UserName);
                //System.Diagnostics.Debug.WriteLine("TimeStr " + workComment.TimeStr);
                //System.Diagnostics.Debug.WriteLine("Text " + workComment.Text);
                workCommentList.Add(workComment);
            }
            return(workCommentList);
        }