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 ClipClop.User;
using System.Xml;
using System.Diagnostics;
using System.IO;
using CaLib.User;

namespace ClipClop.View
{
	//TODO ○定型文アイコン指定を可能にする
	//TODO bDutyFlag_ は沢山抜けているはずなので使わず、オリジナルと比較したら？

	/// <summary>
	/// 定型文定義ダイアログ。
	/// </summary>
    public partial class TemplateSetting : Form
    {
		XmlCipheredDocument doc_;

		XmlNode xmlNodeCopied_ = null;

		readonly string templateFilePath_;

		bool bDutyFlag_ = false;

		public XmlCipheredDocument Document
		{
			get
			{
				return this.doc_;
			}
		}

		string passwordString_;

        public string PasswordString { get { return this.passwordString_; } }

        public TemplateSetting()
        {
            InitializeComponent();

            FormUtil.GeometryFromString(Properties.Settings.Default.WindowGeometryTemplateSetting, this);

			//アイテムをユーザーが編集できるようにする
			this.treeView.LabelEdit = true;

			UpdateEncrypted();
        }

		public TemplateSetting(string templateFilePath, string passwordString)
		{
			InitializeComponent();
            FormUtil.GeometryFromString(Properties.Settings.Default.WindowGeometryTemplateSetting, this);

			passwordString_ = passwordString;
			templateFilePath_ = templateFilePath;

			//アイテムをユーザーが編集できるようにする
			this.treeView.LabelEdit = true;
		}

		private void TemplateSetting_Load(object sender, EventArgs e)
		{
			try
			{
				this.Cursor = Cursors.WaitCursor;

				XmlContextMenuReader reader = new XmlContextMenuReader();
				reader.Read(templateFilePath_);

				XmlCipheredDocument tempDoc = reader.GetDocument();

				if (tempDoc.IsEncrypted())
				{
					if (string.IsNullOrEmpty(passwordString_))
					{
						if (!PasswordForm.ShowInputPassword(ref passwordString_))
						{
							//暗号化するのにパスワードを入れないなら、変更を破棄する
							throw new FundamentalException(global::ClipClop.Properties.Resources.EF010);
						}
					}
					tempDoc.Decrypt(passwordString_);
				}

				this.doc_ = tempDoc;

				this.treeView.Setup(this.doc_);
			}
			catch (Exception exp)
			{
				doc_ = null;
				Util.ShowError(global::ClipClop.Properties.Resources.EF005 + Environment.NewLine + exp.Message);
			}
			finally
			{
				UpdateEncrypted();
				this.Cursor = Cursors.Default;
			}
		}

		/// <summary>
		/// Formの表示を初期化する
		/// </summary>
		void Initialize()
		{
			doc_ = null;

			this.treeView.Nodes.Clear();

			this.textBox.Text = string.Empty;
		}

		/// <summary>
		/// QT Clipの設定ファイルをインポートする
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void importToolStripMenuItem_Click_1(object sender, EventArgs e)
		{
			string filePath;

			using (OpenFileDialog fd = new OpenFileDialog())
			{
				fd.FileName = "QTCLIP.TXT";
				fd.Filter = "TEXTファイル(*.TXT)|*.TXT|すべてのファイル(*.*)|*.*";
                fd.InitialDirectory = string.IsNullOrEmpty(ClipClop.Properties.Settings.Default.InitialDirectoryImportFile) ?
                    string.Empty : ClipClop.Properties.Settings.Default.InitialDirectoryImportFile;                

				DialogResult result = fd.ShowDialog();
				if (result != DialogResult.OK)
					return;
				filePath = fd.FileName;
                ClipClop.Properties.Settings.Default.InitialDirectoryImportFile = Path.GetDirectoryName(fd.FileName);

			}

			try
			{
				this.Cursor = Cursors.WaitCursor;

				QtClipContextMenuReader reader = new QtClipContextMenuReader();

				reader.Read(filePath);

				// Formの表示を初期化する
				Initialize();

				this.doc_ = reader.GetDocument();

				this.treeView.Setup(this.doc_);

				UpdateEncrypted();
			}
			catch (Exception exp)
			{
				Util.ShowError(global::ClipClop.Properties.Resources.EF005 + Environment.NewLine + exp.Message);
			}
			finally
			{
				this.Cursor = Cursors.Default;
			}

		}

