using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Runtime.Serialization;
using System.Data.Odbc;
using System.Data.SqlClient;
using System.Data.OracleClient;
using DataSetService;




namespace ODBCTableProvider
{
    public class ODBCDataSetFactory : DataSetFactoryChooser, IDataSetFactory
    {
        static readonly string[] names = new string[] { "ODBC", "SQL Server", "Oracle" };

        static private Dictionary<string, IDataSetFactory> factories = new Dictionary<string, IDataSetFactory>();
        public static readonly DataSetFactoryChooser Object = new ODBCDataSetFactory();

        private ODBCDataSetFactory()
        {
            factories[names[0]] = this;
            factories[names[1]] = SQLServerFactory.Object;
            factories[names[2]] = OracleFactory.Object;
        }

        public override IDataSetFactory this[string name]
        {
            get
            {
                return factories[name];
            }
        }

        public override string[] Names
        {
            get
            {
                return names;
            }
        }

        public static string GenerateScriptStatic(IColumn column)
        {
            string t = column.Type;
            string s = "";
            if (t.Equals("System.Double"))
            {
                s += "float(53)";
            }
            if (t.Equals("System.Guid"))
            {
                s += "uniqueidentifier";
            }
            if (t.Equals("System.Int32"))
            {
                s += "int";
            }
            if (t.Equals("System.String"))
            {
                s += "char(";
                s += column.Length + ")";
            }
            s += " ";
            if (column.IsNullable)
            {
                s += "NULL";
            }
            else
            {
                s += "NOT NULL";
            }
            return s;
        }

        public static List<string> GenerateScriptStatic(ITable table, IDataSetFactory factory)
        {
            List<string> l = new List<string>();
            l.Add("CREATE TABLE dbo." + table.Name);
            l.Add("(");
            Dictionary<string, IColumn> d = table.Columns;
            int n = 0;
            foreach (string key in d.Keys)
            {
                string s = key + " " + factory.GenerateScript(d[key]);
                ++n;
                if (n < d.Count)
                {
                    s += ",";
                }
                l.Add(s);
            }
            l.Add(");");
            return l;
        }

        #region IDataSetFactory Members

        public System.Data.Common.DbConnection Connection
        {
            get
            {
                return new OdbcConnection();

            }
        }

        public System.Data.Common.DbCommand Command
        {
            get
            {
                return new OdbcCommand();
            }
        }

        public DataSet GetData(System.Data.Common.DbConnection connection)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public DataSet GetData(string connectionString)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public IDbDataAdapter Adapter
        {
            get
            {
                return new OdbcDataAdapter();
            }
        }


        /// <summary>
        /// Creates type from metadata row
        /// </summary>
        /// <param name="row">The metadata row</param>
        /// <returns>The type</returns>
        public Type GetTypeFromRow(DataRow row)
        {
            return null;
        }

        /// <summary>
        /// Table name in metadata
        /// </summary>
        public string TableName
        {
            get
            {
                return "TABLE_NAME";
            }
        }

   
        /// <summary>
        /// Column name in metadata
        /// </summary>
        public string ColumnName
        {
            get
            {
                return "COLUMN_NAME";
            }
        }

        public string IsNullable
        {
            get
            {
                return "IS_NULLABLE";
            }
        }


        public string GetStringFromType(Type type)
        {
            return type + "";
        }


        public string GenerateStatement(IDataSetDesktop desktop)
        {
            return AbstractDataSetDesktop.GenerateStandardStatement(desktop);
        }

        public object GetObjectType(DataColumn column)
        {
            return column.DataType;
        }

        /// <summary>
        /// Gets modifiers
        /// </summary>
        /// <param name="type">Type</param>
        /// <returns>Modifiers</returns>
        public string[] GetModifiers(string type)
        {
            return DataSetFactoryPerformer.GetModifiers(type);
        }

        public string GenerateScript(IColumn column)
        {
            return GenerateScriptStatic(column);
        }


        public List<string> GenerateScript(ITable table)
        {
            return GenerateScriptStatic(table, this);
        }


        public List<string> GenerateScript(DataSet metaData)
        {
            return null;
        }


        #endregion
    }

    internal class SQLServerFactory : IDataSetFactory
    {
 
        internal static readonly SQLServerFactory Object = new SQLServerFactory();

        private SQLServerFactory()
        {
        }

        #region IDataSetFactory Members
        
        System.Data.Common.DbConnection IDataSetFactory.Connection
        {
            get
            {
                return new SqlConnection();
            }
        }

