using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.Text.RegularExpressions;
using System.Diagnostics;

namespace Aqua877.WinApp.IronLivetube
{
	public partial class MainWindow : Form
	{
		private LivetubeCommentReader LivetubeComments;
		private LivetubeInformation LivetubeLiveInfo;
		private TextReaderServices TextReader;
		private FilteringHelper FilterService;
		private CommandHelper CommandService;
		private MainWindowListViewSorter SortHelper;
		private SendersWiki SendersWikiCollector;

		private bool IsShowingFindWindow = false;
		private FindConditionsData FindConditions;
		private List<int> FindResult = new List<int>();
		private int CurrentShowingFindResultIndex = -1;

		public MainWindow()
		{
			this.SortHelper = new MainWindowListViewSorter();
			this.SendersWikiCollector = new SendersWiki();

			this.InitializeComponent();

			//イベント登録
			this.LivetubeComments = new LivetubeCommentReader();
			this.LivetubeComments.OnLoaded += this.OnLoaded;
			this.LivetubeComments.OnCaughtComment += this.OnCaughtComment;
			this.LivetubeComments.OnStatusTextChanged += this.OnStatusTextChanged;
			this.LivetubeComments.OnPostCommentFinished += this.OnPostCommentFinished;
			this.LivetubeComments.OnBanCommentFinished += this.OnBanCommentFinished;
			this.LivetubeComments.OnUnBanCommentFinished += this.OnUnBanCommentFinished;
			this.LivetubeComments.OnBannedCommentsListRefreshed += this.OnBannedCommentsListFinished;
			this.LivetubeComments.OnGetHostFinished += this.OnGetHostFinished;

			this.LivetubeLiveInfo = new LivetubeInformation();
			this.LivetubeLiveInfo.OnInformationRefreshed += this.OnInformationRefreshed;
			this.LivetubeLiveInfo.OnLiveEnded += this.OnLiveEnded;
			this.LivetubeComments.LiveInfo = this.LivetubeLiveInfo;

			//ヘルパークラスの初期化
			this.TextReader = new TextReaderServices();
			this.FilterService = new FilteringHelper();
#warning	//this.FilterService.OnMatchedFilteringCondition +=
			this.CommandService = new CommandHelper();
#warning	//this.CommandService.OnCommandExecuted += 

			//ソート設定
			this.LivetubeCommentsList.ListViewItemSorter = this.SortHelper;

			//設定の反映
			this.TopMost = GlobalValues.Setting.IsShowWindowMostTop;
			this.LivetubeCommentsList.GridLines = GlobalValues.Setting.IsShowGridLines;
			this.UseCommandsMenuItem.Checked = GlobalValues.Setting.IsEnableCommand;
			this.UseReadingMenuItem.Checked = GlobalValues.Setting.IsEnableReading;
			this.UseSoundEffectMenuItem.Checked = GlobalValues.Setting.IsEnableSoundEffect;
			this.UseFilteringMenuItem.Checked = GlobalValues.Setting.IsEnableFiltering;

			if (!string.IsNullOrWhiteSpace(GlobalValues.Setting.LivetubeUserID))
			{
				this.NameTextBox.Text = GlobalValues.Setting.LivetubeUserID;
				this.NameTextBox.Font = new Font("メイリオ", 9F, FontStyle.Bold, GraphicsUnit.Point, 128);
				this.NameTextBox.ForeColor = Color.Green;
			}
			else
			{
				this.NameTextBox.Text = "";
				this.NameTextBox.Font = new Font("メイリオ", 9F, FontStyle.Regular, GraphicsUnit.Point, 128);
				this.NameTextBox.ForeColor = SystemColors.WindowText;
			}
			this.SetProcessingText("初期化完了");
		}

