using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;

using Infragistics.Win.Misc;
using Infragistics.Win.UltraWinGrid;
using Infragistics.Win.UltraWinTree;
using Infragistics.Win.UltraWinListView;

using Medivators.BusinessObjects;
using Medivators.Common;
using Medivators.Common.Enums;
using Medivators.Data;
using Medivators.Data.Queries;

namespace Medivators.Reporting
{
	public partial class frmCycles : frmBase
	{
		#region declarations

		private delegate void UpdateDisplay();
		private delegate void ClearCursor();

		private Dictionary<string, string> _filterCriteria = null;
		private List<UltraListViewItem> _availableReports = new List<UltraListViewItem>();
		private Dictionary<string, CycleReport> _availableCycleReports = new Dictionary<string, CycleReport>();
		private List<LogDisplayRecord> _logEvents = new List<LogDisplayRecord>();
		private SelectCycleReportsByFilterList _query = null;

		private bool _gridHasData = false;
		private string[] _gridColumnWidths = null;
		private bool _loading = false;
		private bool _exporting = false;

		#endregion

		#region construct/load/dispose

		public frmCycles()
		{
			try
			{
				InitializeComponent();
			}
			catch (Exception ex)
			{
				ErrorHandler.GetInstance().LogException("frmCycles Ctor InitializeComponent: ", ex);
			}
			btnCycles.BackColor = Color.Black;
			btnCycles.BackColorLight = Color.Green;
			btnCycles.Enabled = false;
			textCycles.Enabled = false;

		}
		private void frmCycles_Load(object sender, EventArgs e)
		{
			_loading = true;
			this.ucSelectCycles.SelectorsLoad();
			_loading = false;
		}
		public override void Dispose()
		{
			_availableReports.Clear();
			_availableCycleReports.Clear();
			base.Dispose();
		}

		#endregion

		public override Enums.Forms FormType
		{
			get { return Enums.Forms.Cycles; }
		}

		#region private helpers and delegate targets

		private void StopWaiting()
		{
			this.Cursor = Cursors.Default;
		}
		private void LoadReports()
		{
			lock (listAvailableReports)
			{
				this.listAvailableReports.Items.Clear();
				if (_availableReports != null)
					foreach (UltraListViewItem item in _availableReports)
						listAvailableReports.Items.Add(item);
			}
		}
		private void EnableButtons()
		{
			this.btnExport.Enabled = true;
			this.btnPageSetup.Enabled = true;
			this.btnPrint.Enabled = true;
			this.btnPrintPreview.Enabled = true;
		}

		#endregion

		#region loading available reports

		private void ucSelectCycles_FilterCriteriaChanged(object sender, ucSelector.FilterCriteriaChangedEventArgs e)
		{
			try
			{
				if (!_loading)
				{
					if (e != null)
					{
						if (e.FilterCriteria != null)
						{
							if (e.FilterCriteria.Count > 0)
							{
								if (_filterCriteria != null)
									_filterCriteria.Clear();
								else
									_filterCriteria = new Dictionary<string, string>();
								foreach (KeyValuePair<string, string> item in e.FilterCriteria)
									_filterCriteria.Add(item.Key, item.Value);
								RefreshData();
							}
						}
					}
				}
			}
			catch (Exception ex)
			{
				using (dlgError dlg = new dlgError())
				{
					dlg.Message = "Error encountered loading data for the Available Reports list.";
					dlg.Details = ex.ToString();
					dlg.ShowDialog();
				}
				ErrorHandler.GetInstance().LogException("Cycle Reports form FilterCriteriaChanged:", ex);
				this.Invoke(new ClearCursor(this.StopWaiting));
			}
		}
		private void ucAutoRefresh_AutoRefreshTimerElapsed(object sender, EventArgs e)
		{
			RefreshData();
			ucSelectCycles.SelectorsLoad();
		}
		private void RefreshData()
		{
			try
			{
				if (_filterCriteria == null || _filterCriteria.Count <= 0)
				{
					if (this.ucSelectCycles == null)
						_filterCriteria = new Dictionary<string, string>();
					else
						_filterCriteria = ucSelectCycles.GetSelectedFilters();
				}
				else
				{
					if (_query == null)
					{
						_query = new SelectCycleReportsByFilterList();
						_query.DataException += new DataExceptionEventHandler(SelectError);
						_query.SelectComplete += new SelectCompleteEventHandler(SelectComplete);
					}
					_query.Select(_filterCriteria);
				}
			}
			catch (Exception ex)
			{
				ErrorHandler.GetInstance().LogException("Cycle Reports form RefreshData:", ex);
			}
		}

