//==============================================================
//  版权所有：深圳杰文科技
//  文件名：GridLayoutController.cs
//  版本：V1.0  
//  创建者：Jay  ( QQ： 85363208 )
//  创建时间：2017-11-28 16:18
//  创建描述：
//  修改者：
//  修改时间：
//  修改说明： 
//==============================================================

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using DevExpress.XtraGrid;
using DevExpress.XtraGrid.Views.Base;
using DevExpress.Utils;
using System.Text;
using System.Xml;

namespace Infrastructure.Components
{
	/// <summary>
	///  BaseView 样式控制类。
	/// </summary>
	internal class GridLayoutController
	{
		#region - field -

		/// <summary>
		/// 默认用户名称。
		/// </summary>
		public static string DefaultUser = "_DefaultUser";

		/// <summary>
		/// 配置文件根目录。
		/// </summary>
		public static string StylePath = string.Format("{0}\\StyleSetting", Application.StartupPath);

		#endregion - field -

		#region - methods -

		#region - 获取 BaseView 样式 Xml 文件路径 -

		#region - GetInitStylePath -
		/// <summary>
		/// 获取 BaseView 初始样式 Xml 文件路径。
		/// </summary>
		/// <param name="user">用户名称。</param>
		/// <param name="name">配置名称(作为样式文件名称的一部分，不能为 null 或空字符串)。</param>
		/// <param name="baseView"> BaseView 控件。</param>
		/// <returns> BaseView 初始样式 Xml 文件路径。</returns>
		private static string GetInitStylePath(string user, string name, BaseView baseView)
		{
			return GetStylePath(user, name, baseView, true);
		}
		#endregion

		#region - GetStylePath -
		/// <summary>
		/// 获取 BaseView 样式 Xml 文件路径。
		/// </summary>
		/// <param name="user">用户名称。</param>
		/// <param name="name">配置名称(作为样式文件名称的一部分，不能为 null 或空字符串)。</param>
		/// <param name="baseView"> BaseView 控件。</param>
		/// <returns> BaseView 样式 Xml 文件路径。</returns>
		private static string GetStylePath(string user, string name, BaseView baseView)
		{
			return GetStylePath(user, name, baseView, false);
		}

		/// <summary>
		/// 获取 BaseView 样式 Xml 文件路径。
		/// </summary>
		/// <param name="user">用户名称。</param>
		/// <param name="name">配置名称(作为样式文件名称的一部分，不能为 null 或空字符串)。</param>
		/// <param name="baseView"> BaseView 控件。</param>
		/// <param name="init">是否为初始样式。</param>
		/// <returns> BaseView 初始样式 Xml 文件路径。</returns>
		private static string GetStylePath(string user, string name, BaseView baseView, bool init)
		{
			CheckName(name);
			return string.Format("{0}\\{1}\\{2}.{3}.Style{4}.xml", StylePath, user, name, baseView.Name, init ? ".Init" : string.Empty);
		}
		#endregion

		#endregion

		#region - 获取文件列表 -
		/// <summary>
		/// 获取文件列表。
		/// </summary>
		/// <param name="path">路径。</param>
		/// <param name="groupName">名称。</param>
		/// <param name="suffix">后缀。</param>
		/// <returns>配置名称字符串数组。</returns>
		private static string[] GetFileList(string path, string subName, string suffix)
		{
			if (!Directory.Exists(path))
			{
				return null;
			}
			string[] list = Directory.GetFiles(path, string.Format("*{0}{1}", subName, suffix), SearchOption.TopDirectoryOnly);
			return list;
		}
		#endregion

		#region - 校验配置名称 -
		/// <summary>
		/// 校验配置名称。
		/// </summary>
		/// <param name="name">配置名称。</param>
		private static void CheckName(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				throw new ArgumentException(string.Format("配置名称 name 不能为 null 或空字符串！", name));
			}
		}
		#endregion

		#region - 将指定的文本添加指定的流 -
		/// <summary>
		/// 将指定的文本添加指定的流。
		/// </summary>
		/// <param name="stream">流。</param>
		/// <param name="value">文本。</param>
		private static void AppendText(Stream stream, string value)
		{
			byte[] info = Encoding.UTF8.GetBytes(value);
			stream.Write(info, 0, info.Length);
		}
		#endregion

