using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using pcmp.Setting;
using System.Text.RegularExpressions;

namespace pcmp
{
    public enum ChannelDiff
    {
        New = 2,
        Up = 0,
        Down = 1,
        None = -1
    }

    [Flags]
    public enum ChannelState
    {
        New = 1,
        Broadcasting = 2,
    }

    public class CastTime : IComparable
    {
        // コンストラクタ
        public CastTime() { }

        public CastTime(int hour, int minutes)
        {
            Hour = hour;
            Minutes = minutes;
        }

        // プロパティ
        public int Hour { get; set; }
        public int Minutes { get; set; }

        public override string ToString()
        {
            return string.Format("{0:d2}:{1:d2}", Hour, Minutes);
        }

        #region IComparable メンバ

        public int CompareTo(object obj)
        {
            CastTime time = obj as CastTime;
            int x = Hour * 60 + Minutes;
            int y = time.Hour * 60 + time.Minutes;
            return x - y;
        }

        #endregion
    }

    public class Status : IComparable
    {
        // コンストラクタ
        public Status(int listener, int relay)
        {
            Listener = listener;
            Relay = relay;
        }

        // プロパティ
        public int Listener { get; set; }
        public int Relay { get; set; }

        public override string ToString()
        {
            return Listener + " / " + Relay;
        }

        public static int Compare(Status x, Status y)
        {
            if (x.Relay > y.Relay)
                return 1;
            else if (x.Relay == y.Relay)
                return x.Listener - y.Listener;
            else
                return -1;
        }

        #region IComparable メンバ

        public int CompareTo(object obj)
        {
            if (obj == null) return 1;
            Status y = (Status)obj;
            if (Listener > y.Listener)
                return 1;
            else if (Listener == y.Listener)
                return Relay - y.Relay;
            else
                return -1;
        }

        #endregion
    }

    public class Bitrate : IComparable
    {
        // コンストラクタ
        public Bitrate(int bit)
        {
            Bit = bit;
            Rate = "kb/s";
        }

        public Bitrate(int bit, string rate)
        {
            Bit = bit;
            Rate = rate;
        }

        // プロパティ
        public int Bit { get; set; }
        public string Rate { get; set; }

        public override string ToString()
        {
            return Bit + Rate;
        }

        #region IComparable メンバ

        public int CompareTo(object obj)
        {
            return Bit - ((Bitrate)obj).Bit;
        }

        #endregion
    }

    [Serializable]
    public class Channel : ICloneable
    {
        public Channel()
        {
            this.ChannelName = string.Empty;
            this.Detail = string.Empty;
            this.Type = string.Empty;
            this.Playing = string.Empty;
            this.Desc = string.Empty;
            this.ContactUrl = string.Empty;
            this.StreamUrl = string.Empty;
            this.DirectStreamUrl = string.Empty;
            this.ChatUrl = string.Empty;
            this.StatUrl = string.Empty;
            this.YPUrl = string.Empty;
            this.Comment = string.Empty;
            this.YPName = string.Empty;
            this.Alt = string.Empty;
            this.ID = string.Empty;
            this.GetTime = string.Empty;
            this.Sound = string.Empty;
            this.FavIndex = -1;
            this.Diff = ChannelDiff.None;
            this.Status = new Status(0, 0);
            this.BitRate = new Bitrate(0);
            this.Time = new CastTime();
            this.MatchStatus = MatchStatus.None;
            this.DispStyle = new DisplayStyle();
        }

        public ChannelState State { get; set; }

        public DisplayStyle DispStyle { get; set; }

        public MatchStatus MatchStatus { get; set; }

        public int FavIndex { get; set; }

        public int StateImageIndex { get; set; }

        [ListViewColumnText("*")]
        public ChannelDiff Diff { get; set; }

        [ListViewColumnText("No")]
        public int No { get; set; }

        // public bool IsFav { get; set; }

        [ListViewColumnText("チャンネル名")]
        public string ChannelName { get; set; }

        [ListViewColumnText("詳細")]
        public string Detail { get; set; }

        [ListViewColumnText("コメント")]
        public string Comment { get; set; }

        [ListViewColumnText("ステータス")]
        public Status Status { get; set; }

        [ListViewColumnText("ビットレート")]
        public Bitrate BitRate { get; set; }