		#region イベントハンドラ
		#region ファイルメニュー
		//設定ウィンドウを開く
		private void SettingsMenuItem_Click(object sender, EventArgs e)
		{
			using (var settingsWindow = new SettingsWindow(this.LivetubeComments))
			{
				this.TopMost = false;
				settingsWindow.ShowDialog();
			}

			//設定の反映等
			this.TopMost = GlobalValues.Setting.IsShowWindowMostTop;
			this.LivetubeCommentsList.GridLines = GlobalValues.Setting.IsShowGridLines;
			this.UseCommandsMenuItem.Checked = GlobalValues.Setting.IsEnableCommand;
			this.UseSoundEffectMenuItem.Checked = GlobalValues.Setting.IsEnableSoundEffect;
			this.UseReadingMenuItem.Checked = GlobalValues.Setting.IsEnableReading;
			this.UseFilteringMenuItem.Checked = GlobalValues.Setting.IsEnableFiltering;

			if (GlobalValues.Setting.CredentialData.Length > 0)
			{
				this.NameTextBox.Text = GlobalValues.Setting.LivetubeUserID;
				this.NameTextBox.ForeColor = Color.Green;
				this.NameTextBox.Font = new Font("メイリオ", 9F, FontStyle.Bold, GraphicsUnit.Point, 128);
			}
			else
			{
				this.NameTextBox.ForeColor = SystemColors.WindowText;
				this.NameTextBox.Font = new Font("メイリオ", 9F, FontStyle.Regular, GraphicsUnit.Point, 128);
				this.NameTextBox.ReadOnly = false;
			}

			if (GlobalValues.Setting.IsEnableReading && this.LivetubeComments.IsReading)
			{
				this.StartReadingMenuItem.Enabled = true;
				this.StopReadingMenuItem.Enabled = false;
				this.RestartReadingMenuItem.Enabled = false;
				this.SuspendReadingMenuItem.Enabled = false;
				this.TextReader.Start();
			}
			else
			{
				this.StartReadingMenuItem.Enabled = false;
				this.StopReadingMenuItem.Enabled = false;
				this.RestartReadingMenuItem.Enabled = false;
				this.SuspendReadingMenuItem.Enabled = false;
				if (this.TextReader.IsEnable)
				{
					this.TextReader.Stop();
				}
			}

			//全件表示の切り替え
			if(this.LivetubeComments.IsReading)
			{
				if (!GlobalValues.Setting.IsShowAllComments)
				{
					//全件表示オフ時には過分を削除
					while (this.LivetubeCommentsList.Items.Count > GlobalValues.Setting.ShowCommentCount)
					{
						if (this.SortHelper.Order == SortOrder.Ascending)
						{
							this.LivetubeCommentsList.Items.RemoveAt(0);
						}
						else
						{
							int lastOfIndex = this.LivetubeCommentsList.Items.Count - 1;
							this.LivetubeCommentsList.Items.RemoveAt(lastOfIndex);
						}
					}
				}
				else
				{
					//全件表示オン時には不足分を追加
					this.LivetubeCommentsList.BeginUpdate();
					this.LivetubeCommentsList.ListViewItemSorter = null;

					int shortage = this.LivetubeComments.CommentContainer.Count - this.LivetubeCommentsList.Items.Count;
					if (shortage > 0)
					{
						this.LivetubeComments.CommentContainer
							.TakeLast(shortage)
							.ToObservable().Let(
							xs =>
							{
								xs.Where(c => c.Name == "")//名無しコメント
								.Select(d => new ListViewItem(new[]
								{
									new ListViewItem.ListViewSubItem { Text = d.Number.ToString() },
									new ListViewItem.ListViewSubItem { Text = "" },
									new ListViewItem.ListViewSubItem { Text = d.Text },
									new ListViewItem.ListViewSubItem { Text = "" },
									new ListViewItem.ListViewSubItem { Text = d.PostedDate.ToString("M/d H:mm:ss") },
									new ListViewItem.ListViewSubItem { Text = d.ID, Font = new Font("メイリオ", 9F, FontStyle.Italic, GraphicsUnit.Point, 128) },
									new ListViewItem.ListViewSubItem { Text = "" }
								}, 0) { UseItemStyleForSubItems = false })
											.Merge(
												xs.Where(c => c.Name != "" && !c.ContributorCanBroadcasting)//黒コテ
												.Select(d => new ListViewItem(new[]
									{
										new ListViewItem.ListViewSubItem { Text = d.Number.ToString() },
										new ListViewItem.ListViewSubItem { Text = "" },
										new ListViewItem.ListViewSubItem { Text = d.Text },
										new ListViewItem.ListViewSubItem { Text = d.Name, Font = new Font("メイリオ", 9F, FontStyle.Bold, GraphicsUnit.Point, 128) },
										new ListViewItem.ListViewSubItem { Text = d.PostedDate.ToString("M/d H:mm:ss") },
										new ListViewItem.ListViewSubItem { Text = d.ID, Font = new Font("メイリオ", 9F, FontStyle.Italic, GraphicsUnit.Point, 128) },
										new ListViewItem.ListViewSubItem { Text = "" }
									}, 0) { UseItemStyleForSubItems = false })
												.Merge(
													xs.Where(c => c.Name != "" && c.ContributorCanBroadcasting)//緑コテ
													.Select(d => new ListViewItem(new[]
										{
											new ListViewItem.ListViewSubItem { Text = d.Number.ToString() },
											new ListViewItem.ListViewSubItem { Text = "" },
											new ListViewItem.ListViewSubItem { Text = d.Text },
											new ListViewItem.ListViewSubItem { Text = d.Name, Font = new Font("メイリオ", 9F, FontStyle.Bold, GraphicsUnit.Point, 128), ForeColor = Color.Green },
											new ListViewItem.ListViewSubItem { Text = d.PostedDate.ToString("M/d H:mm:ss") },
											new ListViewItem.ListViewSubItem { Text = d.ID, Font = new Font("メイリオ", 9F, FontStyle.Italic, GraphicsUnit.Point, 128) },
											new ListViewItem.ListViewSubItem { Text = "" }
										}, 0) { UseItemStyleForSubItems = false })
									)
								).Subscribe(
									//すべて追加
									d => this.LivetubeCommentsList.Items.Add(d)
								);
								return xs;
							}
						);
					}
				}
				this.LivetubeCommentsList.ListViewItemSorter = this.SortHelper;
				this.LivetubeCommentsList.Sort();
				this.LivetubeCommentsList.EndUpdate();
			}
		}

		//配信をURLから開く
		private void OpenLiveFromURLMenu_Click(object sender, EventArgs e)
		{
			DialogResult result;
			var resultUrl = "";

			using (var openLive = new OpenLiveFromURLWindow())
			{
				this.TopMost = false;
				result = openLive.ShowDialog();

				if (GlobalValues.Setting.IsShowWindowMostTop)
				{
					this.TopMost = true;
				}

				resultUrl = openLive.Tag as string;
			}

			if (result == DialogResult.OK)
			{
				this.OpenLiveFromURLMenu.Enabled = false;
				this.OpenLiveFromStreamIDMenuItem.Enabled = false;
				this.OpenLiveFromLiveListMenuItem.Enabled = false;

				this.LivetubeComments.LoadAsync(new Uri(resultUrl));
				this.LivetubeLiveInfo.LoadAsync(new Uri(resultUrl));
			}
		}

		//配信をStreamIDから開く
		private void OpenLiveFromStreamIDMenuItem_Click(object sender, EventArgs e)
		{
			var result = DialogResult.None;
			var resultStreamID = "";

			using (var openLive = new OpenLiveFromStreamIDWindow())
			{
				this.TopMost = false;
				result = openLive.ShowDialog();

				if (GlobalValues.Setting.IsShowWindowMostTop)
				{
					this.TopMost = true;
				}
				resultStreamID = openLive.Tag as string;
			}

			if (result == DialogResult.OK)
			{
				this.OpenLiveFromURLMenu.Enabled = false;
				this.OpenLiveFromStreamIDMenuItem.Enabled = false;
				this.OpenLiveFromLiveListMenuItem.Enabled = false;

				this.LivetubeComments.LoadAsync(resultStreamID);
			}
		}