		#region - 保存 GridControl 样式 -

		#region - SaveInitStyle -
		/// <summary>
		/// 保存 GridControl 初始样式到默认用户名称文件夹下。
		/// </summary>
		/// <param name="name">配置名称(作为样式文件名称的一部分，不能为 null 或空字符串)。</param>
		/// <param name="gridControl"> GridControl 控件。</param>
		/// <returns>是否保存成功。</returns>
		public static void SaveInitStyle(string name, GridControl gridControl)
		{
			SaveInitStyle(DefaultUser, name, gridControl);
		}

		/// <summary>
		/// 保存 GridControl 初始样式到指定用户名称文件夹下。
		/// </summary>
		/// <param name="user">用户名称。</param>
		/// <param name="name">配置名称(作为样式文件名称的一部分，不能为 null 或空字符串)。</param>
		/// <param name="gridControl"> GridControl 控件。</param>
		/// <returns>是否保存成功。</returns>
		public static void SaveInitStyle(string user, string name, GridControl gridControl)
		{
			SaveStyle(user, name, gridControl, true);
		}
		#endregion

		#region - SaveStyle -
		/// <summary>
		/// 保存 GridControl 样式到默认用户名称文件夹下。
		/// </summary>
		/// <param name="name">配置名称(作为样式文件名称的一部分，不能为 null 或空字符串)。</param>
		/// <param name="gridControl"> GridControl 控件。</param>
		/// <returns>是否保存成功。</returns>
		public static void SaveStyle(string name, GridControl gridControl)
		{
			SaveStyle(DefaultUser, name, gridControl);
		}

		/// <summary>
		/// 保存 GridControl 样式到指定用户名称文件夹下。
		/// </summary>
		/// <param name="user">用户名称。</param>
		/// <param name="name">配置名称(作为样式文件名称的一部分，不能为 null 或空字符串)。</param>
		/// <param name="gridControl"> GridControl 控件。</param>
		/// <returns>是否保存成功。</returns>
		public static void SaveStyle(string user, string name, GridControl gridControl)
		{
			SaveStyle(user, name, gridControl, false);
		}

		/// <summary>
		/// 保存 GridControl 样式到指定用户名称文件夹下。
		/// </summary>
		/// <param name="user">用户名称。</param>
		/// <param name="name">配置名称(作为样式文件名称的一部分，不能为 null 或空字符串)。</param>
		/// <param name="gridControl"> GridControl 控件。</param>
		/// <param name="init">是否为初始样式。</param>
		/// <returns>是否保存成功。</returns>
		public static void SaveStyle(string user, string name, GridControl gridControl, bool init)
		{
			var listView = from BaseView a in gridControl.ViewCollection
						   orderby a.DetailLevel descending
						   select a;
			foreach (BaseView view in listView.Distinct(new BaseViewComparer()))
			{
				SaveStyle(user, name, view, init);
			}
		}
		#endregion

		#region - SaveStyleTo -
		/// <summary>
		/// 保存 GridControl 样式到默认用户名称文件夹下，自定义文件名。
		/// </summary>
		/// <param name="gridControl"> GridControl 控件。</param>
		/// <returns>是否保存成功。</returns>
		public static void SaveStyleTo(GridControl gridControl)
		{
			SaveStyleTo(DefaultUser, gridControl);
		}