        [ListViewColumnText("タイプ")]
        public string Type { get; set; }

        [ListViewColumnText("コンタクトURL")]
        public string ContactUrl { get; set; }

        [ListViewColumnText("ストリームURL")]
        public string StreamUrl { get; set; }

        [ListViewColumnText("チャットURL")]
        public string ChatUrl { get; set; }

        [ListViewColumnText("統計URL")]
        public string StatUrl { get; set; }

        [ListViewColumnText("Playing")]
        public string Playing { get; set; }

        [ListViewColumnText("ジャンル")]
        public string Desc { get; set; }

        [ListViewColumnText("ダイレクトストリームURL")]
        public string DirectStreamUrl { get; set; }

        [ListViewColumnText("YPURL")]
        public string YPUrl { get; set; }

        [ListViewColumnText("YP")]
        public string YPName { get; set; }

        [ListViewColumnText("ID")]
        public string ID { get; set; }

        [ListViewColumnText("Alt")]
        public string Alt { get; set; }

        public string Sound { get; set; }

        [ListViewColumnText("取得時間")]
        public string GetTime { get; set; }

        [ListViewColumnText("配信時間")]
        public CastTime Time { get; set; }

        #region ICloneable メンバ

        public object Clone()
        {
            return MemberwiseClone();
        }

        #endregion

        public NGSetting MatchNG(NGSetting[] ngSettings)
        {
            if (ngSettings == null) return null;
            StringBuilder sb;

            foreach (NGSetting ng in ngSettings)
            {
                if (!ng.Enable) continue;
                if (ng.SerachAfterConcat)
                {
                    sb = new StringBuilder();
                    if (ng.SearchChannelName) sb.Append(this.ChannelName);
                    if (ng.SearchComment) sb.Append(this.Comment);
                    if (ng.SearchContactUrl) sb.Append(this.ChatUrl);
                    if (ng.SearchDetail) sb.Append(this.Detail);
                    if (ng.SearchYelloPageUrl) sb.Append(this.YPUrl);

                    if (ng.UseRegex)
                    {
                        try
                        {
                            Regex regex = new Regex(ng.SearchString, RegexOptions.IgnoreCase);
                            if (regex.IsMatch(sb.ToString()))
                            {
                                this.MatchStatus = MatchStatus.NG;
                                return ng;
                            }
                        }
                        catch (ArgumentException) { }
                    }
                    else
                    {
                        if (sb.ToString().Contains(ng.SearchString))
                        {
                            this.MatchStatus = MatchStatus.NG;
                            return ng;
                        }
                    }
                }
                else
                {
                    if (ng.UseRegex)
                    {
                        try
                        {
                            Regex regex = new Regex(ng.SearchString);
                            if (ng.SearchChannelName && regex.IsMatch(this.ChannelName))
                            {
                                this.MatchStatus = MatchStatus.NG;
                                return ng;
                            }
                            if (ng.SearchComment && regex.IsMatch(this.Comment))
                            {
                                this.MatchStatus = MatchStatus.NG;
                                return ng;
                            }
                            if (ng.SearchContactUrl && regex.IsMatch(this.ContactUrl))
                            {
                                this.MatchStatus = MatchStatus.NG;
                                return ng;
                            }
                            if (ng.SearchDetail && regex.IsMatch(this.Detail))
                            {
                                this.MatchStatus = MatchStatus.NG;
                                return ng;
                            }
                            if (ng.SearchYelloPageUrl && regex.IsMatch(this.YPUrl))
                            {
                                this.MatchStatus = MatchStatus.NG;
                                return ng;
                            }
                        }
                        catch (ArgumentException) { }
                    }
                    else
                    {
                        if (ng.SearchChannelName && this.ChannelName.Contains(ng.SearchString))
                        {
                            this.MatchStatus = MatchStatus.NG;
                            return ng;
                        }

                        if (ng.SearchComment && this.Comment.Contains(ng.SearchString))
                        {
                            this.MatchStatus = MatchStatus.NG;
                            return ng;
                        }

                        if (ng.SearchContactUrl && this.ContactUrl.Contains(ng.SearchString))
                        {
                            this.MatchStatus = MatchStatus.NG;
                            return ng;
                        }

                        if (ng.SearchDetail && this.Detail.Contains(ng.SearchString))
                        {
                            this.MatchStatus = MatchStatus.NG;
                            return ng;
                        }

                        if (ng.SearchYelloPageUrl && this.YPUrl.Contains(ng.SearchString))
                        {
                            this.MatchStatus = MatchStatus.NG;
                            return ng;
                        }
                    }
                }
            }

            this.MatchStatus = MatchStatus.None;
            return null;
        }

