using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing.Design;
using System.Reflection;
using System.Data;
using System.Collections;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Data.SqlClient;
namespace DataLoader
{
	[Serializable]
	class DataLoaderSettings:ICloneable
	{
		#region Clone
		public object Clone()
		{
			MemoryStream memoryStream = new MemoryStream();
			BinaryFormatter binaryFormatter = new BinaryFormatter();
			binaryFormatter.Serialize(memoryStream, this);
			memoryStream.Seek(0, SeekOrigin.Begin);
			return binaryFormatter.Deserialize(memoryStream);
		}
		#endregion
		#region 16-Bit Executable
		private string _VEPromsPath; // Folder
		[Category("16-Bit Executable")]
		[DisplayName("VEProms Exe Folder")]
		[Description("Path to the VE-PROMS Executable Folder")]
		[EditorAttribute(typeof(UIFolderEditor), typeof(System.Drawing.Design.UITypeEditor))]
		public string VEPromsPath
		{
			get { return _VEPromsPath; }
			set { _VEPromsPath = value; }
		}
		private string _VESamFile; // File
		[Category("16-Bit Executable")]
		[DisplayName("VEProms Security File")]
		[Description("VE-PROMS Securty File (VESam)")]
		[UIFilenameEditor.FileDialogFilterAttribute("VEProms Security File|vesam.opt")]
		[EditorAttribute(typeof(UIFilenameEditor), typeof(System.Drawing.Design.UITypeEditor))]
		public string VESamFile
		{
			get { return _VESamFile; }
			set { _VESamFile = value; }
		}
		#endregion
		#region 16-Bit Data
		private string _ProcedureSetPath; // Folder
		[Category("16-Bit Data")]
		[DisplayName("Procedure Folder")]
		[Description("Path to the Data Set being converted")]
		[EditorAttribute(typeof(UIFolderEditor), typeof(System.Drawing.Design.UITypeEditor))]
		public string ProcedureSetPath
		{
			get { return _ProcedureSetPath; }
			set { _ProcedureSetPath = value; }
		}
		private bool _OnlyThisSet; // Boolean
		[Category("16-Bit Data")]
		[DisplayName("Only Process this Procedure Set")]
		[Description("Only Convert the Selected Procedure Set")]
		public bool OnlyThisSet
		{
			get { return _OnlyThisSet; }
			set { _OnlyThisSet = value; }
		}
		private bool _LoadApproved; // Boolean
		[Category("16-Bit Data")]
		[DisplayName("Load approved data for this Procedure Set")]
		[Description("Load approved PDFs (if they exist) and consistency checks for the Selected Procedure Set")]
		public bool LoadApproved
		{
			get { return _LoadApproved; }
			set { _LoadApproved = value; }
		}
		private string _ProcessOnlyInLocation; // Folder
		[Category("16-Bit Data")]
		[DisplayName("Process Only In Location")]
		[Description("Limit to folder or group of folders (otherwise all plants will be processed)")]
		[EditorAttribute(typeof(UIFolderEditor), typeof(System.Drawing.Design.UITypeEditor))]
		public string ProcessOnlyInLocation
		{
			get { return _ProcessOnlyInLocation; }
			set { _ProcessOnlyInLocation = value; }
		}
		#endregion
		#region Format Data
		private string _FormatFolder; // Folder
		[Category("Format Data")]
		[DisplayName("Format Folder")]
		[Description("Location of XML Format Files.")]
		[EditorAttribute(typeof(UIFolderEditor), typeof(System.Drawing.Design.UITypeEditor))]
		public string FormatFolder
		{
			get { return _FormatFolder; }
			set { _FormatFolder = value; }
		}
		private string _GenMacFolder; // Folder
		[Category("Format Data")]
		[DisplayName("GenMac Folder")]
		[Description("Location of XML (SVG) GenMac Macro Files.")]
		[EditorAttribute(typeof(UIFolderEditor), typeof(System.Drawing.Design.UITypeEditor))]
		public string GenMacFolder
		{
			get { return _GenMacFolder; }
			set { _GenMacFolder = value; }
		}
		#endregion
		#region Backup Data
		private string _BackupFileName; // String
		[Category("Backup Data")]
		[DisplayName("Backup File Name")]
		[Description("Name of Backup File in the batch files created in the Log Folder")]
		public string BackupFileName
		{
			get { return _BackupFileName; }
			set { _BackupFileName = value; }
		}
		private string _BackupFolder; // Folder
		[Category("Backup Data")]
		[DisplayName("Backup Folder")]
		[Description("Location of Backup Files created during each phase of the conversion process.")]
		[EditorAttribute(typeof(UIFolderEditor), typeof(System.Drawing.Design.UITypeEditor))]
		public string BackupFolder
		{
			get { return _BackupFolder; }
			set { _BackupFolder = value; }
		}
		private string _Phase1Suffix; // String
		[Category("Backup Data")]
		[DisplayName("Phase 1 Suffix")]
		[Description("Suffix to use for backup before Transitions are Fixed")]
		public string Phase1Suffix
		{
			get { return _Phase1Suffix; }
			set { _Phase1Suffix = value; }
		}
		private string _Phase2Suffix; // String
		[Category("Backup Data")]
		[DisplayName("Phase 2 Suffix")]
		[Description("Suffix to use for backup before Change Manager Script")]
		public string Phase2Suffix
		{
			get { return _Phase2Suffix; }
			set { _Phase2Suffix = value; }
		}
		private string _Phase3Suffix; // String
		[Category("Backup Data")]
		[DisplayName("Phase 3 Suffix")]
		[Description("Suffix to use for backup before Approval Script")]
		public string Phase3Suffix
		{
			get { return _Phase3Suffix; }
			set { _Phase3Suffix = value; }
		}
		private string _Phase4Suffix; // String
		[Category("Backup Data")]
		[DisplayName("Phase 4 Suffix")]
		[Description("Suffix to use for backup before Loading Approved Data")]
		public string Phase4Suffix
		{
			get { return _Phase4Suffix; }
			set { _Phase4Suffix = value; }
		}
		#endregion
		#region Process Log
		private string _LogFilePath; // Folder
		[Category("Process Log")]
		[DisplayName("Log File Folder")]
		[Description("Location of the Log Files")]
		[EditorAttribute(typeof(UIFolderEditor), typeof(System.Drawing.Design.UITypeEditor))]
		public string LogFilePath
		{
			get { return _LogFilePath; }
			set { _LogFilePath = value; }
		}
		#endregion
		#region Sql Database
		private string _ConnectionString; // String
		[Category("Sql Database")]
		[DisplayName("SQL Connection String")]
		[Description("Connection string for SQL")]
		public string ConnectionString
		{
			get { return _ConnectionString; }
			set { _ConnectionString = value; }
		}
		private string _DBName; // String
		[Category("Sql Database")]
		[DisplayName("Database Name")]
		[Description("Name of the Database that will be created to contain the converted data.")]
		public string DBName
		{
			get { return _DBName; }
			set { _DBName = value; }
		}
		private string _DBPath; // Folder
		[Category("Sql Database")]
		[DisplayName("Database File Folder")]
		[Description("Location of  the Database files.")]
		[EditorAttribute(typeof(UIFolderEditor), typeof(System.Drawing.Design.UITypeEditor))]
		public string DBPath
		{
			get { return _DBPath; }
			set { _DBPath = value; }
		}
		private bool _PurgeExistingData;
		[Category("Sql Database")]
		[DisplayName("Purge Existing Data")]
		[Description("Should the data in the SQL database be purged (emptied) before adding this data.")]
		public bool PurgeExistingData
		{
			get { return _PurgeExistingData; }
			set { _PurgeExistingData = value; }
		}
		#endregion
		#region PDFs
		private string _PDFFolder; // Folder
		[Category("PDFs")]
		[DisplayName("PDF Folder")]
		[Description("Location for PDFs when printing.")]
		[EditorAttribute(typeof(UIFolderEditor), typeof(System.Drawing.Design.UITypeEditor))]
		public string PDFFolder
		{
			get { return _PDFFolder; }
			set { _PDFFolder = value; }
		}
		#endregion
		#region Debugging
		private ExecutionMode _ExecutionMode;
		[TypeConverter(typeof(EnumDescConverter))]
		[DisplayName("Execution Mode")]
		[Category("Debugging")]
		[Description("Mode for Conversion")]
		public ExecutionMode ExecutionMode
		{
			get { return _ExecutionMode; }
			set { _ExecutionMode = value; }
		}
		private bool _CheckRTF;
		[DisplayName("Check RTF")]
		[Category("Debugging")]
		[Description("This makes the Fix Transtion Code work Differently.  Not sure what it does.")]
		public bool CheckRTF
		{
			get { return _CheckRTF; }
			set { _CheckRTF = value; }
		}
		private int _Skip; // Skip specified procedures during load.
		[DisplayName("Skip First n Procedures")]
		[Category("Debugging")]
		[Description("Skip the specified number of procedures during conversion to get to a problem quicker.")]
		public int Skip
		{
			get { return _Skip; }
			set { _Skip = value; }
		}
		#endregion
		#region Accessory Pages
		private AccPageConversion _ConvertTo;
		[TypeConverter(typeof(EnumDescConverter))]
		[DisplayName("Convert To")]
		[Category("Accessory Pages")]
		[Description("Format to which the Accessory Page converted")]
		public AccPageConversion ConvertTo
		{
			get { return _ConvertTo; }
			set { _ConvertTo = value; }
		}
		private bool _RedPDFs; // Boolean
		[Category("Accessory Pages")]
		[DisplayName("Print MSWord PDFs in Red")]
		[Description("Creates Word PDFs in Debug Mode so that Debug printing will not require Word to print again.")]
		public bool RedPDFs
		{
			get { return _RedPDFs; }
			set { _RedPDFs = value; }
		}
		#endregion
		[Browsable(false)]
		public string ValidityCheck
		{
			get
			{
				StringBuilder sb = new StringBuilder();
				string ErrorPrefix = "Settings are not valid\r\n";
				// VEPromsPath = has to be non-blank
				if ((VEPromsPath ?? "") == "" || !Directory.Exists(VEPromsPath))
				{
					sb.Append(ErrorPrefix + "VEProms Exe Folder must point to an existing folder\r\n");
					ErrorPrefix = "";
				}
			// VESamFile = has to be non-blank
				if ((VESamFile ?? "") == "" || !File.Exists(VESamFile))
				{
					sb.Append(ErrorPrefix + "VEProms Security File must point to an existing file\r\n");
					ErrorPrefix = "";
				}
				// ProcedureSetPath = If OnlyThisSet is checked, then has to be non-blank
				if (OnlyThisSet)
				{
					if ((ProcedureSetPath ?? "") == "" || !Directory.Exists(ProcedureSetPath))
					{
						sb.Append(ErrorPrefix + "Procedure Folder must point to an existing folder\r\n");
						ErrorPrefix = "";
					}
					else
					{
						if (!File.Exists(ProcedureSetPath + @"\set.dbf"))
						{
							sb.Append(ErrorPrefix + "Procedure Folder must point to an existing procedure data folder\r\n");
							ErrorPrefix = "";
						}
					}
				}
				//added by jcb 20121127
				//check is ProcedureSetPath contains ProcessOnlyInLocation
				if (ProcedureSetPath.StartsWith(ProcessOnlyInLocation ?? "") == false)
				{
					sb.Append(ErrorPrefix + "Check Process Only In Location value is pointing to similar directory as Procedure Set Path\r\n");
					ErrorPrefix = "";
				}
				//end added by jcb 20121127
				// BackupFileName = Has to be non-blank
				if ((BackupFileName ?? "") == "")
				{
					sb.Append(ErrorPrefix + "Backup File Name must not be blank\r\n");
					ErrorPrefix = "";
				}
				if ((Phase1Suffix ?? "") == "")
				{
					sb.Append(ErrorPrefix + "Phase 1 Suffix must not be blank\r\n");
					ErrorPrefix = "";
				}
				if ((Phase2Suffix ?? "") == "")
				{
					sb.Append(ErrorPrefix + "Phase 2 Suffix must not be blank\r\n");
					ErrorPrefix = "";
				}
				if ((Phase3Suffix ?? "") == "")
				{
					sb.Append(ErrorPrefix + "Phase 3 Suffix must not be blank\r\n");
					ErrorPrefix = "";
				}
				// BackupFolder = Has to be non-blank
				if (OnlyThisSet && (BackupFolder ?? "") == "" || !Directory.Exists(BackupFolder))
				{
					sb.Append(ErrorPrefix + "Backup Folder must point to an existing folder\r\n");
					ErrorPrefix = "";
				}
				// FormatFolder = Has to be non-blank
				if (OnlyThisSet && (FormatFolder ?? "") == "" || !Directory.Exists(FormatFolder))
				{
					sb.Append(ErrorPrefix + "Format Folder must point to an existing folder\r\n");
					ErrorPrefix = "";
				}
				// GenMacFolder = Has to be non-blank
				if (OnlyThisSet && (GenMacFolder ?? "") == "" || !Directory.Exists(GenMacFolder))
				{
					sb.Append(ErrorPrefix + "GenMac Folder must point to an existing folder\r\n");
					ErrorPrefix = "";
				}
				// LogFilePath = Has to be non-blank
				if (OnlyThisSet && (LogFilePath ?? "") == "" || !Directory.Exists(LogFilePath))
				{
					sb.Append(ErrorPrefix + "Log File Folder must point to an existing folder\r\n");
					ErrorPrefix = "";
				}
				// ConnectionString = Has to be non-blank
				if ((ConnectionString ?? "") == "")
				{
					sb.Append(ErrorPrefix + "SQL Connection String must be a valid connection string\r\n");
					ErrorPrefix = "";
				}
				else
				{
					// Validate ConnectionString
					string checkConnectionString = ValidateConnectionString("Master");
					if (checkConnectionString != "")
					{
						sb.Append(ErrorPrefix + "SQL Connection String must be a valid connection string\r\n");
						sb.Append(checkConnectionString);
						ErrorPrefix = "";
					}
				}
				// DBName = Has to be non-blank
				if ((DBName ?? "") == "")
				{
					sb.Append(ErrorPrefix + "SQL Database Name must be a valid database name\r\n");
					ErrorPrefix = "";
				}
				// DBPath = if null check to see if DBName DB has Path, if it does then set DBPath
				if ((DBPath ?? "") == "" || !Directory.Exists(DBPath))
				{
					string filePath = GetDBFileName();
					if (filePath != null)
					{
						FileInfo fi = new FileInfo(filePath);
						DBPath = fi.DirectoryName;
					}
					else
					{
						sb.Append(ErrorPrefix + "SQL Database Path must point to an existing folder\r\n");
						ErrorPrefix = "";
					}
				}
				// PDFFolder = if not set, then don't set PDFFolder in DocVersion.Config
				if (ExecutionMode == ExecutionMode.Debug && ((PDFFolder ?? "") == "" || !Directory.Exists(PDFFolder)))
				{
					sb.Append(ErrorPrefix + "PDF Folder must point to an existing folder in debug mode\r\n");
					ErrorPrefix = "";
				}
				// Skip = Any NUmber
				// PurgeExistingData = N/A
				// OnlyThisSet = N/A
				// CheckRTF = N/A
				// ConvertTo = N/A
				// RedPDFs = N/A
				return sb.ToString();
			}
		}
		private string ValidateConnectionString(string dbName)
		{
			if(!ConnectionString.Contains("{DBName}"))
				return "    Needs to have a {DBName} token for the Initial Catalog";
			string cnstr = ConnectionString.Replace("{DBName}", dbName);
			try
			{
				SqlConnection cn = new SqlConnection(cnstr);
				cn.Open();
				cn.Close();
			}
			catch (Exception ex)
			{
				StringBuilder sb = new StringBuilder();
				while (ex != null)
				{
					sb.Append(string.Format("    {0}-{1}",ex.GetType().Name,ex.Message));
					ex = ex.InnerException;
				}
				return sb.ToString();
			}
			return "";
		}
		private string GetDBFileName()
		{
			string filename = null;
			SqlConnection cn = new SqlConnection(ConnectionString.Replace("{DBName}","Master"));
			cn.Open();
			string cmd = string.Format("Select FileName from sysdatabases where Name = '{0}'",DBName);
			SqlDataAdapter da = new SqlDataAdapter(cmd,cn);
			DataSet ds = new DataSet();
			da.Fill(ds);
			if (ds.Tables.Count == 1 && ds.Tables[0].Rows.Count == 1)
				filename = ds.Tables[0].Rows[0][0].ToString();
			cn.Close();
			return filename;
		}
	}
	public  enum AccPageConversion : int 
	{
		[Description("Don't Convert")] DoNotConvert=0,
		[Description("MS Word")] MSWord = 1,
		[Description("Rich Text Format")] RichTextFormat = 2
	}
	public enum ExecutionMode : int
	{
		[Description("Debug")] Debug = 0,
		[Description("Production")] Production = 1,
	}
	public class EnumDescConverter : System.ComponentModel.EnumConverter
	{
		protected System.Type myVal;
		/// 
		/// Gets Enum Value's Description Attribute
		/// 
		/// The value you want the description attribute for
		/// The description, if any, else it's .ToString()
		public static string GetEnumDescription(Enum value)
		{
			//Console.WriteLine("{0}", value);
			FieldInfo fi = value.GetType().GetField(value.ToString());
			DescriptionAttribute[] attributes =
				(DescriptionAttribute[])fi.GetCustomAttributes(
				typeof(DescriptionAttribute), false);
			//Console.WriteLine("{0},{1},{2}", value.ToString(), attributes.Length, (attributes.Length > 0) ? attributes[0].Description : value.ToString());
			return (attributes.Length > 0) ? attributes[0].Description : value.ToString();
		}
		/// 
		/// Gets the description for certaing named value in an Enumeration
		/// 
		/// The type of the Enumeration
		/// The name of the Enumeration value
		/// The description, if any, else the passed name
		public static string GetEnumDescription(System.Type value, string name)
		{
			FieldInfo fi = value.GetField(name);
			DescriptionAttribute[] attributes =
				(DescriptionAttribute[])fi.GetCustomAttributes(
				typeof(DescriptionAttribute), false);
			return (attributes.Length > 0) ? attributes[0].Description : name;
		}
		/// 
		/// Gets the value of an Enum, based on it's Description Attribute or named value
		/// 
		/// The Enum type
		/// The description or name of the element
		/// The value, or the passed in description, if it was not found
		public static object GetEnumValue(System.Type value, string description)
		{
			FieldInfo[] fis = value.GetFields();
			foreach (FieldInfo fi in fis)
			{
				DescriptionAttribute[] attributes =
					(DescriptionAttribute[])fi.GetCustomAttributes(
					typeof(DescriptionAttribute), false);
				if (attributes.Length > 0)
				{
					if (attributes[0].Description == description)
					{
						return fi.GetValue(fi.Name);
					}
				}
				if (fi.Name == description)
				{
					return fi.GetValue(fi.Name);
				}
			}
			return description;
		}
		public EnumDescConverter(System.Type type)
			: base(type.GetType())
		{
			myVal = type;
		}
		public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
		{
			if (value is Enum && destinationType == typeof(string))
			{
				return EnumDescConverter.GetEnumDescription((Enum)value);
			}
			if (value is string && destinationType == typeof(string))
			{
				return EnumDescConverter.GetEnumDescription(myVal, (string)value);
			}
			return base.ConvertTo(context, culture, value, destinationType);
		}
		public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
		{
			if (value is string)
			{
				return EnumDescConverter.GetEnumValue(myVal, (string)value);
			}
			if (value is Enum)
			{
				return EnumDescConverter.GetEnumDescription((Enum)value);
			}
			return base.ConvertFrom(context, culture, value);
		}
		public override bool GetPropertiesSupported(ITypeDescriptorContext context)
		{
			return false;
		}
		public override TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
		{
			ArrayList values = new ArrayList();
			FieldInfo[] fis = myVal.GetFields();
			foreach (FieldInfo fi in fis)
			{
				DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(
					 typeof(DescriptionAttribute), false);
				//if (attributes.Length > 0) 
				if (fi.Name != "value__")
					values.Add(fi.GetValue(fi.Name));
			}
			return new TypeConverter.StandardValuesCollection(values);
		}
		public static string GetEnumKeyDescription(Enum value)
		{
			FieldInfo fi = value.GetType().GetField(value.ToString());
			DescriptionAttribute[] attributes =
				(DescriptionAttribute[])fi.GetCustomAttributes(
				typeof(DescriptionAttribute), false);
			return (attributes.Length > 0) ? attributes[0].Description : value.ToString();
		}
		public static DataTable GetEnumAsDataTable(System.Type EnumType)
		{
			DataTable DTEnum = new DataTable();
			DTEnum.Columns.Add(new DataColumn("EnumID", typeof(Int32)));
			DTEnum.Columns.Add(new DataColumn("Enum", typeof(string)));
			DTEnum.Columns.Add(new DataColumn("Description", typeof(string)));
			foreach (int i in Enum.GetValues(EnumType))
			{
				System.Enum fooItem = (System.Enum)Enum.ToObject(EnumType, i);
				DTEnum.Rows.Add(new object[] { i, fooItem.ToString(), GetEnumKeyDescription(fooItem) });
			}
			return DTEnum;
		}
	}
}