using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using WeifenLuo.WinFormsUI.Docking;
using pcmp.Setting;
using GrayIris.Utilities.UI.Controls;
using System.Net;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
using System.Runtime.InteropServices;

namespace pcmp.Forms
{
    public delegate void ChangeListnerRelayStatEventHandler(int ch, int lis, int rel);
    public delegate void NavigateUrlEventHandler(string url);

    public partial class FormChannelList : DockContent
    {
        public event EventHandler OnListViewSelectedIndexChanged;
        public event ChangeListnerRelayStatEventHandler OnChangeLisRelStat;
        public event NavigateUrlEventHandler OnNavigateUrl;

        ListViewItemComparer comparer;
        List<Channel> DisconnectedChannelList, PlayHistoryChannelList;

        public FormChannelList()
        {
            InitializeComponent();
            Application.Idle += new EventHandler(Application_Idle);
        }

        void Application_Idle(object sender, EventArgs e)
        {
            Application.Idle -= new EventHandler(Application_Idle);

            DisconnectedChannelList = new List<Channel>();
            PlayHistoryChannelList = new List<Channel>();

            // ListViewの描画更新を停止
            listViewChannels.SuspendLayout();

            InitializeListViewColumns();
            InitializeListView();
            InitialApplySetting();

            // ListViewの描画更新を再開
            listViewChannels.ResumeLayout(false);

            InitializeToolMenu();
            Settings.LoadTabSetting();
            InitializeTabs();
        }

        private void InitializeToolMenu()
        {
            //ToolSetting[] toolsettings = Setting.ToolSetting.Load();
            //if (toolsettings != null)
            //{
            //    menuItemExtTool.DropDownItems.Clear();
            //    foreach (ToolSetting item in toolsettings)
            //    {
            //        ToolStripMenuItem menu = new ToolStripMenuItem();
            //        menu.Text = item.Name;
            //        menu.Tag = item;
            //        menu.Click += new EventHandler(menu_Click);
            //        menuItemExtTool.DropDownItems.Add(menu);
            //    }
            //}
        }

        void menu_Click(object sender, EventArgs e)
        {
            ToolSetting tool = (ToolSetting)((ToolStripMenuItem)sender).Tag;
            Channel selItem = listViewChannels.SelectedItems[0].Tag as Channel;
            string arg = tool.Argument;
            arg = Common.ReplaceTag(arg, selItem);
            //arg = arg.Replace("<channelname />", Common.ToArg(selItem.ChannelName));
            //arg = arg.Replace("<stream />", Common.ToArg(selItem.StreamUrl));

            if (arg.Contains("<stream_audio />"))
            {
                HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(selItem.StreamUrl);
                RequestState reqestState = new RequestState();
                reqestState.argument = arg;
                reqestState.request = webReq;
                reqestState.path = tool.Path;
                try
                {
                    webReq.BeginGetResponse(new AsyncCallback(GetAudioStreamUrl), reqestState);
                }
                catch (WebException) { }
                catch { }

                return;
            }

            Common.StartProcess(tool.Path, arg);
        }

        private void InitializeTabs()
        {
            yaTabControl1.Controls.Clear();

            foreach (TabSetting tabsetting in Settings.TabSettings)
            {
                YaTabPage tab = new YaTabPage();
                tab.Text = tabsetting.Name;
                tab.Tag = tabsetting;
                yaTabControl1.Controls.Add(tab);
            }
        }