		/// <summary>
		/// 保存 GridControl 样式到指定用户名称文件夹下，自定义文件名。
		/// </summary>
		/// <param name="user">用户名称。</param>
		/// <param name="gridControl"> GridControl 控件。</param>
		/// <returns>是否保存成功。</returns>
		public static void SaveStyleTo(string user, GridControl gridControl)
		{
			string viewName = "ViewName";
			string suffix = "*.xml";
			string path = string.Format("{0}\\{1}", StylePath, user);
			string subName = string.Format("{0}.Style", gridControl.Name);
			FileDialogForm frm = new FileDialogForm("保存文件", subName, suffix, path, viewName, DialogType.Save);
			DialogResult result = frm.ShowDialog();
			if (result == DialogResult.OK)
			{
				using (FileStream stream = new FileStream(frm.FullName, FileMode.Create))
				{
					AppendText(stream, "<GridControlStyle>\r\n");
				}
				var listView = from BaseView a in gridControl.ViewCollection
							   orderby a.DetailLevel descending
							   select a;
				foreach (BaseView view in listView.Distinct(new BaseViewComparer()))
				{
					using (FileStream fs = new FileStream(frm.FullName, FileMode.Append))
					{
						AppendText(fs, string.Format("<BaseView name=\"{0}\">\r\n", view.Name));
						view.SaveLayoutToStream(fs, OptionsLayoutBase.FullLayout);
						AppendText(fs, "\r\n</BaseView>\r\n");
						fs.Flush();
					}
				}
				using (FileStream stream = new FileStream(frm.FullName, FileMode.Append))
				{
					AppendText(stream, "</GridControlStyle>");
				}
			}
		}
		#endregion

		#endregion

		#region - 保存 BaseView 样式 -

		#region - SaveInitStyle -
		/// <summary>
		/// 保存 BaseView 初始样式到默认用户名称文件夹下。
		/// </summary>
		/// <param name="name">配置名称(作为样式文件名称的一部分，不能为 null 或空字符串)。</param>
		/// <param name="baseView"> BaseView 控件。</param>
		/// <returns>是否保存成功。</returns>
		public static bool SaveInitStyle(string name, BaseView baseView)
		{
			return SaveInitStyle(DefaultUser, name, baseView);
		}

		/// <summary>
		/// 保存 BaseView 初始样式到指定用户名称文件夹下。
		/// </summary>
		/// <param name="user">用户名称。</param>
		/// <param name="name">配置名称(作为样式文件名称的一部分，不能为 null 或空字符串)。</param>
		/// <param name="baseView"> BaseView 控件。</param>
		/// <returns>是否保存成功。</returns>
		public static bool SaveInitStyle(string user, string name, BaseView baseView)
		{
			return SaveStyle(user, name, baseView, true);
		}
		#endregion

		#region - SaveStyle -
		/// <summary>
		/// 保存 BaseView 样式到默认用户名称文件夹下。
		/// </summary>
		/// <param name="name">配置名称(作为样式文件名称的一部分，不能为 null 或空字符串)。</param>
		/// <param name="baseView"> BaseView 控件。</param>
		/// <returns>是否保存成功。</returns>
		public static bool SaveStyle(string name, BaseView baseView)
		{
			return SaveStyle(DefaultUser, name, baseView);
		}

		/// <summary>
		/// 保存 BaseView 样式到指定用户名称文件夹下。
		/// </summary>
		/// <param name="user">用户名称。</param>
		/// <param name="name">配置名称(作为样式文件名称的一部分，不能为 null 或空字符串)。</param>
		/// <param name="baseView"> BaseView 控件。</param>
		/// <returns>是否保存成功。</returns>
		public static bool SaveStyle(string user, string name, BaseView baseView)
		{
			return SaveStyle(user, name, baseView, false);
		}

		/// <summary>
		/// 保存 BaseView 样式到指定用户名称文件夹下。
		/// </summary>
		/// <param name="user">用户名称。</param>
		/// <param name="name">配置名称(作为样式文件名称的一部分，不能为 null 或空字符串)。</param>
		/// <param name="baseView"> BaseView 控件。</param>
		/// <param name="init">是否为初始样式。</param>
		/// <returns>是否保存成功。</returns>
		public static bool SaveStyle(string user, string name, BaseView baseView, bool init)
		{
			string path = GetStylePath(user, name, baseView, init);
			return SaveStyle(baseView, path);
		}

		/// <summary>
		/// 保存 BaseView 样式到指定路径。
		/// </summary>
		/// <param name="baseView"> BaseView 控件。</param>
		/// <param name="path">保存样式 Xml 文件路径。</param>
		/// <returns>是否保存成功。</returns>
		private static bool SaveStyle(BaseView baseView, string path)
		{
			string directory = Path.GetDirectoryName(path);
			if (!Directory.Exists(directory))
			{
				Directory.CreateDirectory(directory);
			}
			baseView.SaveLayoutToXml(path);
			return true;
		}
		#endregion