		//配信を閉じる
		private void CloseLiveMenuItem_Click(object sender, EventArgs e)
		{
			this.LivetubeComments.StopLoad();
			this.LivetubeLiveInfo.StopLoad();
			this.TextReader.Stop();

			this.Text = "IronLivetube";
			this.OpenLiveFromURLMenu.Enabled = true;
			this.OpenLiveFromStreamIDMenuItem.Enabled = true;
			this.OpenLiveFromLiveListMenuItem.Enabled = true;
			this.CloseLiveMenuItem.Enabled = false;
			this.PlayLiveMenuItem.Enabled = false;
			this.CloseLiveMenuItem.Enabled = true;
			this.PlayLiveMenuItem.Enabled = true;
			this.splitContainer1.Panel2.Enabled = false;
			this.CopyCommentMenuItem.Enabled = false;
			this.CopyCommentContextMenuItem.Enabled = false;
			this.CopyCommentTextMenuItem.Enabled = false;
			this.CopyCommentTextContextMenuItem.Enabled = false;
			this.CopyCommentURLMenuItem.Enabled = false;
			this.CopyCommentURLContextMenuItem.Enabled = false;
			this.FindMenuItem.Enabled = false;
			this.FindNextMenuitem.Enabled = false;
			this.FindPreviousMenuItem.Enabled = false;
			this.MarkCommentAsNGMenuItem.Enabled = false;
			this.MarkCommentAsNGContextMenuItem.Enabled = false;
			this.MarkCommentAsNotNGMenuItem.Enabled = false;
			this.MarkCommentAsNotNGContextMenuItem.Enabled = false;
			this.ShowHostMenuItem.Enabled = false;
			this.ShowHostContextMenuItem.Enabled = false;
			this.LiveAuthorMenuItem.Enabled = false;
			this.LiveAuthorContextMenuItem.Enabled = false;
			this.SelectAllMenuItem.Enabled = false;
			this.SelectAllContextMenuItem.Enabled = false;
			this.RefreshConnectionMenuItem.Enabled = false;
			this.RefreshConnectionContextMenuItem.Enabled = false;
			this.LivetubeCommentsList.Items.Clear();
			this.LiveStatusText.Text = "[視/見]?/? [流速(Livetube)]?コメ/h [流速(したらば)]?コメ/h";
			this.StartReadingMenuItem.Enabled = false;
			this.StopReadingMenuItem.Enabled = false;
			this.RestartReadingMenuItem.Enabled = false;
			this.SuspendReadingMenuItem.Enabled = false;
			this.TextReader.Stop();
		}

		//配信を再生
		private void PlayLiveMenuItem_Click(object sender, EventArgs e)
		{

		}

		//プログラムを終了
		private void ExitApplicationMenuItem_Click(object sender, EventArgs e)
		{
			this.LivetubeComments.StopLoad();
			Application.Exit();
		}
		#endregion

		#region 編集メニュー
		//コメント全体をコピー
		private void CopyCommentMenuItem_Click(object sender, EventArgs e)
		{
			string textToCopy = "";

			foreach (var comment in this.LivetubeCommentsList.SelectedItems.Cast<ListViewItem>())
			{
				textToCopy += String.Format("{0} : {1}{2} {3}\n{4}\n----------\n",
					comment.SubItems[0].Text,
					comment.SubItems[3].Text, ((comment.SubItems[5].Text != "") ? "(" + comment.SubItems[5].Text + ")" : ""),
					comment.SubItems[4].Text, comment.SubItems[2].Text
				);
			}
			textToCopy = textToCopy.TrimEnd('\n');
			textToCopy = textToCopy.TrimEnd('-');
			textToCopy = textToCopy.TrimEnd('\n');

			Clipboard.SetDataObject(textToCopy, true);
		}

		//コメント本文のみをコピー
		private void CopyCommentTextMenuItem_Click(object sender, EventArgs e)
		{
			string textToCopy = "";

			foreach (var comment in this.LivetubeCommentsList.SelectedItems.Cast<ListViewItem>())
			{
				textToCopy += comment.SubItems[2].Text + "\n----------\n";
			}
			textToCopy = textToCopy.TrimEnd('\n');
			textToCopy = textToCopy.TrimEnd('-');
			textToCopy = textToCopy.TrimEnd('\n');

			Clipboard.SetDataObject(textToCopy, true);
		}

		//コメントに含まれるURLをコピー
		private void CopyCommentURLMenuItem_Click(object sender, EventArgs e)
		{
			string textToCopy = "";

			foreach (var comment in this.LivetubeCommentsList.SelectedItems.Cast<ListViewItem>())
			{
				foreach (var url in Regex.Matches(comment.SubItems[2].Text, @"^s?https?://[-_.!~*'()a-zA-Z0-9;/?:@&=+$,%#]+$").Cast<Match>().Select(m => m.Value))
				{
					textToCopy += url + "\n----------\n";
				}
			}
			textToCopy = textToCopy.TrimEnd('\n');
			textToCopy = textToCopy.TrimEnd('-');
			textToCopy = textToCopy.TrimEnd('\n');

			Clipboard.SetDataObject(textToCopy, true);
		}