        private void InitialApplySetting()
        {
            listViewChannels.GridLines = Settings.GeneralSetting.ShowGridLine;
            listViewChannels.BackColor = Settings.GeneralSetting.ListViewBack;

            if (Settings.ApplicationSetting != null && Settings.ApplicationSetting.Columns != null)
            {
                int i = 0;

                foreach (var column in Settings.ApplicationSetting.Columns)
                {
                    if (column.Visible)
                    {
                        if (column.Width != 0) listViewChannels.Columns[i].Width = column.Width;
                        else listViewChannels.Columns[i].Width = 50;

                        try
                        {
                            listViewChannels.Columns[i].DisplayIndex = column.DisplayIndex;
                        }
                        catch (ArgumentOutOfRangeException) { }

                        i++;
                    }
                    else
                    {
                        listViewChannels.Columns.RemoveAt(i);
                    }
                }

                return;
            }
            else
            {
                Settings.ApplicationSetting = new ApplicationSetting();
            }

            List<ColumnSetting> list = new List<ColumnSetting>();
            for (int i = 0; i < listViewChannels.Columns.Count; i++)
            {
                ColumnSetting column = new ColumnSetting();
                column.Visible = true;
                column.Width = listViewChannels.Columns[i].Width;
                column.DisplayIndex = listViewChannels.Columns[i].DisplayIndex;
                column.DisplayText = listViewChannels.Columns[i].Text;
                list.Add(column);
            }
            Settings.ApplicationSetting.Columns = list.ToArray();
            Settings.ApplicationSetting.Save();
        }

        /// <summary>
        /// リストビューの列の初期化
        /// </summary>
        private void InitializeListViewColumns()
        {
            // 列の初期化
            listViewChannels.Columns.Clear();

            // Channelクラスのプロパティを取得し
            // ListViewColumnText属性のついているものから
            // ColumnHeaderを作成して追加
            PropertyDescriptorCollection propcol =
                TypeDescriptor.GetProperties(typeof(Channel));

            List<ColumnHeader> columns = new List<ColumnHeader>();
            ListViewColumnTextAttribute columntextattr = null;
            // イメージ表示用のColumnを追加
            //ColumnHeader column = new ColumnHeader();
            //column.Text = "*";
            //column.Name = "*";
            //columns.Add(column);

            // 取得したプロパティから列を作成
            for (int i = 0; i < propcol.Count; i++)
            {
                PropertyDescriptor pd = propcol[i];
                foreach (Attribute attr in pd.Attributes)
                {
                    if (attr.GetType() == typeof(ListViewColumnTextAttribute))
                    {
                        columntextattr = attr as ListViewColumnTextAttribute;
                        break;
                    }
                }
                if (columntextattr == null) continue;

                ColumnHeader cl = new ColumnHeader();
                cl.Name = columntextattr.Text;
                cl.Text = columntextattr.Text;
                cl.Tag = pd;
                columns.Add(cl);
                columntextattr = null;
            }
            listViewChannels.Columns.AddRange(columns.ToArray());
        }

        /// <summary>
        /// リストビューの初期化
        /// 先に列の初期化が必要
        /// </summary>
        private void InitializeListView()
        {
            // ListViewのアイテムの高さを設定
            int itemHeight = 13;
            if (Settings.YpSettings != null)
            {
                foreach (YpSetting yp in Settings.YpSettings)
                {
                    if (itemHeight < yp.Font.Height * 1.5)
                        itemHeight = (int)(yp.Font.Height * 1.5);
                }
            }
            if (Settings.FavSettings != null)
            {
                foreach (FavSetting fav in Settings.FavSettings)
                {
                    if (itemHeight < fav.Font.Height * 1.5)
                        itemHeight = (int)(fav.Font.Height * 1.5);
                }
            }

            imageList1.ImageSize = new Size(1, itemHeight);

            // ListViewItemComparerの初期化
            // ステータス・降順でソートするようにする
            try
            {
                comparer = new ListViewItemComparer(SortOrder.Descending, listViewChannels.Columns[5]);
                listViewChannels.ListViewItemSorter = comparer;
                listViewChannels.SetColumnToSortIcon(5);
            }
            catch (IndexOutOfRangeException) { }
        }

