//===============================================================================
// Microsoft patterns & practices
// Web Service Software Factory
//===============================================================================
// Copyright  Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================

using System;
using Microsoft.Practices.RecipeFramework;
using System.Diagnostics;
using System.Collections.Generic;
using System.Data.Common;
using System.Data;
using System.Configuration;
using System.Globalization;

namespace Microsoft.Practices.SoftwareFactories.ServiceFactory.Actions
{
	/// <summary>
	/// Retrieves the schema for the given table.
	/// </summary>
	public class GetTableSchemaAction : Action
	{
		private ConnectionStringSettings connectionSettings;

        /// <summary>
        /// Gets or sets the connection settings.
        /// </summary>
        /// <value>The connection settings.</value>
		[Input]
		public ConnectionStringSettings ConnectionSettings
		{
			get { return connectionSettings; }
			set { connectionSettings = value; }
		}

		private string tableName;

        /// <summary>
        /// Gets or sets the name of the table.
        /// </summary>
        /// <value>The name of the table.</value>
		[Input]
		public string TableName
		{
			get { return tableName; }
			set { tableName = value; }
		}

		private DataTable tableSchema;

        /// <summary>
        /// Gets or sets the table schema.
        /// </summary>
        /// <value>The table schema.</value>
		[Output]
		public DataTable TableSchema
		{
			get { return tableSchema; }
			set { tableSchema = value; }
		}

		private IDictionary<string, string[]> indexes;

        /// <summary>
        /// Gets or sets the indexes.
        /// </summary>
        /// <value>The indexes.</value>
		[Output]
		public IDictionary<string, string[]> Indexes
		{
			get { return indexes; }
			set { indexes = value; }
		}

        /// <summary>
        /// See <see cref="M:Microsoft.Practices.RecipeFramework.IAction.Execute"/>.
        /// </summary>
		public override void Execute()
		{
			string dbprovider = connectionSettings.ProviderName;
			string cnstring = connectionSettings.ConnectionString;

			DbProviderFactory factory = DbProviderFactories.GetFactory(dbprovider);
			if (factory == null)
			{
				throw new ArgumentException("Provider");
			}

			DbConnection cn = factory.CreateConnection();
			cn.ConnectionString = cnstring;
			cn.Open();
			try
			{
				// Get table columns schema
				DbDataAdapter adapter = factory.CreateDataAdapter();
				adapter.SelectCommand = factory.CreateCommand();
				adapter.SelectCommand.Connection = cn;
				adapter.SelectCommand.CommandText = "select * from [" + tableName + "]";

				tableSchema = new DataTable(tableName);
                tableSchema.Locale = CultureInfo.CurrentCulture;
				adapter.FillSchema(tableSchema, SchemaType.Source);

				// Get table indexes 

				/* Restrictions for the GetSchema on IndexColumns
				CollectionName RestrictionName RestrictionDefault RestrictionNumber 
				--------------------------------------------------------------------
				IndexColumns	Catalog			db_name()			1 
				IndexColumns	Owner			user_name()			2 
				IndexColumns	Table			o.name				3 
				IndexColumns	ConstraintName	x.name				4 
				IndexColumns	Column			c.name				5 
				*/
				DataTable table = cn.GetSchema("IndexColumns",
					new string[] { null, null, tableName, null });
				indexes = new Dictionary<string, string[]>(table.Rows.Count);
				if (table.Rows.Count == 0)
				{
					return;
				}
				int index = 0;
				// Returned data contains the following columns:
				// constraint_schema, constraint_name, table_catalog, table_schema, table_name, column_name, ordinal_position, KeyType, index_name 
				string indexName = (string)table.Rows[index]["index_name"];
				List<string> indexColumns = new List<string>();
				do
				{
					if ((string)table.Rows[index]["index_name"] != indexName)
					{
						indexes.Add(indexName, indexColumns.ToArray());
						indexName = (string)table.Rows[index]["index_name"];
						indexColumns = new List<string>();
						indexColumns.Add((string)table.Rows[index]["column_name"]);
					}
					else
					{
						indexColumns.Add((string)table.Rows[index]["column_name"]);
					}
					index++;
				} while (index < table.Rows.Count);
				// Add the remaining one after iteration completes.
				indexes.Add(indexName, indexColumns.ToArray());
			}
			finally
			{
				cn.Close();
			}
		}

        /// <summary>
        /// See <see cref="M:Microsoft.Practices.RecipeFramework.IAction.Undo"/>.
        /// </summary>
		public override void Undo()
		{
            //Not Implemented
		}
	}
}