using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Nlgp1.StageEditor.Notifies;
using System.Text.RegularExpressions;
using System.IO;
using System.Diagnostics;
using Nlgp1.StageEditor.Instances;
namespace Nlgp1.StageEditor.Controls {
	public partial class StageEditorForm : Form
	{
		private StageCreaterForm stageCreaterForm;
		private int prevGridSize;
		private float prevScale;
		private string stageDataPath;
		private string dataFolderPath = null;
		private bool canNotEvent = false;
		private bool isDirtying = false;

		private List<ToolStripMenuItem> MenuScaleItemList;

		public StageEditorForm()
		{
			InitializeComponent();

			var versionText = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
			this.Text += " ver" + versionText;

			this.stageCreaterForm = new StageCreaterForm();

			InitializeScaleMenuItem();

			this.MenuGridSizeComboBox.LostFocus += MenuGridSizeComboBox_LostFocus;
			this.MenuGridSizeComboBox.DropDownClosed += MenuGridSizeComboBox_DropDownClosed;

			this.MenuScaleTextBox.LostFocus += MenuScaleTextBox_LostFocus;
			this.MenuScaleTextBox.Click += MenuScaleTextBox_Click;

			this.MenuScaleUp.ShortcutKeyDisplayString = "+";
			this.MenuScaleDown.ShortcutKeyDisplayString = "-";

			Disposed += (sender, e) =>
			{
				Dispose();
				Application.Exit();
			};

			if (File.Exists("pathSetting.txt"))
				dataFolderPath = File.ReadAllText("pathSetting.txt").Trim();

			if (dataFolderPath == null || Directory.Exists(dataFolderPath) == false)
				dataFolderPath = Path.Combine(Application.StartupPath, "Data");

			this.Shown += new EventHandler(stageLoad_);
			this.KeyPreview = true;
		}

		private void InitializeScaleMenuItem()
		{
			int[] scales = { 300, 200, 100, 80, 50, 10, };
			string[] scaleTexts = { "&300%", "&200%", "&100%", "&80%", "&50%", "1&0%", };

			this.MenuScaleItemList = new List<ToolStripMenuItem>();
			for (int i = 0; i < scales.Length; i++)
			{
				var scaleItem = new ToolStripMenuItem();
				scaleItem.Text = scaleTexts[i];
				scaleItem.Name = "MenuScale" + scales[i];
				scaleItem.Tag = scales[i];
				scaleItem.Click += ScaleItem_Click;

				this.MenuScale.DropDownItems.Insert(0, scaleItem);
				this.MenuScaleItemList.Add(scaleItem);
			}
		}

		#region MapData_PropertyChanged
		public void MapData_PropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			var stage = (StageNotify)sender;
			if (e.PropertyName == "Create")
				SetNewStageWizard(stage);
			;
			if (e.PropertyName == "SetMapProperty")
				SetNewStageWizard(stage);
			if (e.PropertyName == "SetPath")
				stageDataPath = stage.Path;
		}

		private void SetNewStageWizard(StageNotify stage)
		{
			this.stageCreaterForm.ChipSize = stage.ChipSize;
			this.stageCreaterForm.RowNum = stage.RowNum;
			this.stageCreaterForm.ColumnNum = stage.ColumnNum;
		}