        /// <summary>
        /// 表示チャンネルの更新
        /// </summary>
        internal void RefreshDisplayChannels()
        {
            listViewChannels.Items.Clear();

            List<ListViewItem> items = new List<ListViewItem>();
            YaTabPage tabpage = yaTabControl1.SelectedTab;
            if (tabpage == null) return;
            if (tabpage.Tag is string)
            {
                ShowSearchTabChannels(tabpage.Tag as string);
                return;
            }
            TabSetting tabsetting = (TabSetting)tabpage.Tag;
            int ch = 0, lis = 0, rel = 0;

            switch (tabsetting.ChannelType)
            {
                // 放送終了
                case 2:
                    for (int i = 0; i < Settings.YpSettings.Length; i++)
                    {
                        YpSetting yp = Settings.YpSettings[i];
                        try
                        {
                            foreach (Channel channel in yp.Disconnected)
                            {
                                ch++;
                                Status status = channel.Status;
                                if (status.Listener > 0) lis += status.Listener;
                                if (status.Relay > 0) rel += status.Relay;
                                ListViewItem item = CreateListViewItem(channel);
                                items.Add(item);
                            }
                        }
                        catch (InvalidOperationException) { }
                    }
                    break;
                // 履歴
                case 3:
                    for (int i = 0; i < PlayHistoryChannelList.Count; i++)
                    {
                        PlayHistoryChannelList[i].No = i + 1;
                        ch++;
                        Status status = PlayHistoryChannelList[i].Status;
                        if (status.Listener > 0) lis += status.Listener;
                        if (status.Relay > 0) rel += status.Relay;
                        ListViewItem item = CreateListViewItem(PlayHistoryChannelList[i]);
                        items.Add(item);
                    }
                    break;
                // NG
                //case 4:
                //    break;
                // 放送中・お気に入り
                default:
                    for (int i = 0; i < Settings.YpSettings.Length; i++)
                    {
                        YpSetting yp = Settings.YpSettings[i];
                        if (!TargetYPSetting.CheckYP(yp.YpName, tabsetting.TargetYpList)) continue;

                        try
                        {
                            if (yp.Channels != null)
                            {
                                foreach (Channel channel in yp.Channels)
                                {
                                    if (!channel.MatchFilter(tabsetting)) continue;
                                    ch++;
                                    Status status = channel.Status;
                                    if (status.Listener > 0) lis += status.Listener;
                                    if (status.Relay > 0) rel += status.Relay;
                                    ListViewItem item = CreateListViewItem(channel);
                                    items.Add(item);
                                }
                            }
                        }
                        catch (InvalidOperationException) { }
                    }
                    break;
            }

            listViewChannels.Items.AddRange(items.ToArray());

            if (OnChangeLisRelStat != null)
                OnChangeLisRelStat(ch, lis, rel);

            // listViewChannels.Sort();
        }

        private bool CheckBitrate(Channel channel, TabSetting tab)
        {
            // ビットレートが空欄ならば常に満たしているとする
            if (tab.Bitrate.Length == 0) return true;

            var minmax = tab.Bitrate.Split(new[] { "-" }, StringSplitOptions.None);
            int min, max;
            if (int.TryParse(minmax[0], out min))
            {
                if (channel.BitRate.Bit < min) return false;
            }
            if (int.TryParse(minmax[1], out max))
            {
                if (channel.BitRate.Bit > max) return false;
            }
            return true;
        }

        // 検索タブ
        public void ShowSearchTabChannels(string str)
        {
            listViewChannels.Items.Clear();
            int ch = 0, lis = 0, rel = 0;
            List<ListViewItem> items = new List<ListViewItem>();
            try
            {
                Regex regex = new Regex(str, RegexOptions.IgnoreCase);
                foreach (YpSetting yp in Settings.YpSettings)
                {
                    foreach (Channel item in yp.Channels)
                    {
                        string temp = item.ChannelName + item.Detail + item.Comment;
                        if (regex.IsMatch(temp))
                        {
                            ch++;
                            if (item.Status.Listener > 0) lis += item.Status.Listener;
                            if (item.Status.Relay > 0) rel += item.Status.Relay;
                            items.Add(CreateListViewItem(item));
                        }
                    }
                }
            }
            catch { }

            listViewChannels.Items.AddRange(items.ToArray());

            if (OnChangeLisRelStat != null)
                OnChangeLisRelStat(ch, lis, rel);
        }

