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 System.IO;
using System.Xml.Serialization;
using System.Diagnostics;
using CmdHelper.Properties;

namespace CmdHelper
{
	public partial class MainForm : Form
	{
		public MainForm()
		{
			InitializeComponent();

			checkBoxCui.Checked = true;

			Settings.Default.Reload();

			if (null != Settings.Default.exeFiles)
			{
				foreach (string s in Settings.Default.exeFiles)
				{
					if(!string.IsNullOrEmpty(s))
						this.comboBoxExe.Items.Add(s);
				}
			}
		}

		enum Column
		{
			Param,
		}

		const string filter = @"XMLファイル(*.xml)|*.xml|全てのファイル(*.*)|*.*";

		private void openToolStripMenuItem_Click(object sender, EventArgs e)
		{
			openFileDialog.FileName = string.Empty;
			openFileDialog.Filter = filter;
			openFileDialog.FilterIndex = 0;

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

			CmdSetting cmd = Open(openFileDialog.FileName);

			SetExe(cmd.exe);

			dataGridViewParams.Rows.Clear();
			dataGridViewParams.RowCount = cmd.param.Length;

			int index = 0;
			foreach (string s in cmd.param)
			{
				dataGridViewParams[(int)Column.Param, index++].Value = s;
			}

			this.checkBoxCui.Checked = cmd.cui;

		}

		CmdSetting Open(string filePath)
		{
			XmlSerializer serializer = new XmlSerializer(typeof(CmdSetting));

			//ファイルを開く
			using (FileStream fs = new FileStream(filePath, FileMode.Open))
			{
				//シリアル化し、XMLファイルに保存する
				return (CmdSetting)serializer.Deserialize(fs);
			}
		}

		CmdSetting GetCmdSetting()
		{
			CmdSetting cmd = new CmdSetting();
			cmd.exe = this.comboBoxExe.Text;
			cmd.param = new string[dataGridViewParams.Rows.Count];
			cmd.cui = checkBoxCui.Checked;

			int index = 0;
			foreach (DataGridViewRow row in dataGridViewParams.Rows)
			{
				cmd.param[index++] = (row.Cells[(int)Column.Param].Value != null) ? row.Cells[(int)Column.Param].Value.ToString() : "";
			}

			return cmd;
		}


		private void saveToolStripMenuItem_Click(object sender, EventArgs e)
		{
			saveFileDialog.Filter = filter;
			saveFileDialog.FilterIndex = 0;

			DialogResult result = saveFileDialog.ShowDialog();

			if (result != DialogResult.OK)
				return;

			dataGridViewParams.EndEdit();

			CmdSetting cmd = GetCmdSetting();

			Save(cmd, saveFileDialog.FileName);
		}

		void Save(CmdSetting cmd, string filePath)
		{
			XmlSerializer serializer = new XmlSerializer(typeof(CmdSetting));

			//ファイルを開く
			using (FileStream fs = new FileStream(filePath, FileMode.Create))
			{
				//シリアル化し、XMLファイルに保存する
				serializer.Serialize(fs, cmd);
			}
		}

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

		const int MAX_CMB_SIZE_ = 10;

		void SetExe(string exePath)
		{
			if (string.IsNullOrEmpty(exePath))
				return;
			this.comboBoxExe.Text = exePath;
			if (!this.comboBoxExe.Items.Contains(exePath))
			{
				this.comboBoxExe.Items.Add(exePath);
				if (this.comboBoxExe.Items.Count > MAX_CMB_SIZE_)
					this.comboBoxExe.Items.RemoveAt(0);
			}
		}

		private void buttonFile_Click(object sender, EventArgs e)
		{
			DialogResult result = this.openFileDialog.ShowDialog();

			if( string.IsNullOrEmpty(this.comboBoxExe.Text) == false ){
				this.openFileDialog.InitialDirectory = Path.GetDirectoryName(this.comboBoxExe.Text);
			}
			if (result != DialogResult.OK)
				return;
			SetExe(this.openFileDialog.FileName);
		}

		private void buttonExec_Click(object sender, EventArgs e)
		{
			dataGridViewParams.EndEdit();

			CmdSetting cmd = GetCmdSetting();

			Exec(cmd);
		}

		string execStdout;
		string execStdError;

		void Exec(CmdSetting cmd)
		{
			try
			{
				Cursor.Current = Cursors.WaitCursor;

				if (string.IsNullOrEmpty(cmd.exe))
				{
					throw new ApplicationException("no exe");
				}

				StringBuilder sb = new StringBuilder();
				foreach (string s in cmd.param)
				{
					sb.Append(s);
					sb.Append(' ');
				}

				execStdout = string.Empty;
				execStdError = string.Empty;

				if (cmd.cui)
				{

					//コマンドライン用
					using (Process p = new Process())
					{
						p.StartInfo.UseShellExecute = false;
						p.StartInfo.RedirectStandardOutput = true;
						p.StartInfo.RedirectStandardError = true;

						p.StartInfo.FileName = cmd.exe;
						p.StartInfo.Arguments = sb.ToString().TrimEnd();

						p.StartInfo.CreateNoWindow = true;
						p.Start();

						do
						{
							Application.DoEvents();

						} while (!p.HasExited);


						execStdout = p.StandardOutput.ReadToEnd();
						execStdError = p.StandardError.ReadToEnd();
					}
				}
				else
				{
					//GUI用
					Process.Start(cmd.exe, sb.ToString().TrimEnd());
				}
			}
			catch (Exception exp)
			{
				MessageBox.Show(exp.Message);
			}
			finally
			{
				Cursor.Current = Cursors.Default;
			}
		}