		#region - SaveStyleTo -
		/// <summary>
		/// 保存 BaseView 样式到默认用户名称文件夹下，自定义文件名。
		/// </summary>
		/// <param name="baseView"> BaseView 控件。</param>
		/// <returns>是否保存成功。</returns>
		public static bool SaveStyleTo(BaseView baseView)
		{
			return SaveStyleTo(DefaultUser, baseView);
		}

		/// <summary>
		/// 保存 BaseView 样式到指定用户名称文件夹下，自定义文件名。
		/// </summary>
		/// <param name="user">用户名称。</param>
		/// <param name="baseView"> BaseView 控件。</param>
		/// <returns>是否保存成功。</returns>
		public static bool SaveStyleTo(string user, BaseView baseView)
		{
			string suffix = "*.xml";
			string path = string.Format("{0}\\{1}", StylePath, user);
			string subName = string.Format("{0}.Style", baseView.Name);
			FileDialogForm frm = new FileDialogForm("保存文件", subName, suffix, path, baseView.Name, DialogType.Save);
			DialogResult result = frm.ShowDialog();
			if (result == DialogResult.OK)
			{
				return SaveStyle(baseView, frm.FullName);
			}
			return false;
		}
		#endregion

		#endregion

		#region - 恢复 GridControl 样式 -

		#region - RestoreInitStyle -
		/// <summary>
		/// 从默认用户名称文件夹下，恢复 GridControl 初始样式。
		/// </summary>
		/// <param name="name">配置名称(作为样式文件名称的一部分，不能为 null 或空字符串)。</param>
		/// <param name="gridControl"> GridControl 控件。</param>
		/// <returns>是否恢复成功。</returns>
		public static void RestoreInitStyle(string name, GridControl gridControl)
		{
			RestoreInitStyle(DefaultUser, name, gridControl);
		}

		/// <summary>
		/// 从指定用户名称文件夹下，恢复 GridControl 初始样式。
		/// </summary>
		/// <param name="user">用户名称。</param>
		/// <param name="name">配置名称(作为样式文件名称的一部分，不能为 null 或空字符串)。</param>
		/// <param name="gridControl"> GridControl 控件。</param>
		/// <returns>是否恢复成功。</returns>
		public static void RestoreInitStyle(string user, string name, GridControl gridControl)
		{
			RestoreStyle(user, name, gridControl, true);
		}
		#endregion

		#region - RestoreStyle -
		/// <summary>
		/// 从默认用户名称文件夹下，恢复 GridControl 样式。
		/// </summary>
		/// <param name="name">配置名称(作为样式文件名称的一部分，不能为 null 或空字符串)。</param>
		/// <param name="gridControl">GridControl控件。</param>
		/// <returns>是否恢复成功。</returns>
		public static void RestoreStyle(string name, GridControl gridControl)
		{
			RestoreStyle(DefaultUser, name, gridControl);
		}

		/// <summary>
		/// 从指定用户名称文件夹下，恢复 GridControl 样式。
		/// </summary>
		/// <param name="user">用户名称。</param>
		/// <param name="name">配置名称(作为样式文件名称的一部分，不能为 null 或空字符串)。</param>
		/// <param name="gridControl">GridControl控件。</param>
		/// <returns>是否恢复成功。</returns>
		public static void RestoreStyle(string user, string name, GridControl gridControl)
		{
			RestoreStyle(user, name, gridControl, false);
		}

		/// <summary>
		/// 从指定用户名称文件夹下，恢复 GridControl 样式。
		/// </summary>
		/// <param name="user">用户名称。</param>
		/// <param name="name">配置名称(作为样式文件名称的一部分，不能为 null 或空字符串)。</param>
		/// <param name="gridControl">GridControl控件。</param>
		/// <param name="init">是否为初始样式。</param>
		/// <returns>是否恢复成功。</returns>
		public static void RestoreStyle(string user, string name, GridControl gridControl, bool init)
		{
			var listView = from BaseView a in gridControl.ViewCollection
						   orderby a.DetailLevel descending
						   select a;
			foreach (BaseView view in listView.Distinct(new BaseViewComparer()))
			{
				RestoreStyle(user, name, view, init);
			}
		}
		#endregion