        public void ShowSearchChannels(string str)
        {
            // if (string.IsNullOrEmpty(str)) return;
            listViewChannels.Items.Clear();
            int ch = 0, lis = 0, rel = 0;
            List<ListViewItem> items = new List<ListViewItem>();
            try
            {
                Regex regex = new Regex(str, RegexOptions.IgnoreCase);
                foreach (YpSetting yp in Settings.YpSettings)
                {
                    foreach (Channel item in yp.Channels)
                    {
                        string temp = item.ChannelName + item.Detail + item.Comment;
                        if (regex.IsMatch(temp))
                        {
                            ch++;
                            if (item.Status.Listener > 0) lis += item.Status.Listener;
                            if (item.Status.Relay > 0) rel += item.Status.Relay;
                            items.Add(CreateListViewItem(item));
                        }
                    }
                }
            }
            catch { }

            listViewChannels.Items.AddRange(items.ToArray());

            if (OnChangeLisRelStat != null)
                OnChangeLisRelStat(ch, lis, rel);
        }

        //public void ShowSearchChannels(Regex regex)
        //{
        //    // if (string.IsNullOrEmpty(str)) return;
        //    listViewChannels.Items.Clear();
        //    int ch = 0, lis = 0, rel = 0;
        //    List<ListViewItem> items = new List<ListViewItem>();
        //    try
        //    {
        //        foreach (YpSetting yp in Settings.YpSettings)
        //        {
        //            foreach (Channel item in yp.Channels)
        //            {
        //                string temp = item.ChannelName + item.Detail + item.Comment;
        //                if (regex.IsMatch(temp))
        //                {
        //                    ch++;
        //                    if (item.Status.Listener > 0) lis += item.Status.Listener;
        //                    if (item.Status.Relay > 0) rel += item.Status.Relay;
        //                    items.Add(CreateListViewItem(item));
        //                }
        //            }
        //        }
        //    }
        //    catch { }

        //    listViewChannels.Items.AddRange(items.ToArray());

        //    if (OnChangeLisRelStat != null)
        //        OnChangeLisRelStat(ch, lis, rel);
        //}

        // インクリメンタルサーチで使用
        public void ShowSearchChannels(Regex regex)
        {
            List<ListViewItem> items = new List<ListViewItem>();
            YaTabPage tabpage = yaTabControl1.SelectedTab;
            if (tabpage == null) return;
            Regex regex_prev = null;
            // 選択中のタブが検索タブだった場合
            // 検索文字列で先に絞り込む
            if (tabpage.Tag is string)
            {
                regex_prev = new Regex(tabpage.Tag.ToString(), RegexOptions.IgnoreCase);
            }
            TabSetting tabsetting = (TabSetting)tabpage.Tag;
            int ch = 0, lis = 0, rel = 0;

            switch (tabsetting.ChannelType)
            {
                // 放送終了
                case 2:
                    for (int i = 0; i < Settings.YpSettings.Length; i++)
                    {
                        YpSetting yp = Settings.YpSettings[i];
                        try
                        {
                            foreach (Channel channel in yp.Disconnected)
                            {
                                string temp = channel.ChannelName + channel.Detail + channel.Comment;
                                // 検索タブの条件文字列で絞込み
                                if (regex_prev != null && !regex_prev.IsMatch(temp)) continue;
                                // 検索ボックスの条件で絞込み
                                if (!regex.IsMatch(temp)) continue;

                                ch++;
                                Status status = channel.Status;
                                if (status.Listener > 0) lis += status.Listener;
                                if (status.Relay > 0) rel += status.Relay;
                                ListViewItem item = CreateListViewItem(channel);
                                items.Add(item);
                            }
                        }
                        catch (InvalidOperationException) { }
                    }
                    break;
                // 履歴
                case 3:
                    for (int i = 0; i < PlayHistoryChannelList.Count; i++)
                    {
                        string temp = PlayHistoryChannelList[i].ChannelName +
                            PlayHistoryChannelList[i].Detail +
                            PlayHistoryChannelList[i].Comment;
                        // 検索タブの条件文字列で絞込み
                        if (regex_prev != null && !regex_prev.IsMatch(temp)) continue;
                        // 検索ボックスの条件で絞込み
                        if (!regex.IsMatch(temp)) continue;

                        PlayHistoryChannelList[i].No = i + 1;
                        ch++;
                        Status status = PlayHistoryChannelList[i].Status;
                        if (status.Listener > 0) lis += status.Listener;
                        if (status.Relay > 0) rel += status.Relay;
                        ListViewItem item = CreateListViewItem(PlayHistoryChannelList[i]);
                        items.Add(item);
                    }
                    break;
                // NG
                //case 4:
                //    break;
                // 放送中・お気に入り
                default:
                    for (int i = 0; i < Settings.YpSettings.Length; i++)
                    {
                        YpSetting yp = Settings.YpSettings[i];
                        if (!TargetYPSetting.CheckYP(yp.YpName, tabsetting.TargetYpList)) continue;

                        try
                        {
                            if (yp.Channels != null)
                            {
                                foreach (Channel channel in yp.Channels)
                                {
                                    // タブの条件で絞込み
                                    if (!channel.MatchFilter(tabsetting)) continue;

                                    string temp = channel.ChannelName + channel.Detail + channel.Comment;
                                    // 検索タブの条件文字列で絞込み
                                    if (regex_prev != null && !regex_prev.IsMatch(temp)) continue;
                                    // 検索ボックスの条件で絞込み
                                    if (!regex.IsMatch(temp)) continue;

                                    ch++;
                                    Status status = channel.Status;
                                    if (status.Listener > 0) lis += status.Listener;
                                    if (status.Relay > 0) rel += status.Relay;
                                    ListViewItem item = CreateListViewItem(channel);
                                    items.Add(item);
                                }
                            }
                        }
                        catch (InvalidOperationException) { }
                    }
                    break;
            }

            listViewChannels.Items.Clear();
            listViewChannels.Items.AddRange(items.ToArray());

            if (OnChangeLisRelStat != null)
                OnChangeLisRelStat(ch, lis, rel);
        }