        System.Data.Common.DbCommand IDataSetFactory.Command
        {
            get
            {
                return new SqlCommand();
            }
        }

        DataSet IDataSetFactory.GetData(System.Data.Common.DbConnection connection)
        {
            DataSet s = new DataSet();
            connection.Open();
            DataTable table = connection.GetSchema("Columns");
            connection.Close();
            Dictionary<string, Dictionary<string, DataRow>> dic = DataSetFactoryChooser.GetTables("TABLE_NAME", "COLUMN_NAME", table);
            foreach (string name in dic.Keys)
            {
                Dictionary<string, DataRow> d = dic[name];
                DataTable dt = new DataTable();
                dt.TableName = name;
                int length = 1;
                foreach (string cn in d.Keys)
                {
                    DataRow row = d[cn];
                    string ty = row["DATA_TYPE"] + "";
                    object o = null;
                    if (ty.Equals("uniqueidentifier"))
                    {
                        o = new Guid();
                    }
                    if (ty.Equals("image"))
                    {
                        o = new byte[2];
                    }
                    if (ty.Equals("nvarchar"))
                    {
                        string str = "";
                        o = str;
                    }
                    if (ty.Equals("varchar"))
                    {
                        o = new char[2];
                    }
                    if (ty.Equals("char"))
                    {
                        o = new char[2];
                        length = (int)row["CHARACTER_MAXIMUM_LENGTH"];
                    }
                    if (ty.Equals("bigint"))
                    {
                        long a = 0;
                        o = a;
                    }
                    if (ty.Equals("int"))
                    {
                        int a = 0;
                        o = a;
                    }
                    if (ty.Equals("datetime"))
                    {
                        o = new DateTime();
                    }
                    if (ty.Equals("float"))
                    {
                        byte prec = (byte) row["NUMERIC_PRECISION"];
                        if (prec == 53)
                        {
                            double a = 0;
                            o = a;
                        }
                    }
                    if (o != null)
                    {
                        Type type = o.GetType();
                        if (o is char[])
                        {
                            type = "".GetType();
                        }
                        DataColumn col = new DataColumn();
                        col.ColumnName = cn;
                        col.DataType = type;
                        string on = row["IS_NULLABLE"] + "";
                        col.AllowDBNull = on.Equals("YES");
                        try
                        {
                            col.MaxLength = length;
                        }
                        catch (Exception ex)
                        {
                        }
                        dt.Columns.Add(col);
                    }
                }
                s.Tables.Add(dt);
            }
            return s;
        }

        DataSet IDataSetFactory.GetData(string connectionString)
        {
            IDataSetFactory f = this;
            System.Data.Common.DbConnection connection = f.Connection;
            connection.ConnectionString = connectionString;
            DataSet s = new DataSet();
            connection.Open();
            DataTable table = connection.GetSchema("Columns");
            s.Tables.Add(table);
            return s;
        }

        IDbDataAdapter IDataSetFactory.Adapter
        {
            get
            {
                return new SqlDataAdapter();
            }
        }

        /// <summary>
        /// Creates type from metadata row
        /// </summary>
        /// <param name="row">The metadata row</param>
        /// <returns>The type</returns>
        public Type GetTypeFromRow(DataRow row)
        {
            return null;
        }

        /// <summary>
        /// Table name in metadata
        /// </summary>
        public string TableName
        {
            get
            {
                return "TABLE_NAME";
            }
        }


        /// <summary>
        /// Column name in metadata
        /// </summary>
        public string ColumnName
        {
            get
            {
                return "COLUMN_NAME";
            }
        }

        public string IsNullable
        {
            get
            {
                return "IS_NULLABLE";
            }
        }



        public string GetStringFromType(Type type)
        {
            return type + "";
        }

        public string GenerateStatement(IDataSetDesktop desktop)
        {
            return AbstractDataSetDesktop.GenerateStandardStatement(desktop);
        }

        public object GetObjectType(DataColumn column)
        {
            Double a = 0;
            string s = "";
            Type t = column.DataType;
            if (t.Equals(typeof(Double)))
            {
                return a;
            }
            if (t.Equals(typeof(string)))
            {
                return s;
            }
            return null;
        }

        /// <summary>
        /// Gets modifiers
        /// </summary>
        /// <param name="type">Type</param>
        /// <returns>Modifiers</returns>
        public string[] GetModifiers(string type)
        {
            return DataSetFactoryPerformer.GetModifiers(type);
        }

        public string GenerateScript(IColumn column)
        {
            return ODBCDataSetFactory.GenerateScriptStatic(column);
        }