		#region - RestoreStyleTo -
		/// <summary>
		/// 从默认用户名称文件夹下，选择路径恢复 GridControl 样式。
		/// </summary>
		/// <param name="gridControl"> GridControl 控件。</param>
		/// <returns>是否恢复成功。</returns>
		public static void RestoreStyleTo(GridControl gridControl)
		{
			RestoreStyleTo(DefaultUser, gridControl);
		}

		/// <summary>
		/// 从指定用户名称文件夹下，选择路径恢复 GridControl 样式。
		/// </summary>
		/// <param name="name">用户名称。</param>
		/// <param name="gridControl"> GridControl 控件。</param>
		/// <returns>是否恢复成功。</returns>
		public static void RestoreStyleTo(string user, GridControl gridControl)
		{
			string viewName = "ViewName";
			string suffix = "*.xml";
			string path = string.Format("{0}\\{1}", StylePath, user);
			string subName = string.Format("{0}.Style", gridControl.Name);
			string filePath = string.Empty;
			string[] list = GetFileList(path, subName, suffix);
			if (list == null)
			{
				return;
			}
			else if (list.Length == 1)
			{
				filePath = list[0];
			}
			else if (list.Length > 1)
			{
				FileDialogForm frm = new FileDialogForm("打开文件", subName, suffix, path, viewName, DialogType.Open);
				DialogResult result = frm.ShowDialog();
				if (result == DialogResult.OK)
				{
					filePath = frm.FullName;
				}
			}
			if (filePath != string.Empty)
			{
				XmlDocument xml = new XmlDocument();
				xml.Load(filePath);
				var listView = from BaseView a in gridControl.ViewCollection
							   orderby a.DetailLevel descending
							   select a;
				foreach (BaseView view in listView.Distinct(new BaseViewComparer()))
				{
					XmlNode node = xml.SelectSingleNode(string.Format("GridControlStyle/BaseView[@name='{0}']", view.Name));
					//// TODO:luon
					//using (MemoryStream ms = new MemoryStream())
					//{
					//    AppendText(ms, string.Format("   {0}   ", node.InnerXml));
					//    view.RestoreLayoutFromStream(ms, OptionsLayoutBase.FullLayout);
					//}
					string fileName = Path.GetTempFileName();
					using (FileStream fs = new FileStream(fileName, FileMode.Create))
					{
						AppendText(fs, node.InnerXml);
					}
					view.RestoreLayoutFromXml(fileName);
				}
			}
		}
		#endregion

		#endregion

		#region - 恢复 BaseView 样式 -

		#region - RestoreInitStyle -
		/// <summary>
		/// 从默认用户名称文件夹下，恢复 BaseView 初始样式。
		/// </summary>
		/// <param name="name">配置名称(作为样式文件名称的一部分，不能为 null 或空字符串)。</param>
		/// <param name="baseView"> BaseView 控件。</param>
		/// <returns>是否恢复成功。</returns>
		public static bool RestoreInitStyle(string name, BaseView baseView)
		{
			return RestoreInitStyle(DefaultUser, name, baseView);
		}

		/// <summary>
		/// 从指定用户名称文件夹下，恢复 BaseView 初始样式。
		/// </summary>
		/// <param name="user">用户名称。</param>
		/// <param name="name">配置名称(作为样式文件名称的一部分，不能为 null 或空字符串)。</param>
		/// <param name="baseView"> BaseView 控件。</param>
		/// <returns>是否恢复成功。</returns>
		public static bool RestoreInitStyle(string user, string name, BaseView baseView)
		{
			return RestoreStyle(user, name, baseView, true);
		}
		#endregion

		#region - RestoreStyle -
		/// <summary>
		/// 从默认用户名称文件夹下，恢复 BaseView 样式。
		/// </summary>
		/// <param name="name">配置名称(作为样式文件名称的一部分，不能为 null 或空字符串)。</param>
		/// <param name="baseView"> BaseView 控件。</param>
		/// <returns>是否恢复成功。</returns>
		public static bool RestoreStyle(string name, BaseView baseView)
		{
			return RestoreStyle(DefaultUser, name, baseView);
		}