		private void treeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
		{
			TemplateSettingTreeNode node = e.Node as TemplateSettingTreeNode;

			if (node == null)
			{
				this.textBox.Text = string.Empty;
				UpdateContextMenu(false, node);
			}
			else
			{
				this.textBox.Text = node.DispalyValue;
				UpdateContextMenu(true, node);
			}
		}

		private void treeView_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
		{
			TemplateSettingTreeNode tsnode = e.Node as TemplateSettingTreeNode;
			if (tsnode == null)
			{
				return;
			}

			Debug.WriteLine(tsnode.ToString());

			TemplateSettingTreeNode node = (TemplateSettingTreeNode)e.Node;

			if (node.SettingType != ContextMenuSettingDefinition.SettingType.sentence )
			{
				//編集できるのは、定型文のみ。
				return;
			}

			try
			{
				// ダイアログを表示する。
				using (TemplateItemForm form = new TemplateItemForm(node.Mode, node.DispalyName, node.DispalyValue))
				{
					form.StartPosition = FormStartPosition.Manual;
					form.Location = Control.MousePosition;

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

					if (!node.EditAttribute(form.Mode, form.DispName, form.DispValue, this.doc_))
					{
						throw new FundamentalException(global::ClipClop.Properties.Resources.EA001);
					}

					node.Text = node.DispalyName;
					this.bDutyFlag_ = true;
				}
			}
			catch (Exception exp)
			{
				Util.ShowError(exp.Message);
			}

			this.textBox.Text = node.DispalyValue;
		}


		/// <summary>
		/// 定型文定義ファイルを開く
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void openOToolStripMenuItem_Click(object sender, EventArgs e)
		{
			string filePath;

			using (OpenFileDialog fd = new OpenFileDialog())
			{
				fd.FileName = Path.GetFileName(this.templateFilePath_);
				fd.Filter = "XMLファイル(*.XML)|*.XML|すべてのファイル(*.*)|*.*";
                fd.InitialDirectory = string.IsNullOrEmpty(ClipClop.Properties.Settings.Default.InitialDirectoryXmlFile) ?
                    string.Empty : ClipClop.Properties.Settings.Default.InitialDirectoryXmlFile;


				DialogResult result = fd.ShowDialog();
				if (result != DialogResult.OK)
					return;
				filePath = fd.FileName;
                ClipClop.Properties.Settings.Default.InitialDirectoryXmlFile = Path.GetDirectoryName(fd.FileName);
			}

			try
			{
				this.Cursor = Cursors.WaitCursor;

				XmlContextMenuReader reader = new XmlContextMenuReader();

				reader.Read(filePath);

				// Formの表示を初期化する
				Initialize();

				XmlCipheredDocument tempDoc = reader.GetDocument();

				//IsEncryptedはXmlCipheredDocumentのメンバにする
				if (tempDoc.IsEncrypted())
				{
					string pwd = string.Empty;
					if (!PasswordForm.ShowInputPassword(ref pwd))
					{
						throw new FundamentalException(global::ClipClop.Properties.Resources.EF010);
					}
					tempDoc.Decrypt(pwd);
				}

				this.doc_ = tempDoc;

				this.treeView.Setup(this.doc_);

				UpdateEncrypted();

			}
			catch (Exception exp)
			{
				Util.ShowError(global::ClipClop.Properties.Resources.EF005 + Environment.NewLine + exp.Message);
			}
			finally
			{
				this.Cursor = Cursors.Default;
			}
		}

		#region TreeViewアイテム名の変更

		/// <summary>
		/// キーが離れた時
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void treeView_KeyUp(object sender, KeyEventArgs e)
		{
			//F2キーが離されたときは、フォーカスのあるアイテムの編集を開始
			if (e.KeyCode == Keys.F2 && this.treeView.SelectedNode != null)
			{
				this.treeView.SelectedNode.BeginEdit();
			}
		}

		/// <summary>
		/// アイテムのラベルの編集が開始された時
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void treeView_BeforeLabelEdit(object sender, NodeLabelEditEventArgs e)
		{
			//ルートアイテムは編集できないようにする
			TemplateSettingTreeNode node = e.Node as TemplateSettingTreeNode;

			if (node == null || node.IsRoot())
				e.CancelEdit = true;
			else
				e.CancelEdit = false;
		}

