using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
using KeyConfig.Config;
using KeyConfig.Map;

namespace KeyConfig
{
	public partial class frmMain : Form
	{
		//----------// //----------// //----------// //----------//
		//
		//	Constructor
		//
		//----------// //----------// //----------// //----------//

		public frmMain()
		{
			InitializeComponent();
			Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
		}

		private void frmMain_Load(object sender, EventArgs e)
		{
			Program.WriteLog("# frmMain_Load");
			Program.WriteLog("	JoyPad.ctor");
			pad = new JoyPad(this.Handle.ToInt32());
			Program.WriteLog("	InitializeEditor");
			InitializeEditor();
			Program.WriteLog("	SetActiveControl");
			this.ActiveControl = keyEditor.FocusTarget;
			Program.WriteLog("###");
		}

		//----------// //----------// //----------// //----------//
		//
		//	Destructor
		//
		//----------// //----------// //----------// //----------//

		private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
		{
			if (!initFailed)
			{
				if (Edited)
				{
					DialogResult dr = MessageBox.Show("保存しないで終了しますか？", "確認", MessageBoxButtons.OKCancel);

					if (dr != DialogResult.OK)
					{
						e.Cancel = true;
					}
				}
			}
			if (!e.Cancel)
			{
				pad.Dispose();
				Program.CloseLog();
			}
		}

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

		//----------// Config

		internal static IKeyConfigPath Files = new KeyConfigPath();
		ConfigData config = new ConfigData();
		JoyPad pad;

		//----------// Controls

		KeyEditor keyEditor;
		PadEditor padEditor;
		ScreenEditor screenEditor;

		//----------// Global Settings

		KeyMap keyMap = null;

		//----------// Window

		frmPad padWindow = null;

		//----------// Flags

		bool initFailed = false;

		//----------// //----------// //----------// //----------//
		//
		//	Methods (private)
		//
		//----------// //----------// //----------// //----------//

		private void InitializeEditor()
		{
			Program.WriteLog("# InitializeEditor");
			try
			{
				Program.WriteLog("	ReadConfig");
				config = ConfigReader.ReadFrom(Files.Config);
				Program.WriteLog("	ReadDictionary");
				keyMap = KeyMapReader.ReadFrom(Files.Dictionary);
				Program.WriteLog("	CreateComponents");
				CreateComponents();
			}
			catch (Exception ex)
			{
				Program.WriteLog(ex.ToString());
#if !DEBUG
				MessageBox.Show("初期化に失敗しました。");
#else
				MessageBox.Show(ex.ToString());
#endif
				initFailed = true;
				Application.Exit();
			}
			Program.WriteLog("###");
		}

		const int keyLeft = 8;
		const int padLeft = 200;

		const int labelTop = 32;

		const int labelWidth = 88;
		const int labelHeight = 24;
		const int textWidth = 64;

		const int keyTextLeft = keyLeft + labelWidth;
		const int padTextLeft = padLeft + labelWidth;

		private void CreateComponents()
		{
			Program.WriteLog("# CreateComponents");
			Program.WriteLog("	CreateKeyEditor");
			CreateKeyEditor();
			Program.WriteLog("	CreatePadEditor");
			CreatePadEditor();
			Program.WriteLog("	CreateScreenEditor");
			CreateScreenEditor();

			Program.WriteLog("	Other");

			this.ClientSize = new Size(screenEditor.Right + 8, keyEditor.Bottom + 8);

			btnOK.Left = this.ClientSize.Width - btnOK.Width - 8;
			btnOK.Top = this.ClientSize.Height - btnOK.Height - 8;

			btnCancel.Left = btnOK.Left - btnCancel.Width - 8;
			btnCancel.Top = btnOK.Top;

			btnCheck.Left = btnCancel.Left - btnCheck.Width - 16;
			btnCheck.Top = btnOK.Top;

			Program.WriteLog("###");
		}

		private void CreateKeyEditor()
		{
			keyEditor = new KeyEditor()
			{
				Left = 8,
				Top = 8
			};
			keyEditor.InitializeEditor(config, keyMap, labelWidth, textWidth, labelHeight);
			keyEditor.EditedChanged += new EventHandler(EditorBase_EditedChanged);
			keyEditor.ProceedFocus += new EventHandler(keyEditor_ProceedFocus);
			this.Controls.Add(keyEditor);
		}

		private void CreatePadEditor()
		{
			padEditor = new PadEditor()
			{
				Left = 200,
				Top = 8
			};
			padEditor.InitializeEditor(config, keyMap, pad, labelWidth, textWidth, labelHeight);
			padEditor.EditedChanged += new EventHandler(EditorBase_EditedChanged);
			padEditor.ProceedFocus += new EventHandler(padEditor_ProceedFocus);
			this.Controls.Add(padEditor);
		}

		private void CreateScreenEditor()
		{
			screenEditor = new ScreenEditor()
			{
				Left = 392,
				Top = 8
			};
			screenEditor.InitializeEditor(config);
			screenEditor.EditedChanged += new EventHandler(EditorBase_EditedChanged);

			this.Controls.Add(screenEditor);
		}

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

		void EditorBase_EditedChanged(object sender, EventArgs e)
		{
			if (Edited)
			{
				this.Text = "環境カスタムプログラム *";
			}
			else
			{
				this.Text = "環境カスタムプログラム";
			}
		}

		void keyEditor_ProceedFocus(object sender, EventArgs e)
		{
			padEditor.FocusTarget.Focus();
		}

		void padEditor_ProceedFocus(object sender, EventArgs e)
		{
			screenEditor.FocusTarget.Focus();
		}

		private void btnOK_Click(object sender, EventArgs e)
		{
			try
			{
				var fs = new FileStream(Path.Combine(Application.StartupPath, "CONFIG.INI"), FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
				var cw = new ConfigWriter(fs);

				cw.Write(config);

				cw.Close();

				Edited = false;
				MessageBox.Show("保存しました。");
				this.Close();
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.Message);
			}
		}

		private void btnCancel_Click(object sender, EventArgs e)
		{
			this.Close();
		}

		private void btnCheck_Click(object sender, EventArgs e)
		{
			if ((padWindow == null) || (padWindow.IsDisposed))
			{
				padWindow = new frmPad();
				padWindow.InitializeEditor(pad);
			}
			padWindow.Show();
			padWindow.BringToFront();
		}

		void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
		{
			MessageBox.Show(e.Exception.ToString());
			initFailed = true;
			Application.Exit();
		}

		internal bool Edited
		{
			get
			{
				return keyEditor.Edited || padEditor.Edited || screenEditor.Edited;
			}
			set
			{
				keyEditor.Edited = padEditor.Edited = screenEditor.Edited = value;
			}
		}
	}
}