		//検索
		private void FindMenuItem_Click(object sender, EventArgs e)
		{
			if (this.IsShowingFindWindow)
			{
				return;
			}

			this.TopMost = false;
			this.IsShowingFindWindow = true;
			this.CurrentShowingFindResultIndex = -1;

			var findWindow = new FindWindow() { FindConditions = this.FindConditions };

			findWindow.FormClosed += (args, fce) =>
			{
				if (GlobalValues.Setting.IsShowWindowMostTop)
				{
					this.TopMost = true;
				}

				this.LivetubeCommentsList.Select();
				this.IsShowingFindWindow = false;
			};

			findWindow.OnFindConditionsChanged += () =>
			{
				this.FindConditions = findWindow.FindConditions;
				this.FindResult.Clear();
				this.LivetubeCommentsList.Items
					.Cast<ListViewItem>().ForEach(i =>
						i.SubItems.Cast<ListViewItem.ListViewSubItem>()
							.Where(xs => xs.BackColor == Color.LemonChiffon)
							.ForEach(xs =>
							{
								xs.BackColor = SystemColors.Window;
								xs.ForeColor = SystemColors.WindowText;
							})
					);

				if (!this.FindConditions.IsUseRegex)
				{
					this.LivetubeCommentsList.Items
						.Cast<ListViewItem>()
						.Select((l, i) =>
							new
							{
								Item = new string(
									l.SubItems
									.Cast<ListViewItem.ListViewSubItem>()
									.Let(xs =>
									{
										var str = "";
										xs.ForEach(xi => str += xi.Text + " ");
										return str;
									})
									.ToArray()),
								Index = i
							}
						).Let(ts => this.FindConditions.IgnoreCase ? ts.Where(xs => xs.Item.Contains(this.FindConditions.Pattern.ToLower())) : ts.Where(xs => xs.Item.Contains(this.FindConditions.Pattern))).Select(xs => xs.Index)
						.ForEach(i => this.FindResult.Add(i));

					if (this.FindResult.Count > 0)
					{
						this.CurrentShowingFindResultIndex = 0;
						this.LivetubeCommentsList.Items[this.FindResult[this.CurrentShowingFindResultIndex]].Selected = true;
						this.LivetubeCommentsList.EnsureVisible(this.CurrentShowingFindResultIndex);

						this.FindResult.ForEach(i =>
							this.LivetubeCommentsList.Items[i].SubItems
								.Cast<ListViewItem.ListViewSubItem>().ForEach(s => { s.BackColor = Color.LemonChiffon; s.ForeColor = SystemColors.WindowText; })
						);
					}
				}
				else
				{
					#warning TODO : 正規表現による検索
				}
			};

			findWindow.Show();
		}

		//次を検索
		private void FindNextMenuitem_Click(object sender, EventArgs e)
		{
			if (this.CurrentShowingFindResultIndex + 1 <= this.FindResult.Count - 1)
			{
				this.CurrentShowingFindResultIndex++;
				this.LivetubeCommentsList.Items[this.FindResult[this.CurrentShowingFindResultIndex - 1]].Selected = false;
			}
			else
			{
				this.LivetubeCommentsList.Items[this.FindResult[this.CurrentShowingFindResultIndex]].Selected = false;
				this.CurrentShowingFindResultIndex = 0;
			}

			this.LivetubeCommentsList.Items[this.FindResult[this.CurrentShowingFindResultIndex]].Selected = true;
			this.LivetubeCommentsList.EnsureVisible(this.FindResult[this.CurrentShowingFindResultIndex]);
		}

		//前を検索
		private void FindPreviousMenuItem_Click(object sender, EventArgs e)
		{
			if (this.CurrentShowingFindResultIndex - 1 >= 0)
			{
				this.CurrentShowingFindResultIndex--;
				this.LivetubeCommentsList.Items[this.FindResult[this.CurrentShowingFindResultIndex + 1]].Selected = false;
			}
			else
			{
				this.LivetubeCommentsList.Items[this.FindResult[this.CurrentShowingFindResultIndex]].Selected = false;
				this.CurrentShowingFindResultIndex = this.FindResult.Count - 1;
			}

			
			this.LivetubeCommentsList.Items[this.FindResult[this.CurrentShowingFindResultIndex]].Selected = true;
		}
		#endregion

		#region 操作メニュー
		private void MarkCommentAsNGMenuItem_Click(object sender, EventArgs e)
		{
			this.LivetubeComments.BanCommentAsync(
				this.LivetubeCommentsList.SelectedItems.Cast<ListViewItem>()
				.Select(s => s.SubItems[0].Text)
				.Select(int.Parse)
			);

		}

		private void MarkCommentAsNotNGMenuItem_Click(object sender, EventArgs e)
		{
			this.LivetubeComments.UnBanCommentAsync(
				this.LivetubeCommentsList.SelectedItems.Cast<ListViewItem>()
				.Select(s => s.SubItems[0].Text)
				.Select(int.Parse)
			);
		}

		private void ShowHostMenuItem_Click(object sender, EventArgs e)
		{
			var comment = this.LivetubeComments.CommentContainer.Single(
				d => d.Number == int.Parse(this.LivetubeCommentsList.SelectedItems[0].SubItems[0].Text)
			);

			if (string.IsNullOrWhiteSpace(comment.Host))
			{
				return;
			}
			else
			{
				MessageBox.Show(String.Format("書き込み元ホスト({0}) : {1}", comment.Number, comment.Host), "書き込み元表示", MessageBoxButtons.OK, MessageBoxIcon.Information);
			}
		}

		private void OpenLiveAuthorsPageMenuItem_Click(object sender, EventArgs e)
		{
			Process.Start("http://livetube.cc/" + this.LivetubeCommentsList.SelectedItems[0].SubItems[3].Text);
		}

		private void OpenLiveAuthorWikiMenuItem_Click(object sender, EventArgs e)
		{
			if (this.SendersWikiCollector.SendersWikiList.Keys.Contains(this.LivetubeCommentsList.SelectedItems[0].SubItems[3].Text))
			{
				Process.Start(this.SendersWikiCollector.SendersWikiList[this.LivetubeCommentsList.SelectedItems[0].SubItems[3].Text].ToString());
			}
		}

		private void SelectAllMenuItem_Click(object sender, EventArgs e)
		{
			this.LivetubeCommentsList.Items.Cast<ListViewItem>().ForEach(i => i.Selected = true);
		}

		private void RefreshConnectionMenuItem_Click(object sender, EventArgs e)
		{
			this.LivetubeComments.RefreshConnection();
		}
		#endregion

		#region その他機能メニュー
		private void UseCommandsMenuItem_CheckedChanged(object sender, EventArgs e)
		{
			GlobalValues.Setting.IsEnableCommand = this.UseCommandsMenuItem.Checked;
		}

		private void UseSoundEffectMenuItem_CheckedChanged(object sender, EventArgs e)
		{
			GlobalValues.Setting.IsEnableSoundEffect = this.UseSoundEffectMenuItem.Checked;
		}

		private void UseReadingMenuItem_Click(object sender, EventArgs e)
		{
			GlobalValues.Setting.IsEnableReading = this.UseReadingMenuItem.Checked;
		}

