using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using Sdaleo.Systems;
using System.Data.Common;

#if SQLSERVER
using System.Data.SqlClient;
#endif
#if SQLCOMPACT
using System.Data.SqlServerCe;
#endif
#if ADVANTAGE    
using Advantage.Data.Provider;
#endif
#if CTREE
#endif
#if MYSQL
#endif
#if POSTGRES
//using Devart.Data.PostgreSql;
#endif

namespace Sdaleo
{    
    /// <summary>
    /// This class is a Object factory wrapper class around our DBMS
    /// </summary>
    internal static class DBMS
    {
        #region Connection DB Specifics

        /// <summary>
        /// Creates a Connection Object depending on the type of DBMS we are using
        /// </summary>
        /// <param name="dbsystem">the DBSystem you want parameters for</param>
        /// <param name="ConnectionStr">Must pass in a valid Connection String</param>
        /// <returns>a valid connection * Caller Must Dispose of the Object *, or null if system is not available</returns>
        internal static DbConnection CreateDbConnection(DBSystem dbsystem, string ConnectionStr)
        {
            DbConnection connection = null;
            if (!String.IsNullOrEmpty(ConnectionStr))
            {
                switch (dbsystem)
                {
#if SQLSERVER
                    case DBSystem.SQL_SERVER:
                        connection = (DbConnection)new SqlConnection(ConnectionStr);
                        break;
#endif
#if SQLCOMPACT
                    case DBSystem.SQL_CE:      
                        connection = (DbConnection)new SqlCeConnection(ConnectionStr);                            
                        break;
#endif                    
#if ADVANTAGE      
                    case DBSystem.ADVANTAGE:
                        connection = (DbConnection)new AdsConnection(ConnectionStr);
                        break;
#endif
#if CTREE
                    case DBSystem.CTREE:
                        connection = null;
                        break;
#endif
#if MYSQL
                    case DBSystem.MYSQL:
                        connection = null;
                        break;
#endif
#if POSTGRES
                    case DBSystem.POSTGRES:
                        connection = null;
                        break;
#endif
                    default:
                        break;
                }
            }
            return connection;
        }

        /// <summary>
        /// Creates a DataAdapter depending on the type of DBMS we are using
        /// </summary>
        /// <param name="dbsystem">the DBSystem you want a DataAdapter for</param>
        /// <param name="dbcommand">pass in a valid Command Object for the DBMS</param>
        /// <returns>a valid DataAdapter * Caller Must Dispose of the Object *, or null if system is not available</returns>
        internal static DbDataAdapter CreateDbDataAdapter(DBSystem dbsystem, DbCommand dbcommand)
        {
            DbDataAdapter dbDataAdapter = null;
            switch (dbsystem)
            {
#if SQLSERVER
                case DBSystem.SQL_SERVER:      
                    dbDataAdapter = new SqlDataAdapter((SqlCommand) dbcommand);
                    break;
#endif
#if SQLCOMPACT
                case DBSystem.SQL_CE:
                    dbDataAdapter = new SqlCeDataAdapter((SqlCeCommand) dbcommand);
                    break;
#endif
#if ADVANTAGE    
                case DBSystem.ADVANTAGE:
                    dbDataAdapter = new AdsDataAdapter((AdsCommand) dbcommand);
                    break;
#endif
#if CTREE
                case DBSystem.CTREE:
                    dbDataAdapter = null;
                    break;
#endif
#if MYSQL
                case DBSystem.MYSQL:
                    dbDataAdapter = null;
                    break;
#endif
#if POSTGRES
                case DBSystem.POSTGRES:      
                    dbDataAdapter = null;
                    break;
#endif
                default:
                    break;
            }
            return dbDataAdapter;
        }

        /// <summary>
        /// Creates a DBMS Specific Parameter Array from a DMBS Independent Parameter Array
        /// </summary>
        /// <param name="dbsystem">the DBSystem you want parameters for</param>
        /// <param name="parameters">a valid DBMSIndependent Param array</param>
        /// <returns>a DBMS Specific Parameter Array</returns>
        internal static DbParameter[] CreateDbParameter(DBSystem dbsystem, DBMSIndParameter[] parameters)
        {
            List<DbParameter> param_s = new List<DbParameter>();

            // Convert the Parameters
            foreach (DBMSIndParameter parameter in parameters)
            {
                switch (dbsystem)
                {
#if SQLSERVER
                    case DBSystem.SQL_SERVER:
                        param_s.Add(new SqlParameter(parameter.parameterName, parameter.Value));
                        break;
#endif
#if SQLCOMPACT
                    case DBSystem.SQL_CE:
                        param_s.Add(new SqlCeParameter(parameter.parameterName, parameter.Value));
                        break;
#endif
#if ADVANTAGE
                    case DBSystem.ADVANTAGE:
                        param_s.Add(new AdsParameter(parameter.parameterName, parameter.Value));
                        break;
#endif
#if CTREE
                    case DBSystem.CTREE:
                        //param_s.Add(new SqlCeParameter(parameter.parameterName, parameter.Value));                        
                        break;
#endif
#if MYSQL
                    case DBSystem.MYSQL:
                        //param_s.Add(new SqlCeParameter(parameter.parameterName, parameter.Value));
                        break;
#endif
#if POSTGRES
                    case DBSystem.POSTGRES:      
                        //param_s.Add(new PgSqlParameter(parameter.parameterName, parameter.Value));
                        break;
#endif
                    default:
                        break;
                }
            }

            // Return the Parameter
            return param_s.ToArray();
        }

        #endregion

        #region Exception DB Specifics