        private ListViewItem CreateListViewItem(Channel channel)
        {
            ListViewItem item = new ListViewItem();
            item.ForeColor = channel.DispStyle.TextColor;
            item.BackColor = channel.DispStyle.BackColor;
            item.StateImageIndex = (int)channel.Diff;

            ListViewItem.ListViewSubItem[] subitems =
                new ListViewItem.ListViewSubItem[listViewChannels.Columns.Count - 1];

            foreach (ColumnHeader cl in listViewChannels.Columns)
            {
                if (cl.Index == 0) continue;
                subitems[cl.Index - 1] = new ListViewItem.ListViewSubItem();
                subitems[cl.Index - 1].Text = ((PropertyDescriptor)cl.Tag).GetValue(channel).ToString();
                subitems[cl.Index - 1].ForeColor = channel.DispStyle.TextColor;
                subitems[cl.Index - 1].BackColor = channel.DispStyle.BackColor;
                subitems[cl.Index - 1].Font = channel.DispStyle.Font;
            }
            item.SubItems.AddRange(subitems);
            item.ForeColor = channel.DispStyle.TextColor;
            item.BackColor = channel.DispStyle.BackColor;
            item.Font = channel.DispStyle.Font;
            if (listViewChannels.Columns.ContainsKey("チャンネル名"))
            {
                if (channel.ContactUrl.Length != 0)
                {
                    if (channel.DispStyle.Font != null)
                        item.SubItems[listViewChannels.Columns["チャンネル名"].Index].Font = new Font(channel.DispStyle.Font, channel.DispStyle.ContactStyle);
                    else
                        item.SubItems[listViewChannels.Columns["チャンネル名"].Index].Font = new Font("MS UI Gothic", 9.0F);
                    item.SubItems[listViewChannels.Columns["チャンネル名"].Index].ForeColor = channel.DispStyle.ContactColor;
                }
            }
            if (listViewChannels.Columns.ContainsKey("タイプ"))
            {
                if (channel.DirectStreamUrl.Length != 0)
                {
                    if (channel.DispStyle.Font != null)
                        item.SubItems[listViewChannels.Columns["タイプ"].Index].Font = new Font(channel.DispStyle.Font, channel.DispStyle.DirectStyle);
                    else
                        item.SubItems[listViewChannels.Columns["タイプ"].Index].Font = new Font("MS UI Gothic", 9.0F);
                    item.SubItems[listViewChannels.Columns["タイプ"].Index].ForeColor = channel.DispStyle.DirectColor;
                }
            }
            item.UseItemStyleForSubItems = false;
            item.Tag = channel;

            return item;
        }

