using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using KeyConfig.Config;
using KeyConfig.Map;

namespace KeyConfig
{
	internal class PadEditor : EditorBase
	{
		//----------// //----------// //----------// //----------//
		//
		//	Constructor
		//
		//----------// //----------// //----------// //----------//

		internal PadEditor()
		{
			tmrMain = new Timer()
			{
				Interval = 20
			};
			tmrMain.Tick += new EventHandler(tmrMain_Tick);
			tmrMain.Start();
		}

		//----------// //----------// //----------// //----------//
		//
		//	Fields
		//
		//----------// //----------// //----------// //----------//

		// Controls
		Timer tmrMain;
		List<TextBox> textBoxList = new List<TextBox>();

		// Pad Device
		PadMonitor monitor = null;
		int padValue = 0;

		// Config
		ConfigData config = null;
		KeyMap map = null;

		//----------// //----------// //----------// //----------//
		//
		//	Methods
		//
		//----------// //----------// //----------// //----------//

		internal void InitializeEditor(ConfigData config, KeyMap map, JoyPad pad, int labelWidth, int textWidth, int labelHeight)
		{
			if (config == null) throw new ArgumentNullException("config");
			if (map == null) throw new ArgumentNullException("map");

			this.config = config;
			this.map = map;
			this.monitor = new PadMonitor(pad);
			this.monitor.Pressed += new EventHandler<DataEventArgs<int>>(PadMonitor_Pressed);

			var lblTitle = new Label()
			{
				AutoSize = true,
				Text = "パッド用コンフィグ"
			};

			this.Controls.Add(lblTitle);

			var kt = new ListLabel() { Top = 24 };
			kt.UpdateTitle(GetPadTitles(), 88);

			this.Controls.Add(kt);

			for (int i = 0; i < config.PadList.Count; i++)
			{
				var textBox = new TextBox()
				{
					Left = labelWidth + 8,
					Width = textWidth,
					Top = labelHeight * (i + 1),
					Text = config.PadList[i].Value.ToString()
				};

				textBox.KeyDown += new KeyEventHandler(textBox_KeyDown);
				textBox.TextChanged += new EventHandler(textBox_TextChanged);

				this.Controls.Add(textBox);

				textBoxList.Add(textBox);
			}

			this.Width = textBoxList[textBoxList.Count - 1].Right;
			this.Height = labelHeight * (config.PadList.Count + 1);
		}

		private string GetPadTitle(int index)
		{
			return map.Parse(config.KeyList[index].Key);
		}

		private List<string> GetPadTitles()
		{
			var ktt = new List<string>();

			for (int i = 0; i < config.KeyList.Count; i++)
			{
				ktt.Add(GetPadTitle(i));
			}

			return ktt;
		}

		/// <summary>
		/// パッドの入力値を反映する
		/// </summary>
		void SetPadValue()
		{
			for (int i = 0; i < textBoxList.Count; i++)
			{
				var box = textBoxList[i];
				if (box.Focused)
				{
					config.PadList[i] = new KeyValuePair<string, int>(config.PadList[i].Key, padValue);
					box.Text = padValue.ToString();

					if (i < textBoxList.Count - 1)
					{
						textBoxList[i + 1].Focus();
					}
					else
					{
						OnProceedFocus(EventArgs.Empty);
					}
					Edited = true;
					break;
				}
			}
		}

		//----------// //----------// //----------// //----------//
		//
		//	Event Handlers
		//
		//----------// //----------// //----------// //----------//

		void textBox_KeyDown(object sender, KeyEventArgs e)
		{
			if ((Keys.A <= e.KeyCode) && (e.KeyCode <= Keys.Z))
			{
				e.SuppressKeyPress = true;
			}
			else if (Keys.Oem1 <= e.KeyCode)
			{
				e.SuppressKeyPress = true;
			}
		}

		/// <summary>
		/// テキストボックスからの入力を受け付ける
		/// </summary>
		void textBox_TextChanged(object sender, EventArgs e)
		{
			var box = sender as TextBox;
			var index = textBoxList.IndexOf(box);

			try
			{
				var key = Convert.ToInt32(box.Text);
				config.PadList[index] = new KeyValuePair<string, int>(config.PadList[index].Key, key);
				Edited = true;
			}
			catch
			{
				box.Text = config.PadList[index].Value.ToString();
			}
		}

		/// <summary>
		/// ゲームパッドをポーリングする
		/// </summary>
		private void tmrMain_Tick(object sender, EventArgs e)
		{
			monitor.Check();
		}

		/// <summary>
		/// ゲームパッドからの入力を受け付ける
		/// </summary>
		void PadMonitor_Pressed(object sender, DataEventArgs<int> e)
		{
			if (this.IsDisposed) return;

			padValue = e.Value;
			this.Invoke(new System.Threading.ThreadStart(SetPadValue));
		}

		//----------// //----------// //----------// //----------//
		//
		//	Properties
		//
		//----------// //----------// //----------// //----------//

		internal Control FocusTarget
		{
			get { return textBoxList[0]; }
		}
	}
}