		/// <summary>
		/// アイテムのラベルの編集された時
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void treeView_AfterLabelEdit(object sender, NodeLabelEditEventArgs e)
		{
			if (e.Label == null)
				return;

			TemplateSettingTreeNode node = e.Node as TemplateSettingTreeNode;
			Debug.Assert(node != null);
			Debug.Assert(!node.IsRoot());

			bool ret = node.EditDispalyName(e.Label, this.doc_);
			if (ret == false)
			{
				throw new FundamentalException(global::ClipClop.Properties.Resources.EA001);
			}
			else
			{
				this.textBox.Text = node.DispalyValue;
			}
		}

		#endregion

		#region コンテキストメニュー


		private void UpdateContextMenu(bool bItemSelected, TemplateSettingTreeNode node)
		{
			すべて展開ToolStripMenuItem.Enabled = true;
			全てたたむToolStripMenuItem.Enabled = true;

			if (!bItemSelected)
			{
				追加AToolStripMenuItem.Enabled = false;

				削除DToolStripMenuItem.Enabled = false;
				編集EToolStripMenuItem.Enabled = false;
				コピーCToolStripMenuItem.Enabled = false;
				カットCToolStripMenuItem.Enabled = false;
				ペーストPToolStripMenuItem.Enabled = false;
				上に移動UToolStripMenuItem.Enabled = false;
				下に移動ToolStripMenuItem.Enabled = false;

				return;
			}

			//TODO 追加の仕様は今後変更する
			追加AToolStripMenuItem.Enabled = node.IsAddable();

			コピーCToolStripMenuItem.Enabled = !node.IsRoot();
			カットCToolStripMenuItem.Enabled = !node.IsRoot();

			ペーストPToolStripMenuItem.Enabled = (xmlNodeCopied_ != null && node.IsAddable()) ? true : false;

			削除DToolStripMenuItem.Enabled = !node.IsRoot();
			編集EToolStripMenuItem.Enabled = node.IsEditable();


			//TODO 移動では一個上に上がるとか下がるとかしなければならない
	
			if (node.IsRoot())
			{
				上に移動UToolStripMenuItem.Enabled = false;
				下に移動ToolStripMenuItem.Enabled = false;
				return;
			}

			上に移動UToolStripMenuItem.Enabled = node.IsFirstElement() ? false : true;
			下に移動ToolStripMenuItem.Enabled = node.IsLastElement() ? false : true;
		}

		private void すべて展開ToolStripMenuItem_Click(object sender, EventArgs e)
		{
			this.treeView.ExpandAll();
		}

		private void 全てたたむToolStripMenuItem_Click(object sender, EventArgs e)
		{
			this.treeView.CollapseAll();
		}

		private void フォルダToolStripMenuItem_Click(object sender, EventArgs e)
		{
			using (InputStringForm form = new InputStringForm())
			{
				form.StartPosition = FormStartPosition.Manual;
				form.Location = Control.MousePosition;

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

				this.bDutyFlag_ = true;

				XmlElement xmlNode = doc_.CreateElement(ContextMenuSettingDefinition.Folder_);
				xmlNode.SetAttribute(ContextMenuSettingDefinition.Name_, form.FName);
				this.treeView.AppendChild(xmlNode);
			}
		}

		private void セパレーターToolStripMenuItem_Click(object sender, EventArgs e)
		{
			this.bDutyFlag_ = true;

			XmlElement xmlNode = doc_.CreateElement(ContextMenuSettingDefinition.Separator_);

			this.treeView.AppendChild(xmlNode);
		}

		private void 定型文ToolStripMenuItem_Click(object sender, EventArgs e)
		{
			XmlElement xmlNode = doc_.CreateElement(ContextMenuSettingDefinition.Sentence_);

			try
			{
				// ダイアログを表示する。
				using (TemplateItemForm form = new TemplateItemForm(ContextMenuSettingDefinition.Mode.template,string.Empty,string.Empty))
				{
					form.StartPosition = FormStartPosition.Manual;
					form.Location = Control.MousePosition;

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

					xmlNode.SetAttribute(ContextMenuSettingDefinition.Type_, form.Mode.ToString());
					xmlNode.SetAttribute(ContextMenuSettingDefinition.Name_, form.DispName);
					xmlNode.SetAttribute(ContextMenuSettingDefinition.Value_, form.DispValue);
				}
			}
			catch (Exception exp)
			{
				Util.ShowError(exp.Message);
                return;
			}

			this.bDutyFlag_ = true;

			this.treeView.AppendChild(xmlNode);
		}