        public FavSetting MatchFav(FavSetting[] favSettings)
        {
            if (favSettings == null) return null;
            StringBuilder sb;
            for (int i = 0; i < favSettings.Length; i++)
            {
                FavSetting fav = favSettings[i];
                if (!fav.Enable) continue;
                if (fav.SerachAfterConcat)
                {
                    sb = new StringBuilder();
                    if (fav.SearchChannelName) sb.Append(this.ChannelName);
                    if (fav.SearchComment) sb.Append(this.Comment);
                    if (fav.SearchContactUrl) sb.Append(this.ChatUrl);
                    if (fav.SearchDetail) sb.Append(this.Detail);
                    if (fav.SearchYelloPageUrl) sb.Append(this.YPUrl);

                    if (fav.UseRegex)
                    {
                        try
                        {
                            Regex regex = new Regex(fav.SearchString, RegexOptions.IgnoreCase);
                            if (regex.IsMatch(sb.ToString()))
                            {
                                this.MatchStatus = MatchStatus.Favorite;
                                this.FavIndex = i;
                                this.Sound = fav.SoundPath;
                                return fav;
                            }
                        }
                        catch (ArgumentException) { }
                    }
                    else
                    {
                        if (sb.ToString().Contains(fav.SearchString))
                        {
                            this.MatchStatus = MatchStatus.Favorite;
                            this.FavIndex = i;
                            this.Sound = fav.SoundPath;
                            return fav;
                        }
                    }
                }
                else
                {
                    if (fav.UseRegex)
                    {
                        try
                        {
                            Regex regex = new Regex(fav.SearchString);
                            if (fav.SearchChannelName && regex.IsMatch(this.ChannelName))
                            {
                                this.MatchStatus = MatchStatus.Favorite;
                                this.FavIndex = i;
                                this.Sound = fav.SoundPath;
                                return fav;
                            }
                            if (fav.SearchComment && regex.IsMatch(this.Comment))
                            {
                                this.MatchStatus = MatchStatus.Favorite;
                                this.FavIndex = i;
                                this.Sound = fav.SoundPath;
                                return fav;
                            }
                            if (fav.SearchContactUrl && regex.IsMatch(this.ContactUrl))
                            {
                                this.MatchStatus = MatchStatus.Favorite;
                                this.FavIndex = i;
                                this.Sound = fav.SoundPath;
                                return fav;
                            }
                            if (fav.SearchDetail && regex.IsMatch(this.Detail))
                            {
                                this.MatchStatus = MatchStatus.Favorite;
                                this.FavIndex = i;
                                this.Sound = fav.SoundPath;
                                return fav;
                            }
                            if (fav.SearchYelloPageUrl && regex.IsMatch(this.YPUrl))
                            {
                                this.MatchStatus = MatchStatus.Favorite;
                                this.FavIndex = i;
                                this.Sound = fav.SoundPath;
                                return fav;
                            }
                        }
                        catch (ArgumentException) { }
                    }
                    else
                    {
                        if (fav.SearchChannelName && this.ChannelName.Contains(fav.SearchString))
                        {
                            this.MatchStatus = MatchStatus.Favorite;
                            this.FavIndex = i;
                            this.Sound = fav.SoundPath;
                            return fav;
                        }

                        if (fav.SearchComment && this.Comment.Contains(fav.SearchString))
                        {
                            this.MatchStatus = MatchStatus.Favorite;
                            this.FavIndex = i;
                            this.Sound = fav.SoundPath;
                            return fav;
                        }

                        if (fav.SearchContactUrl && this.ContactUrl.Contains(fav.SearchString))
                        {
                            this.MatchStatus = MatchStatus.Favorite;
                            this.FavIndex = i;
                            this.Sound = fav.SoundPath;
                            return fav;
                        }

                        if (fav.SearchDetail && this.Detail.Contains(fav.SearchString))
                        {
                            this.MatchStatus = MatchStatus.Favorite;
                            this.FavIndex = i;
                            this.Sound = fav.SoundPath;
                            return fav;
                        }

                        if (fav.SearchYelloPageUrl && this.YPUrl.Contains(fav.SearchString))
                        {
                            this.MatchStatus = MatchStatus.Favorite;
                            this.FavIndex = i;
                            this.Sound = fav.SoundPath;
                            return fav;
                        }
                    }
                }
            }

            this.MatchStatus = MatchStatus.None;
            this.FavIndex = -1;
            this.Sound = string.Empty;
            return null;
        }