        public List<string> GenerateScript(ITable table)
        {
            return ODBCDataSetFactory.GenerateScriptStatic(table, this);
        }


        public List<string> GenerateScript(DataSet metaData)
        {
            return null;
        }




        #endregion
    }

    internal class OracleFactory : IDataSetFactory
    {
        internal static readonly OracleFactory Object = new OracleFactory();

        private OracleFactory()
        {
        }

        #region IDataSetFactory Members

        public System.Data.Common.DbConnection Connection
        {
            get
            {
                return new OracleConnection();
            }
        }
        public System.Data.Common.DbCommand Command
        {
            get
            {
                return new OracleCommand();
            }
        }

        public DataSet GetData(System.Data.Common.DbConnection connection)
        {
            DataSet s = new DataSet();
            connection.Open();
            DataTable table = connection.GetSchema("Columns");
            connection.Close();
            Dictionary<string, Dictionary<string, DataRow>> dic = DataSetFactoryChooser.GetTables("TABLE_NAME", "COLUMN_NAME", table);
            foreach (string name in dic.Keys)
            {
                Dictionary<string, DataRow> d = dic[name];
                DataTable dt = new DataTable();
                dt.TableName = name;
                foreach (string cn in d.Keys)
                {
                    DataRow row = d[cn];
                    string ty = row["DATA_TYPE"] + "";
                    object o = null;
                    if (ty.Equals("uniqueidentifier"))
                    {
                        o = new Guid();
                    }
                    if (ty.Equals("image"))
                    {
                        o = new byte[2];
                    }
                    if (ty.Equals("nvarchar"))
                    {
                        string str = "";
                        o = str;
                    }
                    if (ty.Equals("varchar"))
                    {
                        o = new char[2];
                    }
                    if (ty.Equals("char"))
                    {
                        o = new char[2];
                    }
                    if (ty.Equals("bigint"))
                    {
                        long a = 0;
                        o = a;
                    }
                    if (ty.Equals("int"))
                    {
                        int a = 0;
                        o = a;
                    }
                    if (ty.Equals("datetime"))
                    {
                        o = new DateTime();
                    }
                    if (ty.Equals("float"))
                    {
                        byte prec = (byte)row["NUMERIC_PRECISION"];
                        if (prec == 53)
                        {
                            double a = 0;
                            o = a;
                        }
                    }
                    if (o != null)
                    {
                        Type type = o.GetType();
                        DataColumn col = new DataColumn();
                        col.ColumnName = cn;
                        col.DataType = type;
                        string on = row["IS_NULLABLE"] + "";
                        col.AllowDBNull = on.Equals("YES");
                        dt.Columns.Add(col);

                    }
                }
                s.Tables.Add(dt);
            }
            return s;
        }

        public DataSet GetData(string connectionString)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public IDbDataAdapter Adapter
        {
            get
            {
                return new OracleDataAdapter();
            }
        }

        /// <summary>
        /// Creates type from metadata row
        /// </summary>
        /// <param name="row">The metadata row</param>
        /// <returns>The type</returns>
        public Type GetTypeFromRow(DataRow row)
        {
            return null;
        }

        /// <summary>
        /// Table name in metadata
        /// </summary>
        public string TableName
        {
            get
            {
                return "TABLE_NAME";
            }
        }


        /// <summary>
        /// Column name in metadata
        /// </summary>
        public string ColumnName
        {
            get
            {
                return "COLUMN_NAME";
            }
        }

        public string IsNullable
        {
            get
            {
                return "IS_NULLABLE";
            }
        }



        public string GetStringFromType(Type type)
        {
            return type + "";
        }


        public string GenerateStatement(IDataSetDesktop desktop)
        {
            return AbstractDataSetDesktop.GenerateStandardStatement(desktop);
        }

        public object GetObjectType(DataColumn column)
        {
            return column.DataType;
        }

        /// <summary>
        /// Gets modifiers
        /// </summary>
        /// <param name="type">Type</param>
        /// <returns>Modifiers</returns>
        public string[] GetModifiers(string type)
        {
            return DataSetFactoryPerformer.GetModifiers(type);
        }

        public string GenerateScript(IColumn column)
        {
            return ODBCDataSetFactory.GenerateScriptStatic(column);
        }


        public List<string> GenerateScript(ITable table)
        {
            return ODBCDataSetFactory.GenerateScriptStatic(table, this);
        }

        public List<string> GenerateScript(DataSet metaData)
        {
            return null;
        }



        #endregion
    }
}
