using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using Betfair.Gamex.API.UberClient.Classes;

using Betfair.Gamex.API.Entities;
using Betfair.Gamex.API;

namespace Betfair.Gamex.API.UberClient.Controls
{
	/// <summary>
	/// Shows current unmatched bets and "new" bets that have not been posted yet
	/// </summary>
	public class PostBetPanel : System.Windows.Forms.UserControl
	{
		private System.Windows.Forms.Panel pnlBetPanel;
		private System.Windows.Forms.Button btnClear;
		private System.Windows.Forms.Button btnSubmit;
		private Adapter m_ApiAdapter;
        private Button btnRefresh;
        private ToolTip toolTip1;
        private IContainer components;
        private long m_CurrentChannelID;

		public PostBetPanel()
		{
			InitializeComponent();
		}

        public Adapter Adapter
        {
            get { return m_ApiAdapter; }
            set { m_ApiAdapter = value; }
        }

        public long CurrentChannelID
        {
            get { return m_CurrentChannelID; }
            set { m_CurrentChannelID = value; }
        }

        public void Initialise()
        {
            UpdateBettingControlsFromSnapshot();
        }

		public void AddBet(Bet bet)
		{
			foreach (IBetPanel bp in pnlBetPanel.Controls)
			{
                if (bp.bet.selectionId == bet.selectionId && bp.bet.bidType == bet.bidType)
                {
                    return;
                }
			}

			BetPanel betPanel = new BetPanel(bet);
            if (bet.bidType == betBidTypeEnum.BACK)
            {
                betPanel.Back = true;
            }
            else
            {
                betPanel.Back = false;
            }

            betPanel.Location = new Point(0, pnlBetPanel.Controls.Count * betPanel.Height);
            betPanel.CancelBet += new CancelBetHandler(Bet_OnCancel);
            pnlBetPanel.Controls.Add(betPanel);
		}

		public void Clear()
		{
			pnlBetPanel.Controls.Clear();
		}

        private void btnClear_Click(object sender, System.EventArgs e)
        {
            this.Clear();
        }

