using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Configuration;
using Howest.Guidance.DataAccess.CodeGeneration.ObjectModel;
using Howest.Guidance.DataAccess.CustomWizardPages.Helpers;
using SD = Howest.SchemaDiscovery.DbObjects;
using Howest.Guidance.DataAccess.CodeGeneration.ObjectModel.Mappings;
using Howest.Guidance.DataAccess.CodeGeneration.ObjectModel.Mappings.Helpers;
using Howest.Guidance.DataAccess.CodeGeneration.ObjectModel.Mappings.Enums;

namespace Howest.Guidance.DataAccess.CustomWizardPages
{
	public partial class SqlOutputMappingForm : Form
	{

		#region Fields
		Operation _operation = Operation.Add;
		#endregion

		#region Properties
		private Entity _entity;

		public Entity Entity
		{
			get { return _entity; }
			set { _entity = value; }
		}

		private string _mappingName;

		public string MappingName
		{
			get { return _mappingName; }
			set { _mappingName = value; }
		}

		private ConnectionStringSettings _connectionSettings;

		public ConnectionStringSettings ConnectionSettings
		{
			get { return _connectionSettings; }
			set { _connectionSettings = value; }
		}
		#endregion

		#region Constructors

		public SqlOutputMappingForm(ConnectionStringSettings settings, Entity entity)
			: this(settings, entity, Operation.Add, "")
		{

		}
		public SqlOutputMappingForm(ConnectionStringSettings settings, Entity entity, Operation operation, string mappingName)
			: this()
		{
			_connectionSettings = settings;
			_entity = entity;
			_operation = operation;
			_mappingName = mappingName;

			SetControls();
			cboTableView.Items.Clear();

			Cursor.Current = Cursors.WaitCursor;

			try
			{
				List<SD.Table> tables =
					UIHelper.GetTables(_connectionSettings);

				UIHelper.FillTablesCombo<SD.Table>(cboTableView, tables);

				List<SD.View> views =
					UIHelper.GetViews(_connectionSettings);

				UIHelper.FillTablesCombo<SD.View>(cboTableView, views);

				SD.Table custTab = new SD.Table();
				custTab.Fullname = "custom";
				custTab.Name = "custom";
				custTab.Schema = "dbo";

				cboTableView.Items.Add(custTab);
			}
			catch(Exception ex)
			{
				//We cannot use IUIService on an external winform page
				//MessageBox.Show(ex.Message);
				MessageBox.Show(
					"There was an error trying to obtain the list of tables and views",
					"Error");
			}

			Cursor.Current = Cursors.Default;

			if (_operation == Operation.Edit)
			{
				ProvideValues();
			}
		}

		public SqlOutputMappingForm()
		{
			InitializeComponent();
		}

		#endregion

		private void SetControls()
		{
			cboTableView.DisplayMember = "Fullname";
			lstOutputColumns.DisplayMember = "Parameter.DBName";
			txtEntity.Text = _entity.Name;
			txtMappingName.Text = string.Empty;
			txtMappingName.Enabled = (_operation == Operation.Add);
			cboTableView.Enabled = (_operation == Operation.Add);
			btnAddSql.Enabled = true;
			btnEditSql.Enabled = false;
			btnDeleteSql.Enabled = false;
			txtMappingName.Focus();
		}

		private void ProvideValues()
		{
			//UIHelper.Finder = NamingHelper.GetOperationName(this.operationName);
			EntitySqlStatementMapping mapping = _entity.SqlStatementMappings.Find(delegate(EntitySqlStatementMapping listMapping)
			{
				if (listMapping.MappingName == _mappingName)
					return true;
				return false;
			});

			if (mapping != null)
			{
				txtMappingName.Text = mapping.MappingName;
				cboTableView.SelectedItem = UIHelper.FindTable(cboTableView, mapping.TableName);
			}
		}