		private void UseFilteringMenuItem_CheckedChanged(object sender, EventArgs e)
		{
			GlobalValues.Setting.IsEnableFiltering = this.UseFilteringMenuItem.Checked;
		}

		private void StartReadingMenuItem_Click(object sender, EventArgs e)
		{
			this.TextReader.Start();
			this.StartReadingMenuItem.Enabled = false;
			this.StopReadingMenuItem.Enabled = true;
			this.RestartReadingMenuItem.Enabled = false;
			this.SuspendReadingMenuItem.Enabled = true;
		}

		private void StopReadingMenuItem_Click(object sender, EventArgs e)
		{
			this.TextReader.Stop();
			this.StartReadingMenuItem.Enabled = true;
			this.StopReadingMenuItem.Enabled = false;
			this.RestartReadingMenuItem.Enabled = false;
			this.SuspendReadingMenuItem.Enabled = false;
		}

		private void SuspendReadingMenuItem_Click(object sender, EventArgs e)
		{
			this.TextReader.Suspend();
			this.StartReadingMenuItem.Enabled = false;
			this.StopReadingMenuItem.Enabled = true;
			this.RestartReadingMenuItem.Enabled = true;
			this.SuspendReadingMenuItem.Enabled = false;
		}

		private void RestartReadingMenuItem_Click(object sender, EventArgs e)
		{
			this.TextReader.Restart();
			this.StartReadingMenuItem.Enabled = false;
			this.StopReadingMenuItem.Enabled = true;
			this.RestartReadingMenuItem.Enabled = false;
			this.SuspendReadingMenuItem.Enabled = true;
		}

		private void ShortenURLBitlyMenuItem_Click(object sender, EventArgs e)
		{
			Regex.Matches(this.CommentTextBox.Text, @"http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?")
				.Cast<Match>()
				.ForEach(ms =>
				{
					if (GlobalValues.SupportedShortenServices.Any(ms.Value.Contains))
					{
						return;
					}

					var shortener = new global::Aqua877.WinApp.Lib.BitLyURLShortener(GlobalValues.BitLyUserName, GlobalValues.BitLyApiKey);
					shortener.ShortenURLFinished += (sSender, se) =>
					{
						if (se.Error == null)
						{
							this.CommentTextBox.Text = this.CommentTextBox.Text.Replace(ms.Value, se.URLAfterShortening.ToString());
						}
						else
						{
							MessageBox.Show("URLの短縮に失敗しました。", "URL短縮失敗", MessageBoxButtons.OK, MessageBoxIcon.Warning);
						}
					};
					shortener.BeginShortenURL(new Uri(ms.Value));
				});
		}
	
		private void ShortenURLJMpMenuItem_Click(object sender, EventArgs e)
		{
			Regex.Matches(this.CommentTextBox.Text, @"http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?")
				.Cast<Match>()
				.ForEach(ms =>
				{
					if (GlobalValues.SupportedShortenServices.Any(ms.Value.Contains))
					{
						return;
					}

					var shortener = new global::Aqua877.WinApp.Lib.JMpURLShortener(GlobalValues.BitLyUserName, GlobalValues.BitLyApiKey);
					shortener.ShortenURLFinished += (sSender, se) =>
					{
						if (se.Error == null)
						{
							this.CommentTextBox.Text = this.CommentTextBox.Text.Replace(ms.Value, se.URLAfterShortening.ToString());
						}
						else
						{
							MessageBox.Show("URLの短縮に失敗しました。", "URL短縮失敗", MessageBoxButtons.OK, MessageBoxIcon.Warning);
						}
					};
					shortener.BeginShortenURL(new Uri(ms.Value));
				});
		}

		private void ShortenURLIsGdMenuItem_Click(object sender, EventArgs e)
		{
			Regex.Matches(this.CommentTextBox.Text, @"http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?")
				.Cast<Match>()
				.ForEach(ms =>
				{
					if (GlobalValues.SupportedShortenServices.Any(ms.Value.Contains))
					{
						return;
					}

					var shortener = new global::Aqua877.WinApp.Lib.IsGdURLShortener();
					shortener.ShortenURLFinished += (sSender, se) =>
					{
						if (se.Error == null)
						{
							this.CommentTextBox.Text = this.CommentTextBox.Text.Replace(ms.Value, se.URLAfterShortening.ToString());
						}
						else
						{
							MessageBox.Show("URLの短縮に失敗しました。", "URL短縮失敗", MessageBoxButtons.OK, MessageBoxIcon.Warning);
						}
					};
					shortener.BeginShortenURL(new Uri(ms.Value));
				});
		}

		private void ShortenURLUxNuMenuItem_Click(object sender, EventArgs e)
		{
			Regex.Matches(this.CommentTextBox.Text, @"http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?")
				.Cast<Match>()
				.ForEach(ms =>
				{
					if (GlobalValues.SupportedShortenServices.Any(ms.Value.Contains))
					{
						return;
					}

					var shortener = new global::Aqua877.WinApp.Lib.UxNuURLShortener();
					shortener.ShortenURLFinished += (sSender, se) =>
					{
						if (se.Error == null)
						{
							this.CommentTextBox.Text = this.CommentTextBox.Text.Replace(ms.Value, se.URLAfterShortening.ToString());
						}
						else
						{
							MessageBox.Show("URLの短縮に失敗しました。", "URL短縮失敗", MessageBoxButtons.OK, MessageBoxIcon.Warning);
						}
					};
					shortener.BeginShortenURL(new Uri(ms.Value));
				});
		}

		private void ShortenURLPTlMenuItem_Click(object sender, EventArgs e)
		{
			Regex.Matches(this.CommentTextBox.Text, @"http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?")
				.Cast<Match>()
				.ForEach(ms =>
				{
					if (GlobalValues.SupportedShortenServices.Any(ms.Value.Contains))
					{
						return;
					}

					var shortener = new global::Aqua877.WinApp.Lib.PTlURLShortener(GlobalValues.PTlApiKey);
					shortener.ShortenURLFinished += (sSender, se) =>
					{
						if (se.Error == null)
						{
							this.CommentTextBox.Text = this.CommentTextBox.Text.Replace(ms.Value, se.URLAfterShortening.ToString());
						}
						else
						{
							MessageBox.Show("URLの短縮に失敗しました。", "URL短縮失敗", MessageBoxButtons.OK, MessageBoxIcon.Warning);
						}
					};
					shortener.BeginShortenURL(new Uri(ms.Value));
				});
		}
		#endregion