		private void comboBoxExe_DragEnter(object sender, DragEventArgs e)
		{
			if (e.Data.GetDataPresent(DataFormats.FileDrop))
				e.Effect = DragDropEffects.All;
			else
				e.Effect = DragDropEffects.None;
		}

		private void comboBoxExe_DragDrop(object sender, DragEventArgs e)
		{
			string[] s = (string[])e.Data.GetData(DataFormats.FileDrop, false);
			if (s.Length > 0 && string.IsNullOrEmpty(s[0]) == false)
			{
				SetExe(s[0]);
			}
		}

		private void addToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if (dataGridViewParams.SelectedRows.Count < 1)
			{
				dataGridViewParams.RowCount += 1;
				return;
			}
			dataGridViewParams.Rows.Insert(dataGridViewParams.SelectedRows[dataGridViewParams.SelectedRows.Count-1].Index, 1);
		}

		public int Compare(int x, int y)
		{
			return y - x; 
		}

		private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if (dataGridViewParams.SelectedRows.Count < 1)
				return;

			List<int> rows = new List<int>();
			foreach (DataGridViewRow row in dataGridViewParams.SelectedRows)
			{
				rows.Add(row.Index);
			}

			rows.Sort(this.Compare);
			foreach (int i in rows)
			{
				dataGridViewParams.Rows.RemoveAt(i);
			}
		}


		/// <summary>
		/// ドロップ先の行の決定
		/// </summary>
		/// <param name="view"></param>
		/// <param name="e"></param>
		/// <returns></returns>
		public static int DecideDropDestinationRowIndex(
			DataGridView view
			, DragEventArgs e
		)
		{
			Point clientPoint = view.PointToClient(new Point(e.X, e.Y));

			// 上下のみに着目するため、横方向は無視する
			//clientPoint.X = 1;

			DataGridView.HitTestInfo hit = view.HitTest(clientPoint.X, clientPoint.Y);

			int dstIndex = 0;
			if (hit.ColumnIndex == -1 ||
				hit.RowIndex == -1)
				dstIndex = -1;
			else
				dstIndex = hit.RowIndex;

			if (dstIndex < 0)
			{
				int top = (view.ColumnHeadersVisible ? view.ColumnHeadersHeight : 0) + 1;
				if (top > clientPoint.Y)
					// ヘッダへのドロップ時は表示中の先頭行とする
					dstIndex = view.FirstDisplayedCell.RowIndex;
				else
					// ヘッダ以外は新規追加
					dstIndex = view.Rows.Count;
			}
			return dstIndex;
		}


		private void dataGridViewParams_DragDrop(object sender, DragEventArgs e)
		{
			// Drop先カラム
			Point clientPoint = dataGridViewParams.PointToClient(new Point(e.X, e.Y));
			DataGridView.HitTestInfo hit = dataGridViewParams.HitTest(clientPoint.X, clientPoint.Y);

			//すでにある行にファイルを追加するとき、
			//ScnFilePath or CompareFilePathカラム以外にドロップしていた場合は、
			//何もしないようにする。
			if (hit.RowIndex < 0 || (hit.ColumnIndex != (int)Column.Param))
				return;

			string[] files = (string[])e.Data.GetData(DataFormats.FileDrop, false);
			if (files.Length < 1)
				return;

			//昇順ソート
			Array.Sort(files);

			int firstItemIndex = DecideDropDestinationRowIndex(dataGridViewParams, e);
			if (firstItemIndex == -1)
				return;

			int newCount = firstItemIndex + files.Length;
			int nowCount = dataGridViewParams.RowCount;

			if (nowCount < newCount)
			{
				//今ある行には収まりきらないので、足りない分を追加する。
				dataGridViewParams.RowCount += newCount - nowCount;
			}

			int f = 0;
			for (int i = firstItemIndex; i < newCount; i++)
			{
				dataGridViewParams[(int)Column.Param,i].Value = files[f++];
			}

		}

		private void dataGridViewParams_DragEnter(object sender, DragEventArgs e)
		{
			if (e.Data.GetDataPresent(DataFormats.FileDrop))
				e.Effect = DragDropEffects.All;
			else
				e.Effect = DragDropEffects.None;
		}

		private void checkBoxCui_CheckedChanged(object sender, EventArgs e)
		{
			if (checkBoxCui.Checked)
			{
				buttonStdiou.Visible = true;
			}
			else
			{
				buttonStdiou.Visible = false;
			}
		}

		private void buttonStdiou_Click(object sender, EventArgs e)
		{
			StringBuilder sb = new StringBuilder();
			sb.Append(execStdout);
			sb.Append(Environment.NewLine);

			if (string.IsNullOrEmpty(execStdError))
			{
				sb.Append("no error output.");
			}
			else
			{
				sb.Append(execStdError);
			}
			sb.Append(Environment.NewLine);

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

		private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
		{
			Settings.Default.exeFiles.Clear();

			foreach (string s in this.comboBoxExe.Items)
			{
				Settings.Default.exeFiles.Add(s);
			}

			Settings.Default.Save();
		}
	}
}