		private void SelectComplete(object sender, SelectCompleteEventArgs e)
		{
			List<UltraListViewItem> items = new List<UltraListViewItem>();
			Dictionary<string, CycleReport> reports = new Dictionary<string, CycleReport>();

			try
			{
				foreach (CycleReport rpt in ((CycleReportDataMapper)e.Data).BusinessObjectCollection)
				{
					//	before getting into the tawdry task of jumping
					//	through the poorly documented hoops of the UltraListView's
					//  add methods, here we have a perfectly lovely CycleReport
					//	all formatted and everything. Seems a shame to waste that
					//	particularly since we may need it later... 

					reports.Add(rpt.Key, rpt);

					//	and now diving into the mundane

					UltraListViewSubItem[] siCol = new UltraListViewSubItem[3];
					UltraListViewSubItem si0 = new UltraListViewSubItem();
					si0.Value = rpt.EndTimestamp;
					siCol[0] = si0;

					UltraListViewSubItem si1 = new UltraListViewSubItem();
					si1.Value = rpt.MachineID;
					siCol[1] = si1;

					UltraListViewSubItem si2 = new UltraListViewSubItem();
					si2.Value = rpt.Key;
					siCol[2] = si2;

					UltraListViewItem itm = new UltraListViewItem(rpt.StartTimestamp, siCol);
					items.Add(itm);

				}
				//	update reports cache list to class-level version 
				lock (_availableCycleReports)
				{
					_availableCycleReports = reports;
				}

				//	update list to class-level version and invoke
				//	a delegate to load the list into the listview
				lock (_availableReports)
				{
					_availableReports = items;
				}
				UpdateDisplay add = this.LoadReports;
				listAvailableReports.Invoke(add);
			}
			catch (Exception ex)
			{
				using (dlgError dlg = new dlgError())
				{
					dlg.Message = "Error encountered loading data for the Available Reports list.";
					dlg.Details = ex.ToString();
					dlg.ShowDialog();
				}
				ErrorHandler.GetInstance().LogException("Cycle Reports form Tree_AfterSelect:", ex);
			}
			finally
			{
				items.Clear();
				this.Invoke(new ClearCursor(this.StopWaiting));
			}
		}
		private void SelectError(object sender, DataExceptionEventArgs e)
		{
			string details = string.Format("SQL = {0}\r\n\r\nEX = {1}",
										   e.SQL, e.Ex);
			using (dlgError dlg = new dlgError())
			{
				dlg.Message = "Error encountered selecting data for the Available Reports list.";
				dlg.Details = details;
				dlg.ShowDialog();
			}
			ErrorHandler.GetInstance().LogException("Cycle Reports form SelectError :" + details);
			if (!this.Disposing)
				if (this.Cursor.Equals(Cursors.WaitCursor))
					this.Invoke(new ClearCursor(this.StopWaiting));
		}

		#endregion

		#region displaying the selected report