		private void LoadMappings()
		{
			CleanCombos();

			foreach (Property prop in (_entity.Properties))
			{
				lstEntityProperties.Items.Add(prop.Name);
			}

			Cursor.Current = Cursors.WaitCursor;

			try
			{
				SD.Table tab = (SD.Table)cboTableView.SelectedItem;

				if (tab.Fullname != "custom")
				{
					List<SqlStatement> statements = UIHelper.GetSelectStatements(/*_connectionSettings,*/ tab);
					UIHelper.FillStatementsListView(lvwSqlStatements, statements);

					List<SD.Parameter> parameters =
						UIHelper.GetParameters(_connectionSettings, statements[0].Sql, ParameterDirection.ReturnValue);

					UIHelper.FillParametersListBox(lstOutputColumns, parameters);
				}
				else
				{
					if (lvwSqlStatements.Items.Count > 0)
					{
						List<SD.Parameter> parameters =
						UIHelper.GetParameters(_connectionSettings, ((SqlStatement)lvwSqlStatements.Items[0].Tag).Sql, ParameterDirection.ReturnValue);

						UIHelper.FillParametersListBox(lstOutputColumns, parameters);
					}
				}
				//List<SD.Parameter> parameters =
				//    UIHelper.GetParameters(
				//        connectionSettings,
				//        (StoredProcedure)cmbStoredProcedures.SelectedItem,
				//        ParameterDirection.ReturnValue);

				//UIHelper.FillParametersListBox(lstOutputColumns, parameters);
			}
			catch(Exception ex)
			{
				//We cannot use IUIService on an external winform page
				MessageBox.Show(ex.Message);
				MessageBox.Show(
					"There was an error trying to obtain the table or view result set.",
					"Error");
			}

			Cursor.Current = Cursors.Default;
		}

		private void CleanCombos()
		{
			lstEntityProperties.Items.Clear();
			lstOutputColumns.Items.Clear();
			lstMappings.Items.Clear();
		}

		private bool ValidateMappingName()
		{
			frmErrorProvider.SetError(txtMappingName, null);
			if(string.IsNullOrEmpty(txtMappingName.Text))
			{
				frmErrorProvider.SetError(txtMappingName, "Mapping name cannot be an empty name");
				return false;
			}
			return true;
		}

		private bool IsInputValid()
		{
			frmErrorProvider.SetError(txtMappingName, null);
			frmErrorProvider.SetError(cboTableView, null);
			frmErrorProvider.SetError(lvwSqlStatements, null);
			frmErrorProvider.SetError(lstMappings, null);

			if (_operation == Operation.Add)
			{
				if (!ValidateMappingName())
				{
					return false;
				}

				//UIHelper.Finder = NamingHelper.GetOperationName(txtOperationName.Text);
				EntitySqlStatementMapping mapping = _entity.SqlStatementMappings.Find(delegate(EntitySqlStatementMapping listMapping){
					return listMapping.MappingName == txtMappingName.Text;
				});

				if (mapping != null)
				{
					frmErrorProvider.SetError(txtMappingName, "There is another mapping configuration with the same name.");
					return false;
				}
				//else
				//{
				//    UIHelper.Finder = ((StoredProcedure)cmbStoredProcedures.SelectedItem).Name;
				//    mapping = this.entity.StoredProcedureMappings.Find(UIHelper.FindByStoredProcedureName);

				//    if (mapping != null)
				//    {
				//        frmErrorProvider.SetError(cmbStoredProcedures, Properties.Resources.MappingWithSameSPName);
				//        return false;
				//    }
				//}
			}

			if (cboTableView.SelectedItem == null)
			{
				frmErrorProvider.SetError(cboTableView, "Provide table or view");
				return false;
			}

			//if (this.opType != OperationType.DeleteOne)
			//{
			//    if (lstMappings.Items.Count == 0)
			//    {
			//        frmErrorProvider.SetError(lstMappings, Properties.Resources.ProvideMapping);
			//        return false;
			//    }
			//}

			return true;
		}