		/// <summary>
		/// 从指定用户名称文件夹下，恢复 BaseView 样式。
		/// </summary>
		/// <param name="user">用户名称。</param>
		/// <param name="name">配置名称(作为样式文件名称的一部分，不能为 null 或空字符串)。</param>
		/// <param name="baseView"> BaseView 控件。</param>
		/// <returns>是否恢复成功。</returns>
		public static bool RestoreStyle(string user, string name, BaseView baseView)
		{
			return RestoreStyle(user, name, baseView, false);
		}

		/// <summary>
		/// 从指定用户名称文件夹下，恢复 BaseView 样式。
		/// </summary>
		/// <param name="user">用户名称。</param>
		/// <param name="name">配置名称(作为样式文件名称的一部分，不能为 null 或空字符串)。</param>
		/// <param name="baseView"> BaseView 控件。</param>
		/// <param name="init">是否为初始样式。</param>
		/// <returns>是否恢复成功。</returns>
		public static bool RestoreStyle(string user, string name, BaseView baseView, bool init)
		{
			string path = GetStylePath(user, name, baseView, init);
			return LoadStyle(baseView, path);
		}
		#endregion

		#region - RestoreStyleTo -
		/// <summary>
		/// 从默认用户名称文件夹下，选择路径恢复 BaseView 样式。
		/// </summary>
		/// <param name="baseView"> BaseView 控件。</param>
		/// <returns>是否恢复成功。</returns>
		public static bool RestoreStyleTo(BaseView baseView)
		{
			return RestoreStyleTo(DefaultUser, baseView);
		}

		/// <summary>
		/// 从指定用户名称文件夹下，选择路径恢复 BaseView 样式。
		/// </summary>
		/// <param name="name">用户名称。</param>
		/// <param name="baseView"> BaseView 控件。</param>
		/// <returns>是否恢复成功。</returns>
		public static bool RestoreStyleTo(string user, BaseView baseView)
		{
			string suffix = "*.xml";
			string path = string.Format("{0}\\{1}", StylePath, user);
			string subName = string.Format("{0}.Style", baseView.Name);
			string[] list = GetFileList(path, subName, suffix);
			if (list == null)
			{
				return false;
			}
			else if (list.Length == 1)
			{
				return LoadStyle(baseView, list[0]);
			}
			else if (list.Length > 1)
			{
				FileDialogForm frm = new FileDialogForm("打开文件", subName, suffix, path, baseView.Name, DialogType.Open);
				DialogResult result = frm.ShowDialog();
				if (result == DialogResult.OK)
				{
					return LoadStyle(baseView, frm.FullName);
				}
			}
			return false;
		}
		#endregion

		#region - LoadStyle -
		/// <summary>
		/// 从指定路径，加载BaseView样式。
		/// </summary>
		/// <param name="baseView"> BaseView 控件。</param>
		/// <param name="path">加载样式Xml文件路径。</param>
		/// <returns>是否加载成功。</returns>
		private static bool LoadStyle(BaseView baseView, string path)
		{
			if (File.Exists(path))
			{
				baseView.RestoreLayoutFromXml(path);
				return true;
			}
			return false;
		}
		#endregion

		#endregion

		#endregion - methods -
	}

	internal class BaseViewComparer : IEqualityComparer<BaseView>
	{
		public bool Equals(BaseView x, BaseView y)
		{
			if (Object.ReferenceEquals(x, y))
			{
				return true;
			}
			if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
			{
				return false;
			}
			return x.ViewCaption == y.ViewCaption && x.Name == y.Name;
		}

		public int GetHashCode(BaseView obj)
		{
			if (Object.ReferenceEquals(obj, null))
			{
				return 0;
			}
			int hashBaseViewName = obj.Name.GetHashCode();
			int hashBaseViewViewCaption = obj.ViewCaption.GetHashCode();
			return hashBaseViewName ^ hashBaseViewViewCaption;
		}
	}

}