        private void listViewChannels_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
        {
            e.DrawDefault = true;
        }

        private void FormChannelList_Paint(object sender, PaintEventArgs e)
        {
            this.Paint -= new PaintEventHandler(FormChannelList_Paint);
        }

        private void yaTabControl1_TabChanged(object sender, EventArgs e)
        {
            RefreshDisplayChannels();
        }

        private void listViewChannels_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (OnListViewSelectedIndexChanged != null)
            {
                OnListViewSelectedIndexChanged(sender, e);
            }
        }

        private void listViewChannels_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            comparer.ColumnHeader = listViewChannels.Columns[e.Column];
            listViewChannels.ListViewItemSorter = comparer;
            listViewChannels.Sort();
            listViewChannels.SetColumnToSortIcon(e.Column);
        }

        /// <summary>
        /// 設定を適用する
        /// </summary>
        internal void ApplySetting()
        {
            // ListViewの描画更新を停止
            listViewChannels.SuspendLayout();

            InitializeListViewColumns();
            InitializeListView();
            InitialApplySetting();

            // ListViewの描画更新を再開
            listViewChannels.ResumeLayout(false);
            InitializeTabs();
        }

        private void listViewChannels_DoubleClick(object sender, EventArgs e)
        {
            if (listViewChannels.SelectedItems.Count == 0) return;
            ListViewItem item = listViewChannels.SelectedItems[0];
            PlayChannel(item.Tag as Channel);
        }

        public void PlayChannel(Channel channel)
        {
            PlayChannel(channel, channel.StreamUrl);
        }

        public void PlayChannel(Channel channel, string url)
        {
            if (channel == null) return;
            if (Settings.PlayerSettings == null) return;
            PlayHistoryChannelList.Insert(0, channel.Clone() as Channel);
            PlayerSetting player = Settings.PlayerSettings[0];
            foreach (PlayerSetting _playType in Settings.PlayerSettings)
            {
                if (_playType.Type == channel.Type)
                {
                    player = _playType;
                    break;
                }
            }

            string arg = player.Argument;
            if (arg.Contains("<peercast />"))
            {
                try
                {
                    Process.Start(Common.CreatePeercastUrl(url));
                    return;
                }
                catch
                {
                    MessageBox.Show("プレイヤーが起動できませんでした。\r\npeercast://リンクが有効でない可能性があります。", "エラー", MessageBoxButtons.OK);
                }
            }
            arg = arg.Replace("<channelname />", Common.AddQuot(channel.ChannelName));
            arg = arg.Replace("<stream />", Common.AddQuot(url));

            if (arg.Contains("<stream_audio />"))
            {
                HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(url);
                RequestState reqestState = new RequestState();
                reqestState.argument = arg;
                reqestState.request = webReq;
                reqestState.path = player.Path;
                try
                {
                    webReq.BeginGetResponse(new AsyncCallback(GetAudioStreamUrl), reqestState);
                }
                catch (WebException) { }
                catch { }

                return;
            }

            Common.StartProcess(player.Path, arg);
        }

        public void GetAudioStreamUrl(IAsyncResult ar)
        {
            string url = string.Empty;
            RequestState requestState = ar.AsyncState as RequestState;
            if (requestState == null) return;
            HttpWebRequest req = requestState.request;
            using (HttpWebResponse res = (HttpWebResponse)req.EndGetResponse(ar))
            {
                try
                {
                    using (StreamReader sr = new StreamReader(res.GetResponseStream(), Encoding.GetEncoding(932)))
                    {
                        url = sr.ReadLine();
                    }
                }
                catch { }
            }

            string arg = requestState.argument.Replace("<stream_audio />", Common.AddQuot(url));
            Common.StartProcess(requestState.path, arg);
        }

        private void FormChannelList_FormClosing(object sender, FormClosingEventArgs e)
        {
            SaveColumnSetting();
        }

        public void SaveColumnSetting()
        {
            for (int i = 0; i < listViewChannels.Columns.Count; i++)
            {
                Settings.ApplicationSetting.Columns[i].DisplayIndex = listViewChannels.Columns[i].DisplayIndex;
                Settings.ApplicationSetting.Columns[i].Width = listViewChannels.Columns[i].Width;
            }

            Settings.ApplicationSetting.Save();
        }

        public void SearchChannel(string str)
        {
            foreach (YaTabPage tab in yaTabControl1.Controls)
            {
                string tagstr = tab.Tag as string;
                if (tagstr != null && tagstr == str)
                {
                    yaTabControl1.SelectedTab = tab;
                    return;
                }
            }

            YaTabPage tabpage = new YaTabPage();
            tabpage.Tag = str;
            tabpage.Text = "検索:" + str;
            tabpage.ContextMenuStrip = contextMenuStrip2;
            yaTabControl1.Controls.Add(tabpage);
            yaTabControl1.SelectedTab = tabpage;
        }

        private void menuItemCloseTab_Click(object sender, EventArgs e)
        {
            if (yaTabControl1.SelectedTab.Tag is string)
            {
                yaTabControl1.Controls.Remove(yaTabControl1.SelectedTab);
            }
        }

        private void contextMenuStrip2_Opening(object sender, CancelEventArgs e)
        {
            menuItemCloseTab.Enabled = yaTabControl1.SelectedTab.Tag is string;
            e.Cancel = !menuItemCloseTab.Enabled;
        }

        private void menuItemPlay_Click(object sender, EventArgs e)
        {
            if (listViewChannels.SelectedItems.Count == 0) return;
            PlayChannel(listViewChannels.SelectedItems[0].Tag as Channel);
        }

        private void menuItemPlayDirectStream_Click(object sender, EventArgs e)
        {
            if (listViewChannels.SelectedItems.Count == 0) return;
            Channel channel = listViewChannels.SelectedItems[0].Tag as Channel;
            PlayChannel(channel, channel.DirectStreamUrl);
        }

        private void menuItemOpenContactUrl_Click(object sender, EventArgs e)
        {
            if (listViewChannels.SelectedItems.Count == 0) return;
            Channel channel = listViewChannels.SelectedItems[0].Tag as Channel;
            OpenUrl(channel.ContactUrl);
        }

        private void OpenUrl(string url)
        {
            if (Setting.Settings.GeneralSetting.UseBrowser2ch)
            {
                try
                {
                    Regex regex2ch = new Regex(Settings.GeneralSetting.Regex2chUrl);
                    if (regex2ch.IsMatch(url))
                    {
                        Common.StartProcess(Settings.GeneralSetting.Browser2chPath, url);
                        return;
                    }
                }
                catch (ArgumentException) { }
            }

            if (Settings.GeneralSetting.UseOtherBrowser)
            {
                Common.StartProcess(Settings.GeneralSetting.BrowserPath, url);
            }
            else
            {
                if (OnNavigateUrl != null) OnNavigateUrl(url);
            }
        }

        private void menuItemOpenStatUrl_Click(object sender, EventArgs e)
        {
            if (listViewChannels.SelectedItems.Count == 0) return;
            Channel channel = listViewChannels.SelectedItems[0].Tag as Channel;
            OpenUrl(channel.StatUrl);
        }

        private void menuItemOpenChatUrl_Click(object sender, EventArgs e)
        {
            if (listViewChannels.SelectedItems.Count == 0) return;
            Channel channel = listViewChannels.SelectedItems[0].Tag as Channel;
            OpenUrl(channel.ChatUrl);
        }

        private void menuItemCopyDetail_Click(object sender, EventArgs e)
        {
            try
            {
                if (listViewChannels.SelectedItems.Count == 0) return;
                Channel channel = listViewChannels.SelectedItems[0].Tag as Channel;
                string clip = channel.No + " ." + channel.ChannelName + "\r\n";
                if (channel.Desc != string.Empty)
                    clip += "   " + channel.Desc + "\r\n";
                if (channel.Playing != string.Empty)
                    clip += "   " + channel.Playing + "\r\n";
                if (channel.Comment != string.Empty)
                    clip += "   " + channel.Comment + "\r\n";
                if (clip.EndsWith("\r\n"))
                    clip = clip.Remove(clip.LastIndexOf("\r\n"));

                Clipboard.SetText(clip);
            }
            catch (ExternalException) { MessageBox.Show("クリップボードへデータをコピーできませんでした。"); }
            catch { }
        }

        private void menuItemContactUrl_Click(object sender, EventArgs e)
        {
            try
            {
                if (listViewChannels.SelectedItems.Count == 0) return;
                Channel channel = listViewChannels.SelectedItems[0].Tag as Channel;
                Clipboard.SetText(channel.ContactUrl);
            }
            catch (ExternalException) { MessageBox.Show("クリップボードへデータをコピーできませんでした。"); }
            catch { }
        }

        private void menuItemStreamUrl_Click(object sender, EventArgs e)
        {
            try
            {
                if (listViewChannels.SelectedItems.Count == 0) return;
                Channel channel = listViewChannels.SelectedItems[0].Tag as Channel;
                Clipboard.SetText(channel.StreamUrl);
            }
            catch (ExternalException) { MessageBox.Show("クリップボードへデータをコピーできませんでした。"); }
            catch { }
        }

        internal void PlayChannel()
        {
            if (listViewChannels.SelectedItems.Count == 0) return;
            Channel channel = listViewChannels.SelectedItems[0].Tag as Channel;
            PlayChannel(channel);
        }

        internal void PlayChannel(string url)
        {
            
        }
    }

    public class DoubleBufferedListView : ListView
    {
        int previousSortColumn = -1;

        public DoubleBufferedListView()
        {
            base.DoubleBuffered = true;
        }

        public void SetColumnToSortIcon(int newSortColumn)
        {
            IntPtr hHeader = Win32.SendMessage(this.Handle, Win32.LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero);
            IntPtr newColumn = new IntPtr(newSortColumn);
            IntPtr prevColumn = new IntPtr(previousSortColumn);
            Win32.HDITEM hdItem;
            IntPtr rtn;

            // Only update the previous item if it existed and if it was a different one.
            if (previousSortColumn != -1 && previousSortColumn != newSortColumn)
            {
                // Clear icon from the previous column.
                hdItem = new Win32.HDITEM();
                hdItem.mask = Win32.HDI_FORMAT;
                rtn = Win32.SendMessage(hHeader, Win32.HDM_GETITEM, prevColumn, ref hdItem);
                hdItem.fmt &= ~Win32.HDF_SORTDOWN & ~Win32.HDF_SORTUP;
                rtn = Win32.SendMessage(hHeader, Win32.HDM_SETITEM, prevColumn, ref hdItem);
            }

            // Set icon on the new column.
            hdItem = new Win32.HDITEM();
            hdItem.mask = Win32.HDI_FORMAT;
            rtn = Win32.SendMessage(hHeader, Win32.HDM_GETITEM, newColumn, ref hdItem);
            var comparer = this.ListViewItemSorter as ListViewItemComparer;
            if (comparer == null) return;
            if (comparer.Order == SortOrder.Ascending)
            {
                hdItem.fmt &= ~Win32.HDF_SORTDOWN;
                hdItem.fmt |= Win32.HDF_SORTUP;
            }
            else
            {
                hdItem.fmt &= ~Win32.HDF_SORTUP;
                hdItem.fmt |= Win32.HDF_SORTDOWN;
            }
            rtn = Win32.SendMessage(hHeader, Win32.HDM_SETITEM, newColumn, ref hdItem);
            previousSortColumn = newSortColumn;
        }
    }
}