		#region ヘルプメニュー
		private void ViewCachingDataMenuItem_Click(object sender, EventArgs e)
		{
			using (var cm = new CacheManageWindow())
			{
				cm.ShowDialog();
			}
		}

		private void CheckUpdateMenuItem_Click(object sender, EventArgs e)
		{

		}

		private void ShowVersionInformationMenuItem_Click(object sender, EventArgs e)
		{
			using (var about = new AboutIronLivetube())
			{
				about.ShowDialog();
			}
		}
		#endregion

		#region コメント欄
		private void NameTextBox_TextChanged(object sender, EventArgs e)
		{
			if (this.NameTextBox.Text == GlobalValues.Setting.LivetubeUserID)
			{
				this.NameTextBox.ForeColor = Color.Green;
				this.NameTextBox.Font = new Font("メイリオ", 9F, FontStyle.Bold, GraphicsUnit.Point, 128);
			}
			else
			{
				this.NameTextBox.ForeColor = SystemColors.WindowText;
				this.NameTextBox.Font = new Font("メイリオ", 9F, FontStyle.Regular, GraphicsUnit.Point, 128);
			}
		}

		private void PostCommentButton_Click(object sender, EventArgs e)
		{
			if (this.CommentTextBox.Text.Trim() == "")
			{
				this.SetPostCommentErrorText("コメント本文が入力されていません。");
				return;
			}

			this.PostCommentButton.Enabled = false;
			this.LivetubeComments.PostCommentAsync(this.CommentTextBox.Text, this.NameTextBox.Text);
		}
	
		private void CommentTextBox_KeyDown(object sender, KeyEventArgs e)
		{
			Console.WriteLine(e.KeyData);
			if (e.KeyCode == Keys.Enter && e.Modifiers == Keys.Shift)
			{
				this.PostCommentButton.PerformClick();
			}
		}
		#endregion

		#region コメントリストのコンテキストメニュー
		private void CopyCommentContextMenuItem_Click(object sender, EventArgs e)
		{
			this.CopyCommentMenuItem.PerformClick();
		}

		private void CopyCommentTextContextMenuItem_Click(object sender, EventArgs e)
		{
			this.CopyCommentTextMenuItem.PerformClick();
		}

		private void CopyCommentURLContextMenuItem_Click(object sender, EventArgs e)
		{
			this.CopyCommentURLMenuItem.PerformClick();
		}

		private void MarkCommentAsNGContextMenuItem_Click(object sender, EventArgs e)
		{
			this.MarkCommentAsNGMenuItem.PerformClick();
		}

		private void MarkCommentAsNotNGContextMenuItem_Click(object sender, EventArgs e)
		{
			this.MarkCommentAsNotNGMenuItem.PerformClick();
		}

		private void ShowHostContextMenuItem_Click(object sender, EventArgs e)
		{
			this.ShowHostMenuItem.PerformClick();
		}

		private void OpenLiveAuthorsPageContextMenuItem_Click(object sender, EventArgs e)
		{
			this.OpenLiveAuthorsPageMenuItem.PerformClick();
		}

		private void OpenLiveAuthorWikiContextMenuItem_Click(object sender, EventArgs e)
		{
			this.OpenLiveAuthorWikiMenuItem.PerformClick();
		}

		private void SelectAllContextMenuItem_Click(object sender, EventArgs e)
		{
			this.SelectAllMenuItem.PerformClick();
		}

		private void RefreshConnectionContextMenuItem_Click(object sender, EventArgs e)
		{
			this.RefreshConnectionMenuItem.PerformClick();
		}
		#endregion
		#endregion