		private void 編集EToolStripMenuItem_Click(object sender, EventArgs e)
		{
			TemplateSettingTreeNode treeNode = this.treeView.SelectedNode as TemplateSettingTreeNode;

			switch (treeNode.SettingType)
			{
				case ContextMenuSettingDefinition.SettingType.folder:

					using (InputStringForm form = new InputStringForm(treeNode.DispalyName))
					{
						form.StartPosition = FormStartPosition.Manual;
						form.Location = Control.MousePosition;

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

						this.bDutyFlag_ = true;

						treeNode.EditNameAttribute(form.FName);
						treeNode.Text = form.FName;
					}

					break;
				case ContextMenuSettingDefinition.SettingType.sentence:
					try
					{
						// ダイアログを表示する。
						using (TemplateItemForm form = new TemplateItemForm(treeNode.Mode, treeNode.DispalyName, treeNode.DispalyValue))
						{
							form.StartPosition = FormStartPosition.Manual;
							form.Location = Control.MousePosition;

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

							if (!treeNode.EditAttribute(form.Mode, form.DispName, form.DispValue, this.doc_))
							{
								throw new FundamentalException(global::ClipClop.Properties.Resources.EA001);
							}

							treeNode.Text = treeNode.DispalyName;

							this.bDutyFlag_ = true;
						}
					}
					catch (Exception exp)
					{
						Util.ShowError(exp.Message);
					}
					this.textBox.Text = treeNode.DispalyValue;


					break;
				case ContextMenuSettingDefinition.SettingType.separator:
					Debug.Fail("ここに来ても困る");
					break;
			}
		}

		private void 削除DToolStripMenuItem_Click(object sender, EventArgs e)
		{
			this.bDutyFlag_ = true;

			this.treeView.DeleteNode();
		}

		private void コピーCToolStripMenuItem_Click(object sender, EventArgs e)
		{
			this.xmlNodeCopied_ = this.treeView.CopySelectedNode();
		}

		private void カットCToolStripMenuItem_Click(object sender, EventArgs e)
		{
			this.bDutyFlag_ = true;

			this.xmlNodeCopied_ = this.treeView.CopySelectedNode();

			this.treeView.DeleteNode();
		}

		private void ペーストPToolStripMenuItem_Click(object sender, EventArgs e)
		{
			this.bDutyFlag_ = true;

			this.treeView.AppendChild(this.xmlNodeCopied_ );
		}

		private void 上に移動UToolStripMenuItem_Click(object sender, EventArgs e)
		{
			TreeNode prev = this.treeView.SelectedNode.PrevNode;
			TreeNode selected = this.treeView.SelectedNode;

			int tergetIndex = prev.Index;

			TreeNode parent = this.treeView.SelectedNode.Parent;

			parent.Nodes.RemoveAt(tergetIndex);//一個前に詰まる
			parent.Nodes.RemoveAt(tergetIndex);

			parent.Nodes.Insert(tergetIndex, selected);
			parent.Nodes.Insert(tergetIndex + 1, prev);

			this.treeView.SelectedNode = selected;

			TemplateSettingTreeNode treeNode = selected as TemplateSettingTreeNode;
			treeNode.MoveAbove();
		}

		private void 下に移動ToolStripMenuItem_Click(object sender, EventArgs e)
		{
			TreeNode next = this.treeView.SelectedNode.NextNode;
			TreeNode selected = this.treeView.SelectedNode;

			int tergetIndex = selected.Index;

			TreeNode parent = this.treeView.SelectedNode.Parent;

			parent.Nodes.RemoveAt(tergetIndex);//一個前に詰まる
			parent.Nodes.RemoveAt(tergetIndex);

			parent.Nodes.Insert(tergetIndex, next);
			parent.Nodes.Insert(tergetIndex + 1, selected);

			this.treeView.SelectedNode = selected;

			TemplateSettingTreeNode treeNode = selected as TemplateSettingTreeNode;
			treeNode.MoveBelow();
		}
		#endregion

