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

namespace Howest.Guidance.DataAccess.CustomWizardPages
{
	public partial class SqlEdit : Form
	{
		private ConnectionStringSettings _settings;
		private List<Parameter> _outputParameters;
		
		public SqlEdit(ConnectionStringSettings settings, SqlStatement statement, List<Parameter> outputParameters)
			: this()
		{
			
			_settings = settings;
			if (statement == null)
				_statement = new SqlStatement();
			else
				_statement = ClonerHelper.CloneSqlStatement(statement);
			if (outputParameters == null)
				_outputParameters = new List<Parameter>();
			else
				_outputParameters = outputParameters;

			cboOperationType.Items.Clear();
			foreach(OperationType type in Enum.GetValues(typeof(OperationType)))
				cboOperationType.Items.Add(type);

			SetControls();

			RefreshInputParameters();
		}

		public SqlEdit()
		{
			InitializeComponent();
		}

		private SqlStatement _statement;

		public SqlStatement Statement
		{
			get { return _statement; }
			set { _statement = value; }
		}

		private void SetControls()
		{
			lstInputParameters.DisplayMember = "Parameter.DBName";
			txtSQL.Text = _statement.Sql;
			txtMethodName.Text = _statement.MethodName;
			txtSQL.ReadOnly = _statement.IsReadOnly;
			propBrowser.Enabled = !_statement.IsReadOnly;
			cboOperationType.Enabled = !_statement.IsReadOnly;
			cboOperationType.SelectedItem = _statement.OperationType;
		}
	

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

		private bool ValidateSQLStatement()
		{
			frmErrorProvider.SetError(txtSQL, null);
			try
			{
				List<Parameter> pars = UIHelper.GetParameters(_settings, txtSQL.Text, ParameterDirection.ReturnValue);
				foreach (Parameter par in _outputParameters)
				{
					Parameter p = pars.Find(delegate(Parameter listp) {
						return listp.DBName == par.DBName && listp.DbDataType.ProviderType == par.DbDataType.ProviderType;
					});
					if (p == null)
					{
						frmErrorProvider.SetError(txtSQL, string.Format("SQL statement has no output value with name {0} and type {1}", par.DBName, par.DbDataType.ProviderType));
						return false;
					}
				}
				return true;
			}
			catch (Exception ex)
			{
				frmErrorProvider.SetError(txtSQL, ex.Message);
				return false;
			}
		}

		private void lstInputParameters_SelectedIndexChanged(object sender, EventArgs e)
		{
			Parameter par = (Parameter)lstInputParameters.SelectedItem;
			if (par != null)
			{
				DBDataTypeWrapper dbtypeWrapper = new DBDataTypeWrapper(par.DbDataType);
				propBrowser.SelectedObject = dbtypeWrapper;
			}
			else
				propBrowser.SelectedObject = null;
		}

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

		private void SaveSqlStatement()
		{
			//SqlStatement statement = new SqlStatement();
			_statement.MethodName = txtMethodName.Text;
			_statement.Sql = txtSQL.Text;
			_statement.IsReadOnly = _statement.IsReadOnly;
			_statement.OperationType = (OperationType)cboOperationType.SelectedItem;
			_statement.Description = "";
			foreach (Parameter par in lstInputParameters.Items)
			{
				_statement.Parameters.Add(ClonerHelper.CloneParameter(par));
			}
		}

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

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

		private bool IsInputValid()
		{
			if (!ValidateOperationName())
				return false;
			if (!ValidateSQLStatement())
				return false;
			if (!ValidateInputParameters())
				return false;
			return true;
		}

		private bool ValidateInputParameters()
		{
			foreach (Parameter p in lstInputParameters.Items)
			{
				if (p.DbDataType.ProviderType == DatabaseType.NotSupported)
					return false;
			}
			return true;
		}

		public void RefreshInputParameters()
		{
			List<Parameter> pars = UIHelper.GetParameters(_settings, txtSQL.Text, ParameterDirection.Input);
			lstInputParameters.Items.Clear();
			lstInputParameters.Items.AddRange(pars.ToArray());
		}

		private bool ValidateOperationName()
		{
			frmErrorProvider.SetError(txtMethodName, null);
			if (string.IsNullOrEmpty(txtMethodName.Text))
			{
				frmErrorProvider.SetError(txtMethodName, "Method name cannot be empty");
				return false;
			}
			try
			{
				txtMethodName.Text = CodeDomHelper.ConvertToValidIdentifier(txtMethodName.Text);
				return true;
			}
			catch (Exception ex)
			{
				frmErrorProvider.SetError(txtMethodName, ex.Message);
				return false;
			}
		}
	}
}