		#region Component Designer generated code
		/// <summary> 
		/// Required method for Designer support - do not modify 
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
            this.components = new System.ComponentModel.Container();
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PostBetPanel));
            this.pnlBetPanel = new System.Windows.Forms.Panel();
            this.btnSubmit = new System.Windows.Forms.Button();
            this.btnClear = new System.Windows.Forms.Button();
            this.btnRefresh = new System.Windows.Forms.Button();
            this.toolTip1 = new System.Windows.Forms.ToolTip(this.components);
            this.SuspendLayout();
            // 
            // pnlBetPanel
            // 
            this.pnlBetPanel.AutoScroll = true;
            this.pnlBetPanel.Dock = System.Windows.Forms.DockStyle.Top;
            this.pnlBetPanel.Location = new System.Drawing.Point(0, 0);
            this.pnlBetPanel.Name = "pnlBetPanel";
            this.pnlBetPanel.Size = new System.Drawing.Size(217, 323);
            this.pnlBetPanel.TabIndex = 0;
            // 
            // btnSubmit
            // 
            this.btnSubmit.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("btnSubmit.BackgroundImage")));
            this.btnSubmit.Cursor = System.Windows.Forms.Cursors.Hand;
            this.btnSubmit.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
            this.btnSubmit.Font = new System.Drawing.Font("Microsoft Sans Serif", 6.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.btnSubmit.ForeColor = System.Drawing.Color.White;
            this.btnSubmit.Image = ((System.Drawing.Image)(resources.GetObject("btnSubmit.Image")));
            this.btnSubmit.ImageAlign = System.Drawing.ContentAlignment.MiddleRight;
            this.btnSubmit.Location = new System.Drawing.Point(156, 326);
            this.btnSubmit.Name = "btnSubmit";
            this.btnSubmit.Size = new System.Drawing.Size(59, 24);
            this.btnSubmit.TabIndex = 7;
            this.btnSubmit.Text = "Submit";
            this.btnSubmit.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
            this.toolTip1.SetToolTip(this.btnSubmit, "Submit bets and bet edits for this game");
            this.btnSubmit.Click += new System.EventHandler(this.btnSubmit_Click);
            // 
            // btnClear
            // 
            this.btnClear.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("btnClear.BackgroundImage")));
            this.btnClear.Cursor = System.Windows.Forms.Cursors.Hand;
            this.btnClear.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
            this.btnClear.Font = new System.Drawing.Font("Microsoft Sans Serif", 6.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.btnClear.ForeColor = System.Drawing.Color.White;
            this.btnClear.Image = ((System.Drawing.Image)(resources.GetObject("btnClear.Image")));
            this.btnClear.ImageAlign = System.Drawing.ContentAlignment.MiddleRight;
            this.btnClear.Location = new System.Drawing.Point(100, 326);
            this.btnClear.Name = "btnClear";
            this.btnClear.Size = new System.Drawing.Size(52, 24);
            this.btnClear.TabIndex = 8;
            this.btnClear.Text = "Clear";
            this.btnClear.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
            this.toolTip1.SetToolTip(this.btnClear, "Clears all unmatched and unplaced bets on this game");
            this.btnClear.Click += new System.EventHandler(this.btnClear_Click);
            // 
            // btnRefresh
            // 
            this.btnRefresh.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("btnRefresh.BackgroundImage")));
            this.btnRefresh.Cursor = System.Windows.Forms.Cursors.Hand;
            this.btnRefresh.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
            this.btnRefresh.Font = new System.Drawing.Font("Microsoft Sans Serif", 6.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.btnRefresh.ForeColor = System.Drawing.Color.White;
            this.btnRefresh.Image = ((System.Drawing.Image)(resources.GetObject("btnRefresh.Image")));
            this.btnRefresh.ImageAlign = System.Drawing.ContentAlignment.MiddleRight;
            this.btnRefresh.Location = new System.Drawing.Point(32, 326);
            this.btnRefresh.Name = "btnRefresh";
            this.btnRefresh.Size = new System.Drawing.Size(64, 24);
            this.btnRefresh.TabIndex = 9;
            this.btnRefresh.Text = "Refresh";
            this.btnRefresh.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
            this.toolTip1.SetToolTip(this.btnRefresh, "Updates view with all unmatched bets on this game");
            this.btnRefresh.Click += new System.EventHandler(this.btnRefresh_Click);
            // 
            // PostBetPanel
            // 
            this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(192)))), ((int)(((byte)(215)))), ((int)(((byte)(236)))));
            this.Controls.Add(this.btnRefresh);
            this.Controls.Add(this.btnClear);
            this.Controls.Add(this.btnSubmit);
            this.Controls.Add(this.pnlBetPanel);
            this.Location = new System.Drawing.Point(430, 46);
            this.Name = "PostBetPanel";
            this.Size = new System.Drawing.Size(217, 351);
            this.ResumeLayout(false);

		}
		#endregion

		/// <summary>
		/// Removes the bet from the display
		/// </summary>
		/// <param name="bet"></param>
		private void Remove(Bet bet)
		{
			for (int i = 0; i < pnlBetPanel.Controls.Count; i++)
			{
				IBetPanel panel = pnlBetPanel.Controls[i] as IBetPanel;
				if (panel != null)
				{
                    if (panel.bet.SelectionName == bet.SelectionName && panel.bet.bidType == bet.bidType)
					{
						pnlBetPanel.Controls.RemoveAt(i);
						break;
					}
				}
			}

            RedrawBets();
		}

        /// <summary>
        /// Repositions all the bets in the panel
        /// </summary>
        private void RedrawBets()
        {
            for (int i = 0; i < pnlBetPanel.Controls.Count; i++)
            {
                IBetPanel panel = pnlBetPanel.Controls[i] as IBetPanel;
                if (panel != null)
                {
                    pnlBetPanel.Controls[i].Location = new Point(0, i * pnlBetPanel.Controls[i].Height);
                }
            }
        }

		private IBetPanel GetBetPanel(Bet bet)
		{
			for (int i = 0; i < pnlBetPanel.Controls.Count; i++)
			{
                IBetPanel panel = pnlBetPanel.Controls[i] as IBetPanel;
                if (panel != null)
                {
                    if (panel.bet.BetID == bet.BetID)
					{
                        return panel;
					}
				}
			}

			return null;
		}

		/// <summary>
		/// Cancel the given get
		/// </summary>
		/// <param name="bet"></param>
		private void Bet_OnCancel(Bet bet)
		{
			IBetPanel betPanel = GetBetPanel(bet);
			
			if (betPanel.bet.Status != BetStatus.Open)
			{
				postBetOrder order = new postBetOrder();
                List<postBetOrderBetCancel> cancelledBets = new List<postBetOrderBetCancel>();

                postBetOrderBetCancel cancel = new postBetOrderBetCancel();
				cancel.betId = bet.BetID;

				cancelledBets.Add(cancel);
                order.betCancel = cancelledBets.ToArray();
				order.marketId = bet.MarketID;
				order.round = bet.Round;
				order.currency = bet.Currency;

				responseBetOrder response = m_ApiAdapter.SetBetOrder(order);		

				if (response.betCancelResult.Length > 0)
				{
					betCancelResultType result = response.betCancelResult[0];
					Remove(bet);

					if (result.resultCode != betResultEnum.REMAINING_CANCELLED)
					{
						MessageBox.Show(string.Format("Bet not cancelled - {0}", result.resultCode));
                        return;
                    }
				}
			}
			else
			{
				// This is an open which hasn't been placed yet. Just remove if from the panel
				Remove(bet);
			}
		}

		private void btnSubmit_Click(object sender, System.EventArgs e)
		{
            // build list of bet types
            Dictionary<int, List<postBetOrderBetPlace>> placeBets = new Dictionary<int, List<postBetOrderBetPlace>>();
            Dictionary<int, List<postBetOrderBetEdit>> editBets = new Dictionary<int, List<postBetOrderBetEdit>>();

            int round = 0;
            string currency = string.Empty;

			foreach (Control c in pnlBetPanel.Controls)
			{
                IBetPanel betPanel = c as IBetPanel;
				if (betPanel != null)
				{
					Bet b = betPanel.bet;

                    // round and currency is same for all bets
                    round = b.Round;
                    currency = b.Currency;

					switch (b.Status)
					{
                        case BetStatus.Open:
                            {
                                List<postBetOrderBetPlace> place = null;
                                if (placeBets.ContainsKey(b.MarketID) == false)
                                {
                                    place = new List<postBetOrderBetPlace>();
                                    placeBets.Add(b.MarketID, place);
                                }
                                else
                                {
                                    place = placeBets[b.MarketID];
                                }

                                postBetOrderBetPlace betPlace = new postBetOrderBetPlace();
                                betPlace.bidType = b.bidType;
                                betPlace.price = b.price;
                                betPlace.selectionId = b.selectionId;
                                betPlace.size = b.size;
                                place.Add(betPlace);
                                break;
                            }
                        case BetStatus.Edited:
                            {
                                List<postBetOrderBetEdit> edit = null;
                                if (placeBets.ContainsKey(b.MarketID) == false)
                                {
                                    edit = new List<postBetOrderBetEdit>();
                                    editBets.Add(b.MarketID, edit);
                                }
                                else
                                {
                                    edit = editBets[b.MarketID];
                                }

                                postBetOrderBetEdit betEdit = new postBetOrderBetEdit();
                                betEdit.price = b.OriginalPlacedPrice;
                                betEdit.newUnmatchedSize = b.size;
                                betEdit.newPrice = b.price;
                                betEdit.bidType = b.bidType;
                                betEdit.price = b.price;
                                betEdit.selectionId = b.selectionId;
                                edit.Add(betEdit);
                                break;
                            }
						// If the bet has been placed or cancelled then we don't
						// want to do anything
						case BetStatus.Placed:
						case BetStatus.Cancelled:
							break;
					}
				}
			}

            // place the bets
            PlaceBet(placeBets, round, currency);
            EditBet(editBets, round, currency);

            UpdateBettingControlsFromSnapshot();
		}

        private void PlaceBet(Dictionary<int, List<postBetOrderBetPlace>> bets, int round, string currency)
        {
            foreach (KeyValuePair<int, List<postBetOrderBetPlace>> entry in bets)
            {
                if (bets.Count == 0)
                {
                    return;
                }

                postBetOrder order = new postBetOrder();
                order.betPlace = entry.Value.ToArray();
                order.marketId = entry.Key;
                order.round = round;
                order.currency = currency;

                try
                {
                    responseBetOrder response = m_ApiAdapter.SetBetOrder(order);

                    if (response.betPlacementResult.Length > 0)
                    {
                        foreach (betPlacementResultType result in response.betPlacementResult)
                        {
                            if (result.resultCode != betResultEnum.OK)
                            {
                                MessageBox.Show(string.Format("Bet not placed - Market: {0}, BetId: {1} - {2}", entry.Key, result.betId, result.resultCode));
                                break;
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }

        private void EditBet(Dictionary<int, List<postBetOrderBetEdit>> bets, int round, string currency)
        {
            foreach (KeyValuePair<int, List<postBetOrderBetEdit>> entry in bets)
            {
                if (bets.Count == 0)
                {
                    return;
                }

                postBetOrder order = new postBetOrder();
                order.betEdit = entry.Value.ToArray();
                order.marketId = entry.Key;
                order.round = round;
                order.currency = currency;

                responseBetOrder response = m_ApiAdapter.SetBetOrder(order);

                if (response.betEditResult.Length > 0)
                {
                    foreach (betEditResultType result in response.betEditResult)
                    {
                        if (result.resultCode != betResultEnum.OK && result.resultCode != betResultEnum.BET_CANCELLED_REMAINING_UNMATCHED)
                        {
                            MessageBox.Show(string.Format("Bet not placed - Market: {0}, BetId: {1} - {2}", entry.Key, result.betId, result.resultCode));
                            break;
                        }
                    }
                }
            }
        }

		private void UpdateBettingControlsFromSnapshot()
		{
            try
            {
                betSnapshot bets = m_ApiAdapter.GetBetSnapshot(BetSnapshotBetStatus.UNMATCHED, Convert.ToInt32(m_CurrentChannelID), BetSnapshotOrderBy.placedDate);
                channelSnapshot channelSS = m_ApiAdapter.GetChannelSnapshot(m_CurrentChannelID);

                pnlBetPanel.Controls.Clear();

                if (bets.betSnapshotItem != null)
                {
                    foreach (betSnapshotBetSnapshotItem bet in bets.betSnapshotItem)
                    {
                        DrawBet(bet, channelSS.channel.game.round);
                    }
                }
            }
            catch { }
		}

		/// <summary>
		/// Creates a control for a bet and adds it to the panel
		/// </summary>
		private void DrawBet(betSnapshotBetSnapshotItem bet, int roundID)
		{
			Bet b = new Bet();
			b.BetID = bet.betId;
			b.bidType = bet.bidType;
			b.Currency = "GBP";
			b.MarketID = bet.selectionReference.marketReference.marketId;
			b.price = bet.price;
			b.Round = roundID;
			b.selectionId = bet.selectionReference.selectionId;
			b.SelectionName = bet.selectionReference.selectionName;
			b.size = bet.size;
			b.Status = BetStatus.Placed;
			b.OriginalPlacedPrice = bet.price;
			b.OriginalPlacedSize = bet.size;
            AddBet(b);
		}

        private void btnRefresh_Click(object sender, EventArgs e)
        {
            UpdateBettingControlsFromSnapshot();
        }
	}
}