        /// <summary>
        /// Creates an Error Object to be returned to the Caller, fills values depending on DBMS
        /// </summary>
        /// <param name="dbsystem">the DBSystem you want an Error for</param>
        /// <param name="e">the exception being thrown by the DBMS</param>
        /// <returns>a DBRetVal Object filled with the Error Data, or null if system is not available</returns>
        internal static DBRetVal CreateErrorDBRetVal(DBSystem dbsystem, Exception e)
        {
            ////
            // We want to always make sure in this function that we always return a DBRetVal object
            // we should never return null
            ////
            DBRetVal retVal = null;
            if(e == null || String.IsNullOrEmpty(e.Message))
            {
                retVal = new DBRetVal("DB Error Exception object is null or with Empty Message");
                return retVal;
            }

            try
            {
                switch (dbsystem)
                {
#if SQLSERVER
                    case DBSystem.SQL_SERVER:
                        {
                            SqlException ex = e as SqlException;
                            if (ex != null)
                                retVal = new DBRetVal(ex.Number, ex.Message, ex.Errors);
                        }
                        break;
#endif
#if SQLCOMPACT
                case DBSystem.SQL_CE:
                    {
                        SqlCeException ex = e as SqlCeException;
                        if (ex != null)
                            retVal = new DBRetVal(ex.NativeError, ex.Message, ex.Errors);
                    }
                    break;
#endif
#if ADVANTAGE
                    case DBSystem.ADVANTAGE:
                        {
                            AdsException ex = e as AdsException;
                            if (ex != null)
                                retVal = new DBRetVal(ex.Number, ex.Message, null);
                        }
                        break;
#endif
#if CTREE
                case DBSystem.CTREE:
                    {
                        //SqlCeException ex = e as SqlCeException;
                        //if (ex != null)
                        //    retVal = new DBRetVal(ex.NativeError, ex.Message, ex.Errors);
                    }
                    break;
#endif
#if MYSQL
                case DBSystem.MYSQL:
                    {
                        //SqlCeException ex = e as SqlCeException;
                        //if (ex != null)
                        //    retVal = new DBRetVal(ex.NativeError, ex.Message, ex.Errors);                     
                    }
                    break;
#endif
#if POSTGRES
                case DBSystem.POSTGRES:
                    {
                        //PgSqlException ex = e as PgSqlException;
                        //if (ex != null)
                        //    retVal = new DBRetVal(0, ex.Message, null);
                    }
                    break;
#endif
                    default:
                        break;
                }
            }
            catch (Exception ex) 
            {
                retVal = new DBRetVal(ex.Message);
            }

            ////
            // We want to always make sure in this function that we always return a DBRetVal object
            // we should never return null
            ////
            if (retVal == null)
                retVal = new DBRetVal("DB Error Exception object could not be created");
            return retVal;
        }

        /// <summary>
        /// Returns the Error Number for the specified Exception Object for the specified DMBS,
        /// or -1 if an error occured
        /// </summary>
        /// <param name="dbsystem">>the DBSystem you want an Error Number for</param>
        /// <param name="e">the exception being thrown by the DBMS</param>
        /// <returns>the Error Number (ID) of the Exception thrown or -1 if anything else happened</returns>
        internal static int GetErrorNumberForErrorObject(DBSystem dbsystem, Exception e)
        {            
            int nError = -1;         
            if (e == null || String.IsNullOrEmpty(e.Message))            
                return nError;

            try
            {
                switch (dbsystem)
                {
#if SQLSERVER
                    case DBSystem.SQL_SERVER:
                        {
                            SqlException ex = e as SqlException;
                            if (ex != null)
                                nError = ex.Number;
                        }
                        break;
#endif
#if SQLCOMPACT
                case DBSystem.SQL_CE:
                    {
                        SqlCeException ex = e as SqlCeException;
                        if (ex != null)
                            nError = ex.NativeError;
                    }
                    break;
#endif
#if ADVANTAGE
                    case DBSystem.ADVANTAGE:
                        {
                            AdsException ex = e as AdsException;
                            if (ex != null)
                                nError = ex.Number;                                
                        }
                        break;
#endif
#if CTREE
                case DBSystem.CTREE:
                    {
                        //SqlCeException ex = e as SqlCeException;
                        //if (ex != null)
                        //    nError = ex.NativeError;
                    }
                    break;
#endif
#if MYSQL
                case DBSystem.MYSQL:
                    {
                        //SqlCeException ex = e as SqlCeException;
                        //if (ex != null)
                        //    nError = ex.NativeError;                   
                    }
                    break;
#endif
#if POSTGRES
                case DBSystem.POSTGRES:
                    {
                        //PgSqlException ex = e as PgSqlException;
                        //if (ex != null)
                        //    nError = ex.NativeError;
                    }
                    break;
#endif
                    default:
                        break;
                }
            }
            catch (Exception ex) { /* ignore */ }
            return nError;
        }

        /// <summary>
        /// Retrieves all Error Numbers that the specified DBError has in it's collection.
        /// If it doesn't have a collection it will just return an empty list.
        /// </summary>
        /// <param name="dbsystem"></param>
        /// <param name="error"></param>
        /// <returns></returns>
        internal static List<int> GetAllErrorNumbers(DBSystem dbsystem, DBError error)
        {
            List<int> list = new List<int>();
            if (error != null && error.Errors != null)
            {                
                foreach (Exception e in error.Errors)
                {
                    int nError = GetErrorNumberForErrorObject(dbsystem, e);                    
                    list.Add(nError);
                }
            }
            return list;
        }

        #endregion
    }
}