		#region イベントのコールバック
		//コメントのロード準備が完了
		private void OnLoaded(bool result)
		{
			if (!result)
			{
				this.OpenLiveFromURLMenu.Enabled = true;
				this.OpenLiveFromStreamIDMenuItem.Enabled = true;
				this.OpenLiveFromLiveListMenuItem.Enabled = true;

				MessageBox.Show("ロード中にエラーが発生したため配信を開けませんでした。", "エラー発生", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
			else
			{
				this.CloseLiveMenuItem.Enabled = true;
				this.PlayLiveMenuItem.Enabled = true;
				this.splitContainer1.Panel2.Enabled = true;
				//this.CopyCommentMenuItem.Enabled = true;
				//this.CopyCommentTextMenuItem.Enabled = true;
				//this.CopyCommentURLMenuItem.Enabled = true;
				this.FindMenuItem.Enabled = true;
				this.FindNextMenuitem.Enabled = true;
				this.FindPreviousMenuItem.Enabled = true;
				//this.MarkCommentAsNGMenuItem.Enabled = true;
				//this.MarkCommentAsNotNGMenuItem.Enabled = true;
				//this.ShowHostMenuItem.Enabled = true;
				//this.LiveAuthorMenuItem.Enabled = true;
				this.SelectAllMenuItem.Enabled = true;
				this.SelectAllContextMenuItem.Enabled = true;
				this.RefreshConnectionMenuItem.Enabled = true;
				this.RefreshConnectionContextMenuItem.Enabled = true;

				if (GlobalValues.Setting.IsEnableReading)
				{
					this.TextReader.Start();
					this.StartReadingMenuItem.Enabled = false;
					this.StopReadingMenuItem.Enabled = true;
					this.RestartReadingMenuItem.Enabled = false;
					this.SuspendReadingMenuItem.Enabled = true;
				}
			}
		}

		//コメントの取得時
		private void OnCaughtComment(IEnumerable<LivetubeCommentData> comments)
		{
			this.LivetubeCommentsList.BeginUpdate();
			this.LivetubeCommentsList.ListViewItemSorter = null;

			//リストへのコメントの反映
			comments.ToObservable().Let(
				xs =>
				{
					xs.Where(c => c.Name == "")//名無しコメント
					.Select(d => new ListViewItem(new[]
					{
						new ListViewItem.ListViewSubItem { Text = d.Number.ToString() },
						new ListViewItem.ListViewSubItem { Text = "" },
						new ListViewItem.ListViewSubItem { Text = d.Text },
						new ListViewItem.ListViewSubItem { Text = "" },
						new ListViewItem.ListViewSubItem { Text = d.PostedDate.ToString("M/d H:mm:ss") },
						new ListViewItem.ListViewSubItem { Text = d.ID, Font = new Font("メイリオ", 9F, FontStyle.Italic, GraphicsUnit.Point, 128) },
						new ListViewItem.ListViewSubItem { Text = "" }
					}, 0) { UseItemStyleForSubItems = false })
					.Merge(
						xs.Where(c => c.Name != "" && !c.ContributorCanBroadcasting)//黒コテ
						.Select(d => new ListViewItem(new[]
						{
							new ListViewItem.ListViewSubItem { Text = d.Number.ToString() },
							new ListViewItem.ListViewSubItem { Text = "" },
							new ListViewItem.ListViewSubItem { Text = d.Text },
							new ListViewItem.ListViewSubItem { Text = d.Name, Font = new Font("メイリオ", 9F, FontStyle.Bold, GraphicsUnit.Point, 128) },
							new ListViewItem.ListViewSubItem { Text = d.PostedDate.ToString("M/d H:mm:ss") },
							new ListViewItem.ListViewSubItem { Text = d.ID, Font = new Font("メイリオ", 9F, FontStyle.Italic, GraphicsUnit.Point, 128) },
							new ListViewItem.ListViewSubItem { Text = "" }
						}, 0) { UseItemStyleForSubItems = false })
						.Merge(
							xs.Where(c => c.Name != "" && c.ContributorCanBroadcasting)//緑コテ
							.Select(d => new ListViewItem(new[]
							{
								new ListViewItem.ListViewSubItem { Text = d.Number.ToString() },
								new ListViewItem.ListViewSubItem { Text = "" },
								new ListViewItem.ListViewSubItem { Text = d.Text },
								new ListViewItem.ListViewSubItem { Text = d.Name, Font = new Font("メイリオ", 9F, FontStyle.Bold, GraphicsUnit.Point, 128), ForeColor = Color.Green },
								new ListViewItem.ListViewSubItem { Text = d.PostedDate.ToString("M/d H:mm:ss") },
								new ListViewItem.ListViewSubItem { Text = d.ID, Font = new Font("メイリオ", 9F, FontStyle.Italic, GraphicsUnit.Point, 128) },
								new ListViewItem.ListViewSubItem { Text = "" }
							}, 0) { UseItemStyleForSubItems = false })
						)
					).Subscribe(
						//すべて追加
						d => this.LivetubeCommentsList.Items.Add(d)
					);
					return xs;
				}
			);

			this.LivetubeCommentsList.ListViewItemSorter = this.SortHelper;
			this.LivetubeCommentsList.Sort();
			this.LivetubeCommentsList.EndUpdate();

			//自動スクロール
			if (GlobalValues.Setting.IsEnableAutoScroll)
			{
				if (this.SortHelper.Order == SortOrder.Ascending)
				{
					this.LivetubeCommentsList.EnsureVisible(this.LivetubeCommentsList.Items.Count - 1);
				}
				else if (this.SortHelper.Order == SortOrder.Descending)
				{
					this.LivetubeCommentsList.EnsureVisible(0);
				}
			}

			#warning TODO : フィルタリング

			//朗読
			if (GlobalValues.Setting.IsEnableReading)
			{
				this.TextReader.Read(comments);
			}

			//コメントの部分表示
			if (!GlobalValues.Setting.IsShowAllComments)
			{
				while (this.LivetubeCommentsList.Items.Count > GlobalValues.Setting.ShowCommentCount)
				{
					if (this.SortHelper.Order == SortOrder.Ascending)
					{
						this.LivetubeCommentsList.Items.RemoveAt(0);
					}
					else
					{
						int lastOfIndex = this.LivetubeCommentsList.Items.Count - 1;
						this.LivetubeCommentsList.Items.RemoveAt(lastOfIndex);
					}
				}
			}


		}

		//ステータステキスト変更時
		private void OnStatusTextChanged(string text)
		{
			this.SetProcessingText(text);
		}

		//配信終了時
		private void OnLiveEnded()
		{
			DialogResult result = MessageBox.Show("配信の終了を検知しました。配信を閉じますか?", "配信終了検知", MessageBoxButtons.YesNo, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);

			if (result == DialogResult.Yes)
			{
				this.CloseLiveMenuItem.PerformClick();
			}
		}

		//配信情報更新時
		private void OnInformationRefreshed()
		{
			this.Text = String.Format("IronLivetube - {0} : {1}", this.LivetubeLiveInfo.LiveAuthor, this.LivetubeLiveInfo.LiveTitle);
			this.LiveStatusText.Text =
				String.Format("[視/見]{0}/{1} [流速(Livetube)]{2:f1}コメ/h [流速(したらば)]?コメ/h", this.LivetubeLiveInfo.Listeners, this.LivetubeLiveInfo.Visitors, this.LivetubeLiveInfo.CatchCommentsPerHour);
		}

		private void OnPostCommentFinished(bool success, Exception errorReason)
		{
			if (!success)
			{
				this.SetPostCommentErrorText(errorReason.Message);
			}
			else
			{
				this.CommentTextBox.Text = "";
			}

			this.PostCommentButton.Enabled = true;
		}

		private void OnBanCommentFinished(int id, bool success, Exception error)
		{
			if (success)
			{
				//MessageBox.Show("コメント(ID : " + id + ")は荒らしコメントとしてマークされました。", "マーク成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
				this.LivetubeCommentsList.Items[id].SubItems.Cast<ListViewItem>()
					.ForEach(s => s.BackColor = Color.Gray);

				this.SetProcessingText("コメント(ID : " + id + ")は荒らしコメントとしてマークされました。");
			}
			else
			{
				//MessageBox.Show("コメント(ID : " + id + ")のマークに失敗しました。", "マーク失敗", MessageBoxButtons.OK, MessageBoxIcon.Warning);
				this.SetProcessingText("コメント(ID : " + id + ")のマークに失敗しました。");
			}
		}

		private void OnUnBanCommentFinished(int id, bool success, Exception error)
		{
			if (success)
			{
				//MessageBox.Show("コメント(ID : " + id + ")は荒らしコメントではないとしてマークを解除されました。", "マーク解除成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
				this.LivetubeCommentsList.Items[id].SubItems.Cast<ListViewItem>()
					.ForEach(s => s.BackColor = SystemColors.Window);
				this.SetProcessingText("コメント(ID : " + id + ")は荒らしコメントではないとしてマークを解除されました。");
			}
			else
			{
				//MessageBox.Show("コメント(ID : " + id + ")のマーク解除に失敗しました", "マーク失敗", MessageBoxButtons.OK, MessageBoxIcon.Warning);
				this.SetProcessingText("コメント(ID : " + id + ")のマーク解除に失敗しました");
			}
		}

		private void OnBannedCommentsListFinished(IEnumerable<int> unBannedComment, IEnumerable<int> bannedComment)
		{
			unBannedComment.ForEach(i =>
			{
				if (this.LivetubeCommentsList.Items.Count > i)
				{
					this.LivetubeCommentsList.Items[i].SubItems.Cast<ListViewItem.ListViewSubItem>()
						.ForEach(s => s.BackColor = SystemColors.Window);
				}
			});

			bannedComment.ForEach(i =>
			{
				if (this.LivetubeCommentsList.Items.Count > i)
				{
					this.LivetubeCommentsList.Items[i].SubItems.Cast<ListViewItem.ListViewSubItem>()
						.ForEach(s => s.BackColor = Color.Gray);
				}
			});
		}

		private void OnGetHostFinished(int id, string host)
		{
			this.LivetubeCommentsList.Items
				.Cast<ListViewItem>()
				.Single(s => s.SubItems[0].Text == id.ToString())
				.Let(s => s.SubItems[6].Text = host);
		}
		#endregion

		#region 見た目に関するイベント
		private void splitContainer1_SplitterMoved(object sender, SplitterEventArgs e)
		{
			this.splitContainer1.Panel2MinSize = this.splitContainer1.Panel2.ClientSize.Height;
		}

		private void splitContainer1_SplitterMoving(object sender, SplitterCancelEventArgs e)
		{
			this.splitContainer1.Panel2MinSize = 0;
		}

		private void LivetubeCommentsList_ColumnClick(object sender, ColumnClickEventArgs e)
		{
			if (!GlobalValues.Setting.IsLockSortOrder)
			{
				this.SortHelper.Column = e.Column;
				GlobalValues.Setting.CommentsSortOrder = this.SortHelper.Order;

				this.LivetubeCommentsList.Sort();
			}
		}
	
		private void LivetubeCommentsList_SelectedIndexChanged(object sender, EventArgs e)
		{
			if (this.LivetubeCommentsList.SelectedItems.Count > 0)
			{
				this.CopyCommentMenuItem.Enabled = true;
				this.CopyCommentContextMenuItem.Enabled = true;
				this.CopyCommentTextMenuItem.Enabled = true;
				this.CopyCommentTextContextMenuItem.Enabled = true;
				this.CopyCommentURLMenuItem.Enabled = true;
				this.CopyCommentURLContextMenuItem.Enabled = true;
				this.MarkCommentAsNGMenuItem.Enabled = true;
				this.MarkCommentAsNGContextMenuItem.Enabled = true;
				this.MarkCommentAsNotNGMenuItem.Enabled = true;
				this.MarkCommentAsNotNGContextMenuItem.Enabled = true;
				this.ShowHostMenuItem.Enabled = true;
				this.ShowHostContextMenuItem.Enabled = true;

				var comment = this.LivetubeComments.CommentContainer.Single(
					s => s.Number.ToString() == this.LivetubeCommentsList.SelectedItems[0].SubItems[0].Text
				);

				if (comment.ContributorCanBroadcasting)
				{
					this.LiveAuthorMenuItem.Enabled = true;
					this.LiveAuthorContextMenuItem.Enabled = true;
				}
				else
				{
					this.LiveAuthorMenuItem.Enabled = false;
					this.LiveAuthorContextMenuItem.Enabled = false;
				}
			}
			else
			{
				this.CopyCommentMenuItem.Enabled = false;
				this.CopyCommentContextMenuItem.Enabled = false;
				this.CopyCommentTextMenuItem.Enabled = false;
				this.CopyCommentTextContextMenuItem.Enabled = false;
				this.CopyCommentURLMenuItem.Enabled = false;
				this.CopyCommentURLContextMenuItem.Enabled = false;
				this.MarkCommentAsNGMenuItem.Enabled = false;
				this.MarkCommentAsNGContextMenuItem.Enabled = false;
				this.MarkCommentAsNotNGMenuItem.Enabled = false;
				this.MarkCommentAsNotNGContextMenuItem.Enabled = false;
				this.ShowHostMenuItem.Enabled = false;
				this.ShowHostContextMenuItem.Enabled = false;
			}
		}
		#endregion

		public void SetProcessingText(string text)
		{
			this.ProcessingText.Text = text;

			Observable.Return(text)
				.Delay(TimeSpan.FromSeconds(3))
				.ObserveOnDispatcher()
				.Subscribe(
					s =>
					{
						if (this.ProcessingText.Text == s)
						{
							this.ProcessingText.Text = "";
						}
					}
				);
		}

		public void SetPostCommentErrorText(string errorText)
		{
			this.PostCommentErrorLabel.Visible = true;
			this.PostCommentErrorLabel.Text = "    " + errorText;

			Observable.Return(errorText)
				.Delay(TimeSpan.FromSeconds(5))
				.ObserveOnDispatcher()
				.Subscribe(
					s =>
					{
						if (this.PostCommentErrorLabel.Text == s)
						{
							this.PostCommentErrorLabel.Visible = false;
						}
					}
				);
		}
	}
}