		private void listAvailableReports_ItemSelectionChanged(object sender, ItemSelectionChangedEventArgs e)
		{
			//	we should have the selected report cached. This means 
			//	a fairly straightforward data copying process that
			//	can be done right in the main thread. 
			try
			{
				CycleReport rpt = null;
				string key = e.SelectedItems[0].SubItems[2].Value.ToString();
				if (!_availableCycleReports.ContainsKey(key))
				{
					using (dlgError dlg = new dlgError())
					{
						dlg.Message = "Error encountered while populating the selected Cycle Report.";
						dlg.Details = string.Format("Expected caching of report {0}", key);
						dlg.ShowDialog();
					}
					ErrorHandler.GetInstance().LogException(string.Format("CycleReports reacquiring report {0} from cache - Not Found! ", key));
				}
				else
				{
					rpt = _availableCycleReports[key];
					lblCycleCount.Text = rpt.CycleCount.ToString();
					lblDisinfectantCycleCount.Text = rpt.DisinfectantCycleCount.ToString();
					lblEndTimestamp.Text = rpt.EndTimestamp.ToString();
					lblMachineID.Text = rpt.MachineID.ToString();
					lblOperator.Text = rpt.OperatorID.ToString("000000000");
					lblPatient.Text = rpt.PatientID.ToString("000000000");
					lblPhysician.Text = rpt.PhysicianID.ToString("000000000");
					lblScope.Text = rpt.ScopeID.ToString("000000000");
					lblStartTimestamp.Text = rpt.StartTimestamp.ToString();
					lblStation.Text = rpt.Station;

					//	now load the grid
					_logEvents.Clear();
					foreach (IBusinessObject obj in rpt.LogRecords)
					{
						LogDisplayRecord rec = new LogDisplayRecord(obj);
						_logEvents.Add(rec);
					}
					grid.DataSource = _logEvents;
					//	by default, grid suppresses Time portion of timestamp
					this.grid.DisplayLayout.Bands[0].Columns["Timestamp"].Format = "MM-dd-yyyy HH:mm";
					grid.DataBind();
					//	orderby sortkey column
					grid.DisplayLayout.Bands[0].SortedColumns.Add("SortKey", false);
					//  apply column widths, if any were persisted
					SetColumnWidths();
				}

			}
			catch (Exception ex)
			{
				using (dlgError dlg = new dlgError())
				{
					dlg.Message = "Error encountered while populating the selected Cycle Report.";
					dlg.Details = ex.ToString();
					dlg.ShowDialog();
				}
				ErrorHandler.GetInstance().LogException("Cycle Reports form loading selected report:", ex);
			}
		}

		#endregion

		#region formatting grid display

		private void grid_InitializeRow(object sender, Infragistics.Win.UltraWinGrid.InitializeRowEventArgs e)
		{
			bool rowWritten = false;

			if (((LogDisplayRecord)e.Row.ListObject).IsAlarm)
			{
				e.Row.Appearance.FontData.Bold = Infragistics.Win.DefaultableBoolean.True;
				e.Row.Appearance.ForeColor = Color.Red;
				rowWritten = true;
			}
			else
			{
				e.Row.Appearance.FontData.Bold = Infragistics.Win.DefaultableBoolean.False;
				e.Row.Appearance.ForeColor = SystemColors.ControlText;

				//	do not display data that is already present in the 
				//	report header - unless exporting, when there will be no header
				if (_exporting)
					e.Row.Hidden = false;
				else
				{
					switch (((LogDisplayRecord)e.Row.ListObject).RecordType)
					{
						case DeviceRecordTypes.CycleCount:
						case DeviceRecordTypes.DisinfectantCycleCount:
						case DeviceRecordTypes.OperatorID:
						case DeviceRecordTypes.PatientID:
						case DeviceRecordTypes.PhysicianID:
						case DeviceRecordTypes.ScopeID:
							e.Row.Hidden = true;
							break;
						default:
							rowWritten = true;
							break;
					}
				}
			}
			if (rowWritten)
			{
				//	on first time through only - enable the feature buttons 
				//	that require data to be in the grid
				if (! _gridHasData && ! _exporting)
				{
					_gridHasData = true;
					this.Invoke(new UpdateDisplay(EnableButtons));
				}
			}
		}
		private void SetColumnWidths()
		{
			if (_gridColumnWidths != null)
			{
				for (int idx = 0; idx < grid.DisplayLayout.Bands[0].Columns.Count; idx++)
					if (_gridColumnWidths.Length > idx)
						if (_gridColumnWidths[idx].Length > 0)
							grid.DisplayLayout.Bands[0].Columns[idx].Width = Convert.ToInt32(_gridColumnWidths[idx]);
			}
		}

		#endregion

		#region feature command buttons

		#region *	manual handling command button Focus and LostFocus

		private void Command_Focus(object sender, EventArgs e)
		{
			((UltraButton)sender).Appearance.FontData.Bold = Infragistics.Win.DefaultableBoolean.True;
		}
		private void Command_Unfocus(object sender, EventArgs e)
		{
			((UltraButton)sender).Appearance.FontData.Bold = Infragistics.Win.DefaultableBoolean.False;
		}

		#endregion

		private void btnExport_Click(object sender, EventArgs e)
		{
			try
			{
				if (openExportFile.ShowDialog() == DialogResult.OK)
				{
					_exporting = true;
					this.grid.DisplayLayout.Bands[0].Columns["MachineID"].Hidden = false;
					this.gridExport.Export(grid, openExportFile.FileName);
					this.grid.DisplayLayout.Bands[0].Columns["MachineID"].Hidden = true;
					_exporting = false;
				}
			}
			catch (Exception ex)
			{
				App.ShowError("Error encountered while exporting file. Export was not sucessful", ex);
			}
		}
		private void btnPrint_Click(object sender, EventArgs e)
		{
			try
			{

				gridPrint.Print();
			}
			catch (Exception ex)
			{
				App.ShowError("Error printing report.", ex);
			}
		}
		private void btnPageSetup_Click(object sender, EventArgs e)
		{
			try
			{
				pageSetup.ShowDialog();
			}
			catch (Exception ex)
			{
				App.ShowError("Error encountered during page setup.", ex);
			}
		}
		private void btnPrintPreview_Click(object sender, EventArgs e)
		{
			try
			{
				using (dlgPrintPreview dlg = new dlgPrintPreview())
				{
					dlg.Document = gridPrint;
					dlg.ShowDialog();
				}
			}
			catch (Exception ex)
			{
				App.ShowError("Error encountered while previewing the report.", ex);
			}
		}

		#endregion

