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

namespace Howest.Guidance.DataAccess.CustomWizardPages
{
	public partial class SqlInputMappingForm : Form
	{
		#region Fields
		Operation _operation = Operation.Add;
		OperationType _opType = OperationType.InsertOne;
		#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

		public SqlInputMappingForm(ConnectionStringSettings settings, Entity entity, OperationType opType)
			: this(settings, entity, Operation.Add, opType, "")
		{

		}

		public SqlInputMappingForm(ConnectionStringSettings settings, Entity entity, Operation operation, OperationType opType, string mappingName)
			: this()
		{
			_connectionSettings = settings;
			_entity = entity;
			_operation = operation;
			_mappingName = mappingName;
			_opType = opType;

			SetControls();
			cboTable.Items.Clear();

			Cursor.Current = Cursors.WaitCursor;

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

				UIHelper.FillTablesCombo<SD.Table>(cboTable, tables);
			}
			catch (Exception)
			{
				//We cannot use IUIService on an external winform page
				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 SqlInputMappingForm()
		{
			InitializeComponent();
		}

		private void SetControls()
		{
			cboTable.DisplayMember = "Fullname";
			lstInputParameters.DisplayMember = "Parameter.DBName";
			txtEntity.Text = _entity.Name;
			txtOperationName.Text = string.Empty;
			txtOperationName.Focus();
			switch (_opType)
			{
				case OperationType.InsertOne:
					btnGenerate.Text = "Create Insert";
					break;
				case OperationType.DeleteOne:
					btnGenerate.Text = "Create Delete";
					break;
				case OperationType.UpdateOne:
					btnGenerate.Text = "Create Update";
					break;
				default:
					break;
			}
		}

		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)
			{
				txtOperationName.Text = mapping.Statements[0].MethodName;
				txtSQL.Text = mapping.Statements[0].Sql;
				RefreshMappings(mapping);
			}
		}

		private void LoadMappings()
		{
			CleanCombos();

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

			Cursor.Current = Cursors.WaitCursor;

			try
			{
				List<SD.Parameter> parameters = UIHelper.GetParameters(
					_connectionSettings,
					txtSQL.Text, ParameterDirection.Input);
				UIHelper.FillParametersListBox(lstInputParameters, 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();
			lstInputParameters.Items.Clear();
			lstMappings.Items.Clear();
		}

		private bool ValidateOperationName()
		{
			frmErrorProvider.SetError(txtOperationName, null);
			try
			{
				txtOperationName.Text = CodeDomHelper.ConvertToValidIdentifier(txtOperationName.Text);
				return true;
			}
			catch (Exception ex)
			{
				frmErrorProvider.SetError(txtOperationName, ex.Message);
				return false;
			}
		}

		private bool ValidateSQLStatement()
		{
			frmErrorProvider.SetError(txtSQL, null);
			try
			{
				UIHelper.RunSqlStatement(_connectionSettings, txtSQL.Text);
				return true;
			}
			catch (Exception ex)
			{
				frmErrorProvider.SetError(txtSQL, ex.Message);
				return false;
			}
		}

		private bool IsInputValid()
		{
			frmErrorProvider.SetError(txtOperationName, null);
			frmErrorProvider.SetError(cboTable, null);
			frmErrorProvider.SetError(lstMappings, null);

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

				if (!ValidateSQLStatement())
				{
					return false;
				}

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

				if (mapping != null)
				{
					frmErrorProvider.SetError(txtOperationName, "There is another mapping configuration with the same name.");
					return false;
				}
			}

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

			return true;
		}

		private void SaveMapping()
		{
			SD.Table tab = (SD.Table)cboTable.SelectedItem;
			
			EntitySqlStatementMapping sqlMapping = _entity.SqlStatementMappings.Find(delegate(EntitySqlStatementMapping listMapping)
			{
				return listMapping.MappingName == txtOperationName.Text;
			});

			if (sqlMapping == null)
			{
				sqlMapping =
					new EntitySqlStatementMapping(
					txtOperationName.Text,
					tab.Fullname, SqlStatementMappingType.Input);
			}
			else
			{
				_entity.SqlStatementMappings.Remove(sqlMapping);
				sqlMapping.MappingName = txtOperationName.Text;
				//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;
			}

			SqlStatement statement = new SqlStatement();
			statement.MethodName = NamingHelper.GetOperationName(txtOperationName.Text);
			statement.Sql = txtSQL.Text;
			statement.Parameters.AddRange(UIHelper.GetParameters(_connectionSettings, txtSQL.Text, ParameterDirection.Input));
			statement.OperationType = _opType;

			sqlMapping.Statements.Add(statement);

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

				sqlMapping.ParameterMappings.Add(mapping);
			}

			_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
			{
				List<SD.Parameter> parameters = UIHelper.GetParameters(_connectionSettings, txtSQL.Text, ParameterDirection.Input);
				foreach (SD.Parameter par in parameters)
				{
					if (UIHelper.FindParameter(lstMappings, par.Name) == null)
					{
						lstInputParameters.Items.Add(par.Name);
					}
				}
			}
			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 btnAddMapping_Click(object sender, EventArgs e)
		{
			if (!UIGuard.IsListBoxSelected(lstEntityProperties) || !UIGuard.IsListBoxSelected(lstInputParameters))
			{
				return;
			}

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

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

			lstMappings.SelectedIndex = 0;
		}

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

			UIHelper.RemoveMappingItems(lstEntityProperties, lstInputParameters, 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 btnGenerate_Click(object sender, EventArgs e)
		{
			if (cboTable.SelectedItem != null)
			{
				txtSQL.Text = UIHelper.GetCRUDStatement((SD.Table)cboTable.SelectedItem, _opType);
				LoadMappings();
			}
		}

		private void txtSQL_Leave(object sender, EventArgs e)
		{
			ValidateSQLStatement();
		}

		private void txtOperationName_Leave(object sender, EventArgs e)
		{
			ValidateOperationName();
		}
	}
}