		public void EditorData_PropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			var editor = (EditorNotify)sender;
			if (e.PropertyName == "SetGridProperty")
				SetGridMenu(editor);
			if (e.PropertyName == "SetScale")
				SetScaleMenu(editor.Scale);
		}

		private void SetGridMenu(EditorNotify editor)
		{
			this.MenuVisibleGrid.Checked = editor.VisibleGrid;
			var gridSize = editor.GridSize.ToString();
			this.MenuGridSizeComboBox.Text = gridSize + "row" + gridSize;
			this.prevGridSize = editor.GridSize;
		}

		private void SetScaleMenu(float scale)
		{
			MenuScaleItemList.ForEach(item => item.Checked = false);

			var intScale = (int)Math.Round(scale * 100);
			var menuItem = MenuScaleItemList.Find(item => (int)item.Tag == intScale);
			if (menuItem != null)
			{
				menuItem.Checked = true;
				MenuScaleTextBox.Text = "直接入力";
			}
			else
			{
				MenuScaleTextBox.Text = "" + intScale + "%";
			}
			MenuScale.Text = "倍率(&S)    " + intScale + "%";
			this.prevScale = scale;
		}

		#endregion

		// TODO メニューの動作をコントローラとして別ファイルに分ける
		#region ファイルメニュー
		private void MenuNewMap_Click(object sender, EventArgs e)
		{
			this.stageCreaterForm.StageName = "new commonMap";

			var result = stageCreaterForm.ShowDialog();
			if (result != DialogResult.OK)
				return;

			var name = stageCreaterForm.StageName;
			var chipSize = stageCreaterForm.ChipSize;
			var rowNum = stageCreaterForm.RowNum;
			var columnNum = stageCreaterForm.ColumnNum;
			OnCreateNewStage(name, chipSize, rowNum, columnNum);
		}

		private void MenuOpenMap_Click(object sender, EventArgs e)
		{

			var result = OpenStageDialog.ShowDialog();
			if (result != DialogResult.OK)
				return;

			var path = OpenStageDialog.FileName;
			OnLoadStage(path);

		}

		private void MenuSaveMap_Click(object sender, EventArgs e)
		{
			if (string.IsNullOrEmpty(stageDataPath))
			{
				MenuSaveMapAs_Click(sender, e);
			}
			else
			{
				OnSaveStage(stageDataPath);
			}
		}

		private void MenuSaveMapAs_Click(object sender, EventArgs e)
		{
			var reslst = SaveStageDialog.ShowDialog();
			if (reslst != DialogResult.OK)
				return;

			var path = SaveStageDialog.FileName;
			OnSaveStage(path);
		}

		private void MenuExit_Click(object sender, EventArgs e)
		{

   			this.Close();


		}
		#endregion

		#region 表示メニュー

		#region グリッド設定
		private void MenuGridSizeComboBox_KeyDown(object sender, KeyEventArgs e)
		{
			if (e.KeyCode == Keys.Enter)
			{
				this.ViewMenuToolStripItem.HideDropDown();
			}
		}
		private void MenuGridSizeComboBox_DropDownClosed(object sender, EventArgs e)
		{
			// 検討：ドロップダウンを開いた状態で数値を入力し
			// フォーカスを失った場合入力情報が取れない
			if (MenuGridSizeComboBox.SelectedItem != null)
			{
				this.MenuGridSizeComboBox.Text = MenuGridSizeComboBox.SelectedItem.ToString();
			}
			this.ViewMenuToolStripItem.HideDropDown();
		}
		private void MenuGridSizeComboBox_LostFocus(object sender, EventArgs e)
		{
			if (prevGridSize == GetGridSize())
			{
				MenuGridSizeComboBox.Text = "" + prevGridSize + "row" + prevGridSize;
			}
			else
			{
				OnGridPropertyChanged();
			}
		}
		private int GetGridSize()
		{
			var text = MenuGridSizeComboBox.Text;
			Match match = Regex.Match(text, @"^(\d+)(row?)(\d*)$");
			if (match.Groups.Count < 2)
				return prevGridSize;
			else
				return int.Parse(match.Groups[1].Value);
		}
		private void MenuVisibleGrid_Click(object sender, EventArgs e)
		{
			OnGridPropertyChanged();
		}
		#endregion // グリッド設定

		#region 拡大縮小設定
		private void ScaleItem_Click(object sender, EventArgs e)
		{
			var checkedItem = (ToolStripMenuItem)sender;
			var scale = (int)checkedItem.Tag / 100f;
			OnScaleChanged(scale);
		}
		private void MenuScaleTextBox_KeyDown(object sender, KeyEventArgs e)
		{
			// TODO 上下キーでテキストボックスを抜けて倍率を選択できるようにする
			if (e.KeyCode == Keys.Enter)
			{
				var scale = CovertScale(MenuScaleTextBox.Text);
				this.ViewMenuToolStripItem.HideDropDown();
				OnScaleChanged(scale);
			}
		}

		private void MenuScaleTextBox_LostFocus(object sender, EventArgs e)
		{
			var isAnyChecked = MenuScaleItemList.Any(item => item.Checked);
			if (isAnyChecked == false)
			{
				var scale = CovertScale(MenuScaleTextBox.Text);
				this.ViewMenuToolStripItem.HideDropDown();
				OnScaleChanged(scale);
			}
			else
			{
				MenuScaleTextBox.Text = "直接入力";
			}
		}

		private void MenuScaleTextBox_Click(object sender, EventArgs e)
		{
			MenuScaleTextBox.SelectAll();
		}
		private float CovertScale(string scaleText)
		{
			Match match = Regex.Match(scaleText, @"^(\d+)(%?)$");
			if (match.Groups.Count < 2)
				return prevScale;
			else
				return int.Parse(match.Groups[1].Value) / 100f;
		}
		private const float ScaleAmount = 0.1f;
		private const float ScaleMax = 3.0f;
		private const float ScaleMin = 0.1f;
		private void MapEditorForm_KeyDown(object sender, KeyEventArgs e)
		{
			if (e.KeyCode == Keys.Add)
				MenuScaleUp_Click(sender, e);
			if (e.KeyCode == Keys.Subtract)
				MenuScaleDown_Click(sender, e);

			//MessageBox.Show("JJJ");
			//MessageBox.Show(MapControl.Focused.ToString());

		}
		private void MenuScaleUp_Click(object sender, EventArgs e)
		{
			var scale = prevScale + ScaleAmount;
			scale = (float)Math.Min(scale, ScaleMax);
			OnScaleChanged(scale);
		}
		private void MenuScaleDown_Click(object sender, EventArgs e)
		{
			var scale = prevScale - ScaleAmount;
			scale = (float)Math.Max(scale, ScaleMin);
			OnScaleChanged(scale);
		}

		#endregion // 拡大縮小設定

		#endregion // 表示メニュー

		#region 編集メニュー
		private void MenuShiftLeft_Click(object sender, EventArgs e)
		{
			OnLayerShift("Left");
		}

		private void MenuShiftRight_Click(object sender, EventArgs e)
		{
			OnLayerShift("Right");
		}

		private void MenuShiftUp_Click(object sender, EventArgs e)
		{
			OnLayerShift("Up");
		}

		private void MenuShiftDown_Click(object sender, EventArgs e)
		{
			OnLayerShift("Down");
		}
		#endregion // 編集メニュー

		#region CreateNewStage
		public event CreateNewStageEventHandler CreateNewStage;
		public void OnCreateNewStage(string name, int chipSize, int row, int column)
		{
			if (CreateNewStage == null)
				return;

			var e = new CreateNewStageEventArgs(name, chipSize, row, column);
			CreateNewStage(this, e);
		}

		public delegate void CreateNewStageEventHandler(object sender, CreateNewStageEventArgs e);
		public class CreateNewStageEventArgs : EventArgs
		{
			public string Name
			{
				get;
				private set;
			}
			public int ChipSize
			{
				get;
				private set;
			}
			public int RowNum
			{
				get;
				private set;
			}
			public int ColumnNum
			{
				get;
				private set;
			}

			public CreateNewStageEventArgs(string name, int chipSize, int row, int column)
			{
				this.Name = name;
				this.ChipSize = chipSize;
				this.RowNum = row;
				this.ColumnNum = column;
			}
		}
		#endregion

		#region FileOpen
		public event FileOpenEventHander SaveStage;
		public void OnSaveStage(string path)
		{
			if (SaveStage == null)
				return;

			var e = new FileOpenEventArgs(path);
			SaveStage(this, e);
		}

		public event FileOpenEventHander LoadStage;
		public void OnLoadStage(string path)
		{
			if (LoadStage == null)
				return;

			var e = new FileOpenEventArgs(path);
			LoadStage(this, e);
		}

		public delegate void FileOpenEventHander(object sender, FileOpenEventArgs e);
		public class FileOpenEventArgs : EventArgs
		{
			public string Path
			{
				get;
				private set;
			}
			public FileOpenEventArgs(string path)
			{
				this.Path = path;
			}
		}
		#endregion

		#region GridPropertyChenged
		public event GridPropertyChengedEventHander GridPropertyChenged;
		public void OnGridPropertyChanged()
		{
			if (GridPropertyChenged == null)
				return;

			var e = new GridPropertyChengedEventArgs(
 				this.MenuVisibleGrid.Checked,
 				this.GetGridSize(),
 				Color.Black);
			GridPropertyChenged(this, e);
		}

		public delegate void GridPropertyChengedEventHander(object sender, GridPropertyChengedEventArgs e);
		public class GridPropertyChengedEventArgs : EventArgs
		{
			public bool Visible
			{
				get;
				private set;
			}
			public int Size
			{
				get;
				private set;
			}
			public Color Color
			{
				get;
				private set;
			}

			public GridPropertyChengedEventArgs(bool visible, int size, Color color)
			{
				this.Visible = visible;
				this.Size = size;
				this.Color = color;
			}
		}
		#endregion // GridPropertyChenged

		#region ScaleChenged
		public event ScaleChengedEventHander ScaleChenged;
		public void OnScaleChanged(float scale)
		{
			if (ScaleChenged == null)
				return;

			var e = new ScaleChengedEventArgs(scale);
			ScaleChenged(this, e);
		}

		public delegate void ScaleChengedEventHander(object sender, ScaleChengedEventArgs e);
		public class ScaleChengedEventArgs : EventArgs
		{
			public float Scale
			{
				get;
				private set;
			}

			public ScaleChengedEventArgs(float scale)
			{
				this.Scale = scale;
			}
		}
		#endregion // ScaleChenged

		#region LayerShift
		public event LayerShiftEventHander LayerShift;
		public void OnLayerShift(string direction)
		{
			if (LayerShift == null)
				return;

			var e = new LayerShiftEventArgs(direction);
			LayerShift(this, e);
		}

		public delegate void LayerShiftEventHander(object sender, LayerShiftEventArgs e);
		public class LayerShiftEventArgs : EventArgs
		{
			public string Direction
			{
				get;
				private set;
			}

			public LayerShiftEventArgs(string direction)
			{
				this.Direction = direction;
			}
		}
		#endregion // ScaleChenged

		private string CurrentStagePath
		{
			get
			{
				return Path.Combine(dataFolderPath, string.Format("Stages\\Stage{0}.xml", int.Parse(label2.Text)));
			}
		}
		private string NextStagePath
		{
			get
			{
				return Path.Combine(dataFolderPath, string.Format("Stages\\Stage{0}.xml", (int)stageNumber.Value));
			}
		}
		private void stageLoad_Click(object sender, EventArgs e)
		{
			if (this.isDirtying)
			{
				var response = MessageBox.Show("新しくステージ読み込む前にセーブしときましょうよ？", "確認", MessageBoxButtons.YesNoCancel);

				if (response == DialogResult.Cancel)
				{
					return;
				}
				else if (response == DialogResult.Yes)
				{
					OnSaveStage(CurrentStagePath);
					MessageBox.Show("セーブしました");//余計かもしらん
				}
				this.isDirtying = false;
			}



			if (File.Exists(NextStagePath))
			{
				OnLoadStage(NextStagePath);
				label2.Text = string.Format("{0}", (int)stageNumber.Value);
				if (StageInstance.Stage != null)
				{
					canNotEvent = true;
					yMapSize.Value = StageInstance.Stage.RowNum;
					xMapSize.Value = StageInstance.Stage.ColumnNum;
					canNotEvent = false;
				}
			}
		}
		private void stageLoad_(object sender, EventArgs e)
		{
			if (File.Exists(NextStagePath))
			{
				OnLoadStage(NextStagePath);
				label2.Text = string.Format("{0}", (int)stageNumber.Value);
				if (StageInstance.Stage != null)
				{
					canNotEvent = true;
					yMapSize.Value = StageInstance.Stage.RowNum;
					xMapSize.Value = StageInstance.Stage.ColumnNum;
					canNotEvent = false;
				}
			}
		}

		private void stageSave_Click(object sender, EventArgs e)
		{
			OnSaveStage(CurrentStagePath);
			MessageBox.Show("セーブしました");//余計かもしらん
		}

		private void chipSet_SelectedValueChanged(object sender, EventArgs e)
		{
			StageInstance.Editor.CurrentLayer.ChipsetPath = "";
		}

		private void newMap_Click(object sender, EventArgs e)
		{
			if (this.isDirtying)
			{
				var response = MessageBox.Show("新しくステージ読み込む前にセーブしときましょうよ？", "確認", MessageBoxButtons.YesNoCancel);

				if (response == DialogResult.Cancel)
				{
					return;
				}
				else if (response == DialogResult.Yes)
				{
					OnSaveStage(CurrentStagePath);
					MessageBox.Show("セーブしました");//余計かもしらん
				}
				this.isDirtying = false;
			}
			foreach (var layer in StageInstance.Stage.LayerList)
			{
				for (int i = 0; i < layer.Map.GetLength( 0 ); i++)
				{
					for (int j = 0; j < layer.Map.GetLength( 1 ); j++)
					{
						layer.Map[ i , j ] = layer.ChipTable[ 0 ];
					}
				}
			}
			StageInstance.Stage.OnPropertyChanged("Refresh");
			label2.Text = string.Format("{0}", (int)stageNumber.Value);
		}

		private void xSize_ValueChanged(object sender, EventArgs e)
		{
			if (canNotEvent)
				return;
			var x = yMapSize.Value - (decimal)StageInstance.Stage.ColumnNum;
			var y = xMapSize.Value - (decimal)StageInstance.Stage.RowNum;

			StageInstance.Stage.ColumnNum += (int)x;
			StageInstance.Stage.RowNum += (int)y;

			foreach (var layer in StageInstance.Stage.LayerList)
			{
				var sourceMap = layer.Map;
				var targetMap = new LayerChipNotify[StageInstance.Stage.RowNum, StageInstance.Stage.ColumnNum];
				for (int i = 0; i < targetMap.GetLength(0); ++i) {
					for (int j = 0; j < targetMap.GetLength(1); ++j) {
						if (targetMap.GetLength(0) <= sourceMap.GetLength(0) && targetMap.GetLength(1) <= sourceMap.GetLength(1)) {
							targetMap[i, j] = sourceMap[i, j];
						}
						else {
							targetMap[i, j] = layer.ChipTable[0];
						}
					}
				}
				layer.SetMap(targetMap);
			}
			StageInstance.Stage.OnPropertyChanged("UpdateSize");
		}

		private void dataDirectoryChange_Click(object sender, EventArgs e)
		{
			using (FolderBrowserDialog dia = new FolderBrowserDialog())
			{
				dia.SelectedPath = dataFolderPath;
				dia.ShowNewFolderButton = false;
				dia.Description = "Dataディレクトリを選択して下さい。";
				if (dia.ShowDialog() == System.Windows.Forms.DialogResult.OK)
				{
					if (Directory.Exists(Path.Combine(dia.SelectedPath, "Stages")))
					{
						dataFolderPath = dia.SelectedPath;
						File.WriteAllText("pathSetting.txt", dataFolderPath);
					}
					else
					{
						MessageBox.Show(string.Format("{0}は、正しくないディレクトリです。選択し直して下さい。", dia.SelectedPath));
					}
				}
			}
		}

		private void stageNumber_ValueChanged(object sender, EventArgs e)
		{
			stageLoad.Enabled = File.Exists(NextStagePath);
		}

		private void chipSetCreate_Click(object sender, EventArgs e)
		{
			new MotionImageCreaterForm().Show();
		}

		private void TestplayButton_Click(object sender, EventArgs e)
		{
			// 指定したパスから親ディレクトリの DirectoryInfo を取得する
			DirectoryInfo hDirInfo = System.IO.Directory.GetParent(NextStagePath);
			// DirectoryInfo から親ディレクトリの DirectoryInfo を取得する
			hDirInfo = hDirInfo.Parent;
			hDirInfo = hDirInfo.Parent;
			string gamePath = hDirInfo.FullName;
#if DEBUG
			gamePath = Path.Combine(gamePath, "Nlgp1\\bin\\x86\\Debug\\Nlgp1.exe");
#else
			gamePath = Path.Combine(gamePath, "Nlgp1\\bin\\x86\\Release\\Nlgp1.exe");
#endif
			// 親ディレクトリの名前を表示する
			//MessageBox.Show(gamePath);
			//Process.Start(gamePath);
			// プロセスの終了を待つ方法 - 1 -
			//Process Exec1 = Process.Start(gamePath);
			//Exec1.EnableRaisingEvents = true;
			//Exec1.Exited += new EventHandler(Exec_Exited);
			// プロセス終了時にExec_Exitedが呼ばれる
			// プロセスの終了を待つ方法 - 2 -
			Process Exec2 = Process.Start(gamePath, string.Format("\"{0}\" \"{1}\"", Path.Combine(hDirInfo.FullName, "Data"), stageNumber.Value));
			Exec2.WaitForExit();
			// プロセス終了までWaitForExit()が返ってこない



		}

		private void ShowStagePathButton_Click(object sender, EventArgs e)
		{
			MessageBox.Show(NextStagePath);
		}

		private void MapEditorForm_Load(object sender, EventArgs e)
		{

		}


		private void MainMenu_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
		{

		}

		private void MapEditorForm_FormClosing(object sender, FormClosingEventArgs e)
		{



			if (this.isDirtying)
			{
   			var response = MessageBox.Show("終了前にステージをセーブしときますか？", "確認", MessageBoxButtons.YesNoCancel);

   			if (response == DialogResult.Cancel)
				{
					e.Cancel = true;
					return;
				}
   			else if (response == DialogResult.Yes)
   			{
   				OnSaveStage(CurrentStagePath);
   				MessageBox.Show("セーブしました");//余計かもしらん
   			}
				this.isDirtying = false;
			}


		}

		private void ChipListView_Load(object sender, EventArgs e)
		{

		}

		private void label2_Click(object sender, EventArgs e)
		{

		}

		private void ChipGridView_Load(object sender, EventArgs e)
		{

		}




		private void ChipGridView_KeyDown(object sender, KeyEventArgs e)
		{

			/*MessageBox.Show("WWW");
			MapControl.Focus();
			MessageBox.Show(MapControl.Focused.ToString());*/
		}

		private void ChipGridView_KeyPress(object sender, KeyPressEventArgs e)
		{

		}

		private void ChipGridView_KeyUp(object sender, KeyEventArgs e)
		{

		}

		private void ChipGridView_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
		{

		}

		private void MapEditorForm_KeyUp(object sender, KeyEventArgs e)
		{

		}




	}
}