        public bool MatchFilter(TabSetting tab)
        {
            switch (tab.ChannelType)
            {
                case 0: // 放送中
                    if ((this.State & ChannelState.Broadcasting) != ChannelState.Broadcasting ||
                        this.MatchStatus == MatchStatus.NG) return false;
                    break;
                case 1: // お気に入り
                    if (this.MatchStatus != MatchStatus.Favorite) return false;
                    break;
                //case 2: // 放送終了
                //    if (this.state != ChannelState.Disconnected) return false;
                //    break;
                //case 3: // 履歴
                //    if (this.state != ChannelState.History) return false;
                //    break;
                case 4: // 新着
                    if (this.Diff != ChannelDiff.New) return false;
                    break;
                case 5: // NG
                    if (this.MatchStatus != MatchStatus.NG) return false;
                    break;
                default: break;
            }

            // if (!TargetYPSetting.CheckYP(this, tab.TargetYpList)) return false;

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

            // 文字列をすべて結合
            if (tab.ConcatAllStrings)
            {
                StringBuilder sb = new StringBuilder();
                if (tab.CheckChannel) sb.Append(this.ChannelName);
                if (tab.CheckComment) sb.Append(this.Comment);
                if (tab.CheckGenre) sb.Append(this.Desc);
                if (tab.CheckPlaying) sb.Append(this.Playing);
                if (tab.CheckType) sb.Append(this.Type);
                if (tab.CheckContact) sb.Append(this.ContactUrl);

                string checkstr = sb.ToString();
                return CheckChannelItem(tab, checkstr);

                //// 正規表現を使う場合
                //if (tab.UseRegex)
                //{
                //    try
                //    {
                //        Regex regex;
                //        if (tab.IgnoreCase) regex =
                //            new Regex(tab.Condition, RegexOptions.IgnoreCase);
                //        else regex = new Regex(tab.Condition);
                //        return regex.IsMatch(checkstr);
                //    }
                //    catch (ArgumentException) { return false; }
                //    catch { return false; }
                //}

                //// 正規表現なし
                //if (tab.IgnoreCase) return checkstr.IndexOf(tab.Condition, StringComparison.CurrentCultureIgnoreCase) != -1;
                //else return checkstr.Contains(tab.Condition);
            }

            // 別々にやっていく
            if (tab.CheckChannel) if (CheckChannelItem(tab, this.ChannelName)) return true;
            if (tab.CheckComment) if (CheckChannelItem(tab, this.Comment)) return true;
            if (tab.CheckGenre) if (CheckChannelItem(tab, this.Desc)) return true;
            if (tab.CheckPlaying) if (CheckChannelItem(tab, this.Playing)) return true;
            if (tab.CheckType) if (CheckChannelItem(tab, this.Type)) return true;
            if (tab.CheckContact) if (CheckChannelItem(tab, this.ContactUrl)) return true;

            return false;
        }

        private bool CheckChannelItem(TabSetting tab, string str)
        {
            if (tab.UseRegex)
            {
                try
                {
                    Regex regex;
                    if (tab.IgnoreCase) regex = new Regex(tab.Condition, RegexOptions.IgnoreCase);
                    else regex = new Regex(tab.Condition);
                    return regex.IsMatch(str);
                }
                catch (ArgumentException) { return false; }
                catch { return false; }
            }

            // 正規表現なし
            if (tab.IgnoreCase)
            {
                return str.IndexOf(tab.Condition, StringComparison.CurrentCultureIgnoreCase) != -1;
            }
            else
            {
                return str.Contains(tab.Condition);
            }
        }
    }

    public class ListViewColumnTextAttribute : Attribute
    {
        public ListViewColumnTextAttribute(string text)
        {
            _text = text;
        }

        private string _text;

        public string Text
        {
            get { return _text; }
            set { _text = value; }
        }

    }
}
