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
    {
        TemplateSettingTreeNode nodeCopied_ = null;

		readonly string templateFilePath_;

		bool bDutyFlag_ = false;

		string passwordString_;

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

        public TemplateSetting()
        {
            InitializeComponent();

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

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

			UpdateEncrypted(false);
        }

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

			passwordString_ = passwordString;
			templateFilePath_ = templateFilePath;

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

		public void DragDropItemChanged()
		{
			//ドラッグドロップでTreeViewが変わった
			this.bDutyFlag_ = true;
		}


		private void TemplateSetting_Load(object sender, EventArgs e)
		{
            bool bEncrypted = false; 
			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_);
				}

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

		/// <summary>
		/// Formの表示を初期化する
		/// </summary>
		void Initialize()
		{
			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.InitialDirectoryQtFile) ?
					string.Empty : ClipClop.Properties.Settings.Default.InitialDirectoryQtFile;                

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

			}

			try
			{
				this.Cursor = Cursors.WaitCursor;

				QtClipContextMenuReader reader = new QtClipContextMenuReader();

				reader.Read(filePath);

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

                this.treeView.Setup(reader.GetDocument());

				UpdateEncrypted(false);
			}
			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.DisplayValue;
				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.Classification != ContextMenuSettingDefinition.Classification.sentence )
			{
				//編集できるのは、定型文のみ。
				return;
			}

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

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

					node.EditAttribute(form.SentenceType, form.DispName, form.DispValue, form.DispLatter);

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

			this.textBox.Text = node.DisplayValue;
		}


		/// <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) ?
                    Path.GetDirectoryName(templateFilePath_) : 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);
			}

			ReadFile(filePath);
		}

		private void ReadFile(string filePath)
		{
			passwordString_ = string.Empty;

			try
			{
				this.Cursor = Cursors.WaitCursor;

				XmlContextMenuReader reader = new XmlContextMenuReader();

				reader.Read(filePath);

				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);

					passwordString_ = pwd;
				}

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

				this.treeView.Setup(tempDoc);

				UpdateEncrypted(tempDoc.IsEncrypted());
			}
			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 if (node.Classification == ContextMenuSettingDefinition.Classification.separator)
            {
				e.CancelEdit = true;
            }
            else if (node.Classification == ContextMenuSettingDefinition.Classification.sentence &&
                (node.SentenceType == ContextMenuSettingDefinition.SentenceType.editfile))
            {
                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());

            if( string.IsNullOrEmpty( node.NameAttribute ))
            {
				node.EditAttribute(node.SentenceType, string.Empty, e.Label, node.LatterAttribute);
            }
            else{
				node.EditAttribute(node.SentenceType, e.Label, node.ValueAttribute, node.LatterAttribute);
            }

            this.textBox.Text = node.DisplayValue;
		}

		#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 = (nodeCopied_ != 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.PrevNode == null ? false : true;
			下に移動ToolStripMenuItem.Enabled = node.NextNode == null ? 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;

                this.treeView.AppendChild(new TemplateSettingTreeNodeData(ContextMenuSettingDefinition.Classification.folder, form.FName));
			}
		}

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

            this.treeView.AppendChild(new TemplateSettingTreeNodeData(ContextMenuSettingDefinition.Classification.separator));
		}

		private void 定型文ToolStripMenuItem_Click(object sender, EventArgs e)
		{
			try
			{
				// ダイアログを表示する。
				using (TemplateItemForm form = new TemplateItemForm(ContextMenuSettingDefinition.SentenceType.template, string.Empty, string.Empty, string.Empty))
				{
					form.StartPosition = FormStartPosition.Manual;
					form.Location = Control.MousePosition;

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

					TemplateSettingTreeNodeData newData = new TemplateSettingTreeNodeData(ContextMenuSettingDefinition.Classification.sentence);

					newData.sentenceType_ = form.SentenceType;
                    if (!string.IsNullOrEmpty(form.DispName))
                    {
                        newData.nameAttribute_ = form.DispName;
                    }

                    newData.valueAttribute_ = form.DispValue;
					newData.latterAttribute_ = form.DispLatter;

					this.treeView.AppendChild(newData);
					this.bDutyFlag_ = true;
				}
			}
			catch (Exception exp)
			{
				Util.ShowError(exp.Message);
                return;
			}
		}

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

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

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

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

						this.bDutyFlag_ = true;

						treeNode.EditAttribute(treeNode.SentenceType, form.FName, string.Empty, string.Empty);
                        treeNode.Text = form.FName;
					}

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

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

							treeNode.EditAttribute(form.SentenceType, form.DispName, form.DispValue, form.DispLatter);

							treeNode.Update();

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


					break;
				case ContextMenuSettingDefinition.Classification.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)
		{
            if( this.treeView.SelectedNode!=null)
                this.nodeCopied_ = (TemplateSettingTreeNode)this.treeView.SelectedNode.Clone();
		}

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

            if (this.treeView.SelectedNode != null)
                this.nodeCopied_ = (TemplateSettingTreeNode)this.treeView.SelectedNode.Clone();

			this.treeView.DeleteNode();
		}

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

			this.treeView.AppendChild((TemplateSettingTreeNode)this.nodeCopied_.Clone() );
		}

		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;
		}

		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;
		}
		#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) ?
                    Path.GetDirectoryName(templateFilePath_) : 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.Encryption)
			{
				if (!PasswordForm.ShowInputPassword(ref pwd))
				{
					return;
				}
			}


			try
			{
				this.Cursor = Cursors.WaitCursor;

                XmlCipheredDocument doc = this.GetXmlCipheredDocument();

				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;
			}
		}

        public XmlCipheredDocument GetXmlCipheredDocument()
        {
            XmlCipheredDocument doc = treeView.CreateDocument();
            doc.SetEncryptionAttribute(this.Encryption);
            return doc;
        }

		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;
			}

			try
			{
				this.Cursor = Cursors.WaitCursor;

                XmlCipheredDocument tempDoc = XmlCipheredDocument.CreateEmptyDocument();

                this.treeView.Setup(tempDoc);

				this.bDutyFlag_ = false;

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

		}

		bool encrypted_ = false;
		public bool Encryption
		{
			get { return encrypted_; }
		}


		/// <summary>
		/// 定義ファイルの暗号化状態表示を更新する。
		/// </summary>
        void UpdateEncrypted(bool bEncrypted)
		{
			this.encrypted_ = bEncrypted;

            if (bEncrypted)
			{
				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)
		{
            bool bEncrypted = false;
			if (Encryption)
			{
				if (Util.Confirm(global::ClipClop.Properties.Resources.MSG009) != true)
					return;
                bEncrypted = false;
			}
			else{
				if (Util.Confirm(global::ClipClop.Properties.Resources.MSG008) != true)
					return;
                bEncrypted = true;
			}

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

		private void googleDocumentsからToolStripMenuItem_Click(object sender, EventArgs e)
		{
			string filePath = string.Empty;

			try
			{
				using (GoogleDocumentsForm f = new GoogleDocumentsForm())
				{
					if (f.ShowDialog() != DialogResult.OK)
					{
						return;
					}

					filePath = f.TempFilePath;
				}
			}
			catch (Exception exp)
			{
				Util.ShowError(global::ClipClop.Properties.Resources.EF011 + Environment.NewLine + exp.Message);
			}

			if (!string.IsNullOrEmpty(filePath))
			{
				ReadFile(filePath);
				this.bDutyFlag_ = true;
			}

			try
			{
				File.Delete(filePath);
			}
			catch (Exception exp)
			{
				Util.ShowError(global::ClipClop.Properties.Resources.EF012 + Environment.NewLine + filePath + Environment.NewLine + exp.Message);
			}
		}
		
	}
}
