using System;
using System.ComponentModel;
using System.Data;
using System.Windows.Forms;
using System.IO;
using System.Reflection;
using Medivators.Common;
using Medivators.Common.Logging;
using Medivators.Data.Queries;

namespace Medivators.Reporting
{
	public partial class dlgDatabaseTools : Form
	{
		private string _dbPath = string.Empty;

		public dlgDatabaseTools()
		{
			InitializeComponent();
		}
		private void dlgDatabaseTools_Load(object sender, EventArgs e)
		{
			this.dtpArchive.Value = DateTime.Now.Subtract(new TimeSpan(365, 0, 0, 0, 0));
		}

		public string DatabasePath
		{
			get { return _dbPath; }
			set { _dbPath = value; }
		}
		
		private void cmdCancel_Click(object sender, EventArgs e)
		{
			this.Dispose();
		}
		private void btnCompact_Click(object sender, EventArgs e)
		{
			if (WarnUser())
				DoCompact();
		}
		private void btnBackup_Click(object sender, EventArgs e)
		{
			if (WarnUser())
				DoBackup();
		}
		private void btnArchive_Click(object sender, EventArgs e)
		{
			if (DateTime.Compare((DateTime)dtpArchive.Value, DateTime.Now.Subtract(new TimeSpan(30, 0, 0, 0, 0))) > 0 )
				MsgBox.Show("Archive Date must be at least 30 days ago",
							"Database Tools",
							MessageBoxButtons.OK,
							MessageBoxIcon.Exclamation);
			else
				if (WarnUser())
					//	this may really annoy the user but an accidental, 
					//	casual mistake here would be really bad. 
					if (MsgBox.Show(
						string.Format("Please confirm your intention to Archive records older than {0}. There is no Undo!", this.dtpArchive.Value),
						"Database Tools",
						MessageBoxButtons.OKCancel,
						MessageBoxIcon.Question) == DialogResult.OK)
						if (MsgBox.Show(
							"Seriously, there is no Undo! Continue anyway?",
							"Database Tools",
							MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.Yes)
							DoArchive();
		}

		#region ** private database tool helpers

		private void DoCompact()
		{
			try
			{
				stallScreen(true);
				WriteLogEntry("Initiating database compact and repair");

				//	perform a backup, just in case
				DoBackup();

				// close this connection
				Medivators.Data.Connection.GetInstance().Close();

				// Start compacting and repairing
				object[] parms;

				//create an inctance of a Jet Replication Object
				object jro = Activator.CreateInstance(Type.GetTypeFromProgID("JRO.JetEngine"));

				//create a path to a temp file
				string tempDbName = Path.GetTempFileName() + ".mdb";

				//fill Parameters array
				parms = new object[] {Medivators.Data.Connection.GetInstance().ConnectionString,
										"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=\""  +
										tempDbName +
										"\";Jet OLEDB:Engine Type=5"};

				//invoke a CompactDatabase method of JRO 
				//pass Parameters array
				jro.GetType().InvokeMember("CompactDatabase",
					System.Reflection.BindingFlags.InvokeMethod,
					null,
					jro,
					parms);

				//database should now be compacted to temp file
				//need to move over old version

				File.Delete(this._dbPath);
				File.Move(tempDbName, this._dbPath);
				System.Runtime.InteropServices.Marshal.ReleaseComObject(jro);
				jro = null;

				WriteLogEntry("Database compact and repair successful");
				System.Threading.Thread.Sleep(2000);
				stallScreen(false);				
			}
			catch (Exception ex)
			{
				stallScreen(false);
				WriteLogEntry("Database compact and repair Exception: " + ex.ToString());

				//	no error codes in Jet errors. Does not throw a specific
				//	exception type either. Only way to handle one specific 
				//	kind of error is to do string comparison with the 
				//	innerexception message
				if (ex.InnerException.Message.ToLower().StartsWith("you attempted to open a database that is already"))
				{
					string wrkStation = ex.InnerException.Message.Split("'".ToCharArray())[3].Trim();

					using (dlgError dlg = new dlgError())
					{
						if (wrkStation == string.Empty)
							dlg.Message = ex.InnerException.Message;
						else
							dlg.Message = "Someone on workstation " + wrkStation + " is connected to the database.";
						dlg.Details = ex.ToString();
						dlg.ShowDialog();
					}
				}
				else

					using (dlgError dlg = new dlgError())
					{
						dlg.Message = string.Format("Error encountered while compacting database.");
						dlg.Details = ex.ToString();
						dlg.ShowDialog();
					}
			}
		}
		private void DoBackup()
		{
			try
			{
				//	makes a copy of the database file in the
				//	Database folder under the Application folder

				stallScreen(true);
				WriteLogEntry("Initiating database backup");

				string localDbFolder = Utilities.GetAppFolder();
				if (!localDbFolder.EndsWith("\\"))
					localDbFolder += "\\";
				localDbFolder += "Database";
				if (!(Directory.Exists(localDbFolder)))
					Directory.CreateDirectory(localDbFolder);
				localDbFolder += "\\";
				int backupVersion = 1;
				while (File.Exists(localDbFolder + "Medivators.Reporting.Backup." + backupVersion.ToString() + ".mdb"))
					backupVersion++;
				File.Copy(this._dbPath, localDbFolder + "Medivators.Reporting.Backup." + backupVersion.ToString() + ".mdb");

				WriteLogEntry("Database backup successful");
				System.Threading.Thread.Sleep(2000);
				stallScreen(false);

			}
			catch (Exception ex)
			{
				stallScreen(false);
				WriteLogEntry("Database backup Exception: " + ex.ToString());

				using (dlgError dlg = new dlgError())
				{
					dlg.Message = string.Format("Error encountered while compacting database.");
					dlg.Details = ex.ToString();
					dlg.ShowDialog();
				}
			}
		}
		private void DoArchive()
		{
			try
			{
				//	move records older than (archivedate) into archive tables

				stallScreen(true);
				WriteLogEntry("Initiating database archive");

				//	backup, just in case
				DoBackup();

				int rowCount = 0;

				//	start archiving
				ArchiveCycleReportLogRecords query1 = new ArchiveCycleReportLogRecords((DateTime)dtpArchive.Value);
				rowCount = query1.Insert();

				if (rowCount > 0)
				{
					ArchiveLogRecords query2 = new ArchiveLogRecords((DateTime)dtpArchive.Value);
					rowCount = query2.Insert();
				}
				if (rowCount > 0)
				{
					ArchiveCycleReports query3 = new ArchiveCycleReports((DateTime)dtpArchive.Value);
					rowCount = query3.Insert();
				}
				if (rowCount > 0)
					WriteLogEntry("Database archive successful");
				else
					MsgBox.Show("No records archived. Check the Archive Date (Logs may also show an error)");

				System.Threading.Thread.Sleep(2000);
				stallScreen(false);
			}
			catch (Exception ex)
			{
				stallScreen(false);
				WriteLogEntry("Database archive Exception: " + ex.ToString());

				using (dlgError dlg = new dlgError())
				{
					dlg.Message = string.Format("Error encountered while archiving database.");
					dlg.Details = ex.ToString();
					dlg.ShowDialog();
				}
			}
		}

		private void WriteLogEntry(string Message)
		{
			Log.GetInstance().WriteLog(Message);
		}
		private bool WarnUser()
		{
			return (MsgBox.Show("Please confirm that no other users are running Medivators.Reporting, and that the Medivators.Listener service is stopped.",
								"Database Tools",
								MessageBoxButtons.OKCancel,
								MessageBoxIcon.Exclamation) == DialogResult.OK);
		}
		private void stallScreen(bool ScreenOn )
		{
			if (ScreenOn)
			{
				this.panelStall.BringToFront();
				this.Cursor = Cursors.WaitCursor;
			}
			else
			{
				this.panelStall.SendToBack();
				this.Cursor = Cursors.Default;
			}
			this.panelStall.Visible = ScreenOn;
			this.Enabled = ! ScreenOn;
			Application.DoEvents();
		}
		#endregion
	}
}