		private void SaveMapping()
		{
			//const string IDENTITY = "Identity";
			SD.Table tab = (SD.Table)cboTableView.SelectedItem;
			//UIHelper.Finder = NamingHelper.GetOperationName(txtOperationName.Text);
			EntitySqlStatementMapping sqlMapping = _entity.SqlStatementMappings.Find(delegate(EntitySqlStatementMapping listMapping){
				return listMapping.MappingName == txtMappingName.Text;
			});

			if (sqlMapping == null)
			{
				sqlMapping =
					new EntitySqlStatementMapping(
					txtMappingName.Text,
					tab.Fullname, SqlStatementMappingType.Output);
			}
			else
			{
				_entity.SqlStatementMappings.Remove(sqlMapping);
				//sqlMapping.Procedure = sp.Name;
				//sqlMapping.ProcedureHasInputParameters = (UIHelper.GetParameters(this.connectionSettings, sp, ParameterDirection.Input).Count > 0);
				//sqlMapping.OperationName = NamingHelper.GetOperationName(txtOperationName.Text);
				sqlMapping.ParameterMappings.Clear();
				sqlMapping.Statements.Clear();
				//sqlMapping.Identity = null;
			}

			foreach (PropertyParameterMapping mapping in lstMappings.Items)
			{
				//PropertyParameterMapping mapping = (PropertyParameterMapping)item;

				sqlMapping.ParameterMappings.Add(mapping);
			}

			foreach (ListViewItem item in lvwSqlStatements.Items)
			{
				if (item.Checked)
				{
					sqlMapping.Statements.Add((SqlStatement)item.Tag);
				}
			}

			//Identity identity = new Identity();
			//identity.Name = NamingHelper.GetOperationName(txtOperationName.Text) + IDENTITY;

			//foreach (object item in lstInputParameters.Items)
			//{
			//    Parameter parameter = (Parameter)item;
			//    PropertyParameterMapping mapping =
			//        new PropertyParameterMapping(parameter.Name,
			//        ClonerHelper.CloneParameter(parameter));

			//    identity.ParameterMappings.Add(mapping);
			//}

			//sqlMapping.Identity = identity;

			_entity.SqlStatementMappings.Add(sqlMapping);
		}

		private void RefreshMappings(EntitySqlStatementMapping mapping)
		{
			CleanCombos();

			foreach (PropertyParameterMapping parameterMapping in mapping.ParameterMappings)
			{
				lstMappings.Items.Add(parameterMapping);
			}

			foreach (Property prop in _entity.Properties)
			{
				if (UIHelper.FindProperty(lstMappings, prop.Name) == null)
				{
					lstEntityProperties.Items.Add(prop.Name);
				}
			}

			Cursor.Current = Cursors.WaitCursor;

			try
			{
				SD.Table tab = (SD.Table)cboTableView.SelectedItem;

				if (tab.Fullname != "custom")
				{
					List<SqlStatement> statements = UIHelper.GetSelectStatements(/*_connectionSettings,*/ tab);
					UIHelper.FillStatementsListView(lvwSqlStatements, statements);

					UIHelper.FillStatementsListView(lvwSqlStatements, mapping.Statements, true, true);

					List<SD.Parameter> parameters =
						UIHelper.GetParameters(_connectionSettings, statements[0].Sql, ParameterDirection.ReturnValue);
					parameters = parameters.FindAll(delegate(SD.Parameter par) {
						return UIHelper.FindParameter(lstMappings, par.Name) == null;
					});
					UIHelper.FillParametersListBox(lstOutputColumns, lstMappings, parameters);
				}
				else
				{
					UIHelper.FillStatementsListView(lvwSqlStatements, mapping.Statements, true);
					if (lvwSqlStatements.Items.Count > 0)
					{
						List<SD.Parameter> parameters =
						UIHelper.GetParameters(_connectionSettings, ((SqlStatement)lvwSqlStatements.Items[0].Tag).Sql, ParameterDirection.ReturnValue);

						parameters = parameters.FindAll(delegate(SD.Parameter par)
						{
							return UIHelper.FindParameter(lstMappings, par.Name) == null;
						});
						UIHelper.FillParametersListBox(lstOutputColumns, lstMappings, parameters);
					}
				}
				//List<Parameter> parameters =
				//    UIHelper.GetParameters(
				//        connectionSettings,
				//        (StoredProcedure)cmbStoredProcedures.SelectedItem,
				//        ParameterDirection.ReturnValue);

				//UIHelper.FillParametersListBox(lstOutputColumns, lstMappings, parameters);
			}
			catch
			{
				//We cannot use IUIService on an external winform page
				MessageBox.Show(
					"There was an error trying to obtain the table or view result set.",
					"Error");
			}

			Cursor.Current = Cursors.Default;
		}

		private void cboTableView_SelectedIndexChanged(object sender, EventArgs e)
		{
			bool founded = false;
			SD.Table tab = (SD.Table)cboTableView.SelectedItem;

			lvwSqlStatements.Items.Clear();
			lstOutputColumns.Items.Clear();


			if (_operation == Operation.Edit)
			{
				foreach (EntitySqlStatementMapping mapping in _entity.SqlStatementMappings)
				{
					if (mapping.MappingName == _mappingName && tab.Fullname == mapping.TableName)
					{
						//if (tab.Fullname != "custom")
						//{
						//    List<SqlStatement> list = UIHelper.GetSelectStatements(_connectionSettings, tab);
						//    UIHelper.FillStatementsListView(lvwSqlStatements, list);
						//}
						RefreshMappings(mapping);
						founded = true;
						break;
					}
				}
			}
			else
			{
				txtMappingName.Text = tab.Name + "_Mapping";
			}

			if (!founded)
			{
				LoadMappings();
			}
		}

		private void btnAddMapping_Click(object sender, EventArgs e)
		{
			if (!UIGuard.IsListBoxSelected(lstEntityProperties) || !UIGuard.IsListBoxSelected(lstOutputColumns))
			{
				return;
			}

			PropertyParameterMapping mapping =
			new PropertyParameterMapping(
				lstEntityProperties.SelectedItem.ToString(),
				ClonerHelper.CloneParameter((SD.Parameter)lstOutputColumns.SelectedItem));

			lstEntityProperties.Items.Remove(lstEntityProperties.SelectedItem);
			lstOutputColumns.Items.Remove(lstOutputColumns.SelectedItem);
			lstMappings.Items.Add(mapping);

			lstMappings.SelectedIndex = 0;
		}

		private void btnDeleteMapping_Click(object sender, EventArgs e)
		{
			if (!UIGuard.IsListBoxChecked(lstMappings))
			{
				return;
			}

			UIHelper.RemoveMappingItems(lstEntityProperties, lstOutputColumns, lstMappings);
		}

		private void btnOk_Click(object sender, EventArgs e)
		{
			if (IsInputValid())
			{
				SaveMapping();
				DialogResult = DialogResult.OK;
			}
		}

		private void btnCancel_Click(object sender, EventArgs e)
		{
			DialogResult = DialogResult.Cancel;
		}

		private void btnAddSql_Click(object sender, EventArgs e)
		{
			SqlEdit edit = new SqlEdit(_connectionSettings, null, null);
			if (edit.ShowDialog(this) == DialogResult.OK)
			{
				UIHelper.AddStatementToListView(lvwSqlStatements, edit.Statement, true);
				if (lvwSqlStatements.Items.Count == 0)
				{
					LoadMappings();
				}
			}
		}

		private void btnEditSql_Click(object sender, EventArgs e)
		{
			List<SD.Parameter> pars = null;
			if (lvwSqlStatements.Items.Count > 1)
			{
				SqlStatement statement = (SqlStatement)lvwSqlStatements.Items[0].Tag;
				pars = UIHelper.GetParameters(_connectionSettings, statement.Sql, ParameterDirection.ReturnValue);
			}
			SqlEdit edit = new SqlEdit(_connectionSettings, (SqlStatement)lvwSqlStatements.SelectedItems[0].Tag, pars);
			if (edit.ShowDialog(this) == DialogResult.OK)
			{
				bool check = lvwSqlStatements.SelectedItems[0].Checked;
				lvwSqlStatements.SelectedItems[0].Remove();
				UIHelper.AddStatementToListView(lvwSqlStatements, edit.Statement, check);
				if (lvwSqlStatements.Items.Count == 1)
				{
					LoadMappings();
				}
			}
		}

		private void btnDeleteSql_Click(object sender, EventArgs e)
		{
			if (lvwSqlStatements.SelectedItems.Count > 0)
				lvwSqlStatements.SelectedItems[0].Remove();
		}

		private void lvwSqlStatements_SelectedIndexChanged(object sender, EventArgs e)
		{
			if (lvwSqlStatements.SelectedItems.Count > 0)
			{
				SqlStatement statement = (SqlStatement)lvwSqlStatements.SelectedItems[0].Tag;
				if (statement.IsReadOnly)
				{
					btnAddSql.Enabled = true;
					btnEditSql.Enabled = true;
					btnDeleteSql.Enabled = false;
				}
				else
				{
					btnAddSql.Enabled = true;
					btnEditSql.Enabled = true;
					btnDeleteSql.Enabled = false;
				}
			}
			else
			{
				btnAddSql.Enabled = true;
				btnEditSql.Enabled = false;
				btnDeleteSql.Enabled = false;
			}
		}

		private void txtMappingName_Leave(object sender, EventArgs e)
		{
			ValidateMappingName();
		}
	}
}