using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace DaifugouGui
{
    using CardGame;
    using Daifugou;

    /// <summary>
    /// DaifugouSimple.xaml の相互作用ロジック
    /// </summary>
    public partial class DaifugouSimple : UserControl
    {
        public DaifugouSimple()
        {
            InitializeComponent();

            this.Loaded += new RoutedEventHandler(Window1_Loaded);

            for (int i = 0; i < N; i++)
            {
                this.selectedCards[i] = new CardSet();
            }

            this.decks = new[] { this.deck1, this.deck2, this.deck3, this.deck4 };
            this.labels = new[] { this.label1, this.label2, this.label3, this.label4 };
            this.submits = new[] { this.submit1, this.submit2, this.submit3, this.submit4 };
            this.passes = new[] { this.pass1, this.pass2, this.pass3, this.pass4 };
        }

        void Window1_Loaded(object sender, RoutedEventArgs e)
        {
            this.startButton.Click += new RoutedEventHandler(startButton_Click);

            foreach (var deck in this.decks)
            {
                deck.AddHandler(CheckBox.ClickEvent, (RoutedEventHandler)this.Card_Click);
            }

            foreach (var submit in this.submits)
            {
                submit.Click += new RoutedEventHandler(submit_Click);
            }

            foreach (var pass in this.passes)
            {
                pass.Click += new RoutedEventHandler(pass_Click);
            }

            this.history.Click += new RoutedEventHandler(history_Click);

            foreach (var label in this.labels)
            {
                label.Click += new RoutedEventHandler(label_Click);
            }

            this.auto.Click += new RoutedEventHandler(auto_Click);

            for (int i = 0; i < N; i++)
            {
                //this.ai1[i] = new SampleRandomAi();
                this.ai[i] = new SampleShortsitedAi();
            }
        }

        void label_Click(object sender, RoutedEventArgs e)
        {
            int index = Array.IndexOf(this.labels, sender);

            if (index == -1)
                return;

            this.UpdateHand(index);
        }

        void UpdateHand(int index)
        {
            var hand = this.game.GetHand(index);

            if (hand == null)
                return;

            ListBox deck = this.decks[index];
            Func<Card, int> sort = this.labels[index].IsChecked ?? false ? sortBySuit : sortByRank;
            deck.ItemsSource = hand.OrderBy(x => sort(x)).ToArray();
        }

        void pass_Click(object sender, RoutedEventArgs e)
        {
            int index = Array.IndexOf(this.passes, sender);

            if (index == -1)
                return;

            if (this.game.Pass(index))
            {
                this.ShowStatus();
            }
        }

        void submit_Click(object sender, RoutedEventArgs e)
        {
            int index = Array.IndexOf(this.submits, sender);

            if (index == -1)
                return;

            CardSet selected = selected = this.selectedCards[index];
            ListBox deck = this.decks[index];

            if (this.game.Play(index, selected))
            {
                selected.Clear();
                this.UpdateHand(index);
                this.ShowStatus();
            }
        }

        IArtificialIntelligence[] ai = new IArtificialIntelligence[N];

        public IArtificialIntelligence[] AI
        {
            get
            {
                return this.ai;
            }
        }


        void auto_Click(object sender, RoutedEventArgs e)
        {
            if (this.game.Players.Count() == 0)
                return;

            var index = this.game.CurrentPlayer;

            var hand = this.game.GetHand(index);
            var table = this.game.CardsOnTable;
            var rank = this.game.CurrentRank;
            var suit = this.game.CurrentSuit;
            var mode = this.game.CurrentMode;
            var revo = this.game.Revolution;
            var hist = this.game.GetHistory();

            // SampleAI はランダムにカード返すだけなので、必ずしもちゃんと出せるカードを返さない。
            // なので、適当な回数Playしてダメだったらパス。
            //for (int i = 0; i < 10; i++)
            {
                var candidate = this.ai[index].Play(hand, table, rank, suit, mode, revo, hist);

                if (this.game.Play(index, candidate))
                {
                    this.UpdateHand(index);
                    this.ShowStatus();
                    return;
                }
            }

            if (this.game.Pass(index))
            {
                CardSet selected = selected = this.selectedCards[index];
                selected.Clear();
                this.ShowStatus();
            }
        }

        void history_Click(object sender, RoutedEventArgs e)
        {
            var h = this.game.GetHistory();

            if (h == null)
                return;

            StringBuilder sb = new StringBuilder();

            foreach (var v in h)
            {
                if (v.Previous == null)
                    sb.AppendFormat("{0}\n\n", v.Count);

                sb.AppendFormat("{0}; ", v.Count);
                foreach (var c in v.Previous)
                {
                    sb.AppendFormat("{0} {1}, ", c.Suit, c.Rank);
                }
                sb.Append("\n");
            }

            MessageBox.Show(sb.ToString());
        }

        static readonly Func<Card, int> sortByRank = Game.SortByRank;
        static readonly Func<Card, int> sortBySuit = Game.SortBySuit;

        static readonly SolidColorBrush normalBrush = new SolidColorBrush(Colors.White);
        static readonly SolidColorBrush emphBrush = new SolidColorBrush(Colors.LightBlue);

        void ShowStatus()
        {
            this.table.ItemsSource = this.game.CardsOnTable.ToArray();

            for (int i = 0; i < N; i++)
            {
                var brush = this.game.CurrentPlayer == i ? emphBrush : normalBrush;
                this.labels[i].Background = brush;
                this.decks[i].Background = brush;
            }

            StringBuilder sb = new StringBuilder();

            sb.AppendFormat("{0}のターン   ", this.game.CurrentPlayer);

            var mode = this.game.CurrentMode;

            if (mode.Match(Mode.Multiple))
                sb.Append("複数 ");
            if (mode.Match(Mode.Sequence))
                sb.Append("連番 ");
            if (mode.Match(Mode.SuitBound))
                sb.Append("同色 ");
            if (mode.Match(Mode.SequenceBound))
                sb.Append("階段 ");
            if (this.game.Revolution)
                sb.Append("革命 ");

            this.status.Content = sb.ToString();
        }

        void Card_Click(object sender, RoutedEventArgs e)
        {
            CheckBox cb = e.OriginalSource as CheckBox;
            if (cb == null) return;

            ListBox lb = e.Source as ListBox;
            if (lb == null) return;

            Card card = cb.DataContext as Card;
            if (card == null) return;

            int i = this.decks.TakeWhile(x => x != lb).Count();

            if (cb.IsChecked ?? false)
                this.selectedCards[i].Add(card);
            else
                this.selectedCards[i].Remove(card);

            e.Handled = true;
        }

        void startButton_Click(object sender, RoutedEventArgs e)
        {
            if (this.game.Players.Count() == 0)
            {
                for (int i = 0; i < N; i++)
                {
                    this.game.Join(i);
                }
            }

            foreach (var selected in this.selectedCards)
            {
                selected.Clear();
            }

            this.game.Deal();

            for (int i = 0; i < N; i++)
            {
                decks[i].ItemsSource = this.game.GetHand(i).OrderBy(x => Game.SortByRank(x)).ToArray();
            }

            this.ShowStatus();
        }

        void showSelectedButton_Click(object sender, RoutedEventArgs e)
        {
            StringBuilder sb = new StringBuilder();

            for (int i = 0; i < N; i++)
            {
                sb.AppendFormat("{0}\n", i);
                foreach (var card in this.selectedCards[i])
                {
                    sb.AppendFormat("\t{0} {1}\n", card.Suit, card.Rank);
                }

            }

            MessageBox.Show(sb.ToString());
        }

        const int N = 4;

        CardSet[] selectedCards = new CardSet[N];

        ListBox[] decks;
        CheckBox[] labels;
        Button[] submits;
        Button[] passes;

        Game game = new Game();
    }
}