		private void gridPrint_PageHeaderPrinting(object sender, Infragistics.Win.Printing.HeaderFooterPrintingEventArgs e)
		{
			//	we need to add the textboxes and labels to the cycle report. 
			//	the simplest way to do this would seem to be to just clip the
			//	panel containing the cycle report header controls and sort of
			//	paste them into the rendering graphics object here.
			try
			{
				Panel pnl = pnlCycleReportHeader;
				Bitmap bmp = new Bitmap(pnl.Width, pnl.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
				pnl.DrawToBitmap(bmp, new Rectangle(0, 0, pnl.Width, pnl.Height));
				e.Graphics.DrawImage(bmp, e.RectInsideBorders.Location);
				e.Handled = true;
			}
			catch (Exception ex)
			{
				App.ShowError("Error encountered while rendering the Cycle Report page header.", ex);
			}
		}

		#region persisted form settings

		protected override void LoadState()
		{
			base.LoadState();

			// load page setup
			string wrk = string.Empty;

			wrk = TextSettings.GetInstance()[SettingTypes.User, this.Name, "Landscape"];
			if (!wrk.Equals(string.Empty))
				this.pageSetup.PageSettings.Landscape = Convert.ToBoolean(wrk);

			wrk = TextSettings.GetInstance()[SettingTypes.User, this.Name, "Margins.Left"];
			if (!wrk.Equals(string.Empty))
				this.pageSetup.PageSettings.Margins.Left = Convert.ToInt32(wrk);
			wrk = TextSettings.GetInstance()[SettingTypes.User, this.Name, "Margins.Right"];
			if (!wrk.Equals(string.Empty))
				this.pageSetup.PageSettings.Margins.Right = Convert.ToInt32(wrk);
			wrk = TextSettings.GetInstance()[SettingTypes.User, this.Name, "Margins.Top"];
			if (!wrk.Equals(string.Empty))
				this.pageSetup.PageSettings.Margins.Top = Convert.ToInt32(wrk);
			wrk = TextSettings.GetInstance()[SettingTypes.User, this.Name, "Margins.Bottom"];
			if (!wrk.Equals(string.Empty))
				this.pageSetup.PageSettings.Margins.Bottom = Convert.ToInt32(wrk);

			//	autorefresh
			wrk = TextSettings.GetInstance()[SettingTypes.User, this.Name, "AutoRefresh"];
			if (!wrk.Equals(string.Empty))
				this.autoRefreshTimer.AutoRefreshEnabled = Convert.ToBoolean(wrk);

			// get and unparse column widths - but do not
			// apply them until later when binding data
			wrk = TextSettings.GetInstance()[SettingTypes.User, this.Name, "Columns"];
			if (!wrk.Equals(string.Empty))
			{
				this._gridColumnWidths = wrk.Split(Constants.ElementDelimiter.ToCharArray()[0]);
			}

			//	size panels
			this.SuspendLayout();
			wrk = TextSettings.GetInstance()[SettingTypes.User, this.Name, "Selectors.Width"];
			if (!wrk.Equals(string.Empty))
				this.pnlSelectors.Width = Convert.ToInt32(wrk);
			wrk = TextSettings.GetInstance()[SettingTypes.User, this.Name, "AvailableReports.Height"];
			if (!wrk.Equals(string.Empty))
				this.panelAvailableReports.Height = Convert.ToInt32(wrk);
			this.ResumeLayout();
			
		}
		protected override void SaveState()
		{
			base.SaveState();

			// save page setup
			TextSettings.GetInstance()[SettingTypes.User, this.Name, "Landscape"] = this.pageSetup.PageSettings.Landscape.ToString();
			TextSettings.GetInstance()[SettingTypes.User, this.Name, "Margins.Left"] = this.pageSetup.PageSettings.Margins.Left.ToString();
			TextSettings.GetInstance()[SettingTypes.User, this.Name, "Margins.Top"] = this.pageSetup.PageSettings.Margins.Top.ToString();
			TextSettings.GetInstance()[SettingTypes.User, this.Name, "Margins.Right"] = this.pageSetup.PageSettings.Margins.Right.ToString();
			TextSettings.GetInstance()[SettingTypes.User, this.Name, "Margins.Bottom"] = this.pageSetup.PageSettings.Margins.Bottom.ToString();

			// autorefresh
			TextSettings.GetInstance()[SettingTypes.User, this.Name, "AutoRefresh"] = this.autoRefreshTimer.AutoRefreshEnabled.ToString();

			// save grid column widths
			if (_gridHasData)
			{
				string setting = string.Empty;
				foreach (UltraGridColumn col in grid.DisplayLayout.Bands[0].Columns)
					setting += col.Width.ToString() + Constants.ElementDelimiter;
				if (setting != string.Empty)
					TextSettings.GetInstance()[SettingTypes.User, this.Name, "Columns"] = setting;
			}
			// save panel sizes
			TextSettings.GetInstance()[SettingTypes.User, this.Name, "Selectors.Width"] = this.pnlSelectors.Width.ToString();
			TextSettings.GetInstance()[SettingTypes.User, this.Name, "AvailableReports.Height"] = this.panelAvailableReports.Height.ToString();
		}

		#endregion
	}
}