		private void 名前をつけて保存ToolStripMenuItem_Click(object sender, EventArgs e)
		{
			string filePath;

			using (SaveFileDialog fd = new SaveFileDialog())
			{
				fd.FileName = Path.GetFileName(this.templateFilePath_);
				fd.Filter = "XMLファイル(*.XML)|*.XML|すべてのファイル(*.*)|*.*";
                fd.InitialDirectory = string.IsNullOrEmpty(ClipClop.Properties.Settings.Default.InitialDirectoryXmlFile) ?
                    string.Empty : ClipClop.Properties.Settings.Default.InitialDirectoryXmlFile;
                fd.OverwritePrompt = true;

				DialogResult result = fd.ShowDialog();
				if (result != DialogResult.OK)
					return;
				filePath = fd.FileName;

                ClipClop.Properties.Settings.Default.InitialDirectoryXmlFile = Path.GetDirectoryName(fd.FileName);
			}

			string pwd = string.Empty;
			if (this.doc_.IsEncrypted())
			{
				if (!PasswordForm.ShowInputPassword(ref pwd))
				{
					return;
				}
			}


			try
			{
				this.Cursor = Cursors.WaitCursor;

				this.doc_.SaveTo(filePath, pwd); 

				bDutyFlag_ = false;
			}
			catch (Exception exp)
			{
				Util.ShowError(global::ClipClop.Properties.Resources.EF005 + Environment.NewLine + exp.Message);
			}
			finally
			{
				this.Cursor = Cursors.Default;
			}
		}

		private void TemplateSetting_FormClosing(object sender, FormClosingEventArgs e)
		{
			//キャンセルか×ボタンの場合
			if (e.CloseReason == CloseReason.UserClosing || this.DialogResult == DialogResult.Cancel)
			{
                if (!this.bDutyFlag_)
                {
                    return;
                }

				if (Util.Confirm(global::ClipClop.Properties.Resources.MSG005))
				{
					return;
				}
				e.Cancel = true;
			}

            //+
            if (Encryption)
            { 
				if (string.IsNullOrEmpty(passwordString_))
				{
					if (!PasswordForm.ShowInputPassword(ref passwordString_))
					{
                        e.Cancel = true;
					}
				}
            }
		}

		private void TemplateSetting_FormClosed(object sender, FormClosedEventArgs e)
		{
            Properties.Settings.Default.WindowGeometryTemplateSetting = FormUtil.GeometryToString(this);

		}

		private void 新規作成NToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if (this.bDutyFlag_ 
				&& MessageBox.Show(global::ClipClop.Properties.Resources.MSG005, Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
			{
				return;
			}

			XmlNode root = doc_.GetRoot();

			while ( 0 <  root.ChildNodes.Count )
			{
				XmlNode xmlnode = root.ChildNodes[0];
				root.RemoveChild(xmlnode);
			}

			try
			{
				this.Cursor = Cursors.WaitCursor;
				this.treeView.Setup(this.doc_);

				this.bDutyFlag_ = false;

				UpdateEncrypted();
			}
			catch (Exception exp)
			{
				Util.ShowError(global::ClipClop.Properties.Resources.EF005 + Environment.NewLine + exp.Message);
			}
			finally
			{
				this.Cursor = Cursors.Default;
			}

		}


		public bool Encryption
		{
			get
			{
				if (doc_ == null || doc_.IsEncrypted() == false)
					return false;
				else
					return true;
			}
		}


		/// <summary>
		/// 定義ファイルの暗号化状態表示を更新する。
		/// </summary>
		void UpdateEncrypted()
		{
			if (Encryption)
			{
				this.pictureBox.Image = global::ClipClop.Properties.Resources._lock;
			}
			else{
					this.pictureBox.Image = global::ClipClop.Properties.Resources.lock_unlock;
			}
		}

		private void pictureBox_Click(object sender, EventArgs e)
		{
			if (Encryption)
			{
				if (Util.Confirm(global::ClipClop.Properties.Resources.MSG009) != true)
					return;
				doc_.SetEncryptionAttribute(false);
			}
			else{
				if (Util.Confirm(global::ClipClop.Properties.Resources.MSG008) != true)
					return;
				doc_.SetEncryptionAttribute(true);
			}

			this.bDutyFlag_ = true;
			UpdateEncrypted();
		}
		
	}
}
