using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;

namespace ynhtm.DBUtility
{
    public abstract class DbBase : IDb, IDisposable
    {
        enum Provider
        {
            SqlServer,
            SQLite,
        }

        public const string DBKey = "ynhtm.Database";

        internal static readonly string CONNECTIONSTRING;
        static readonly Provider PROVIDER;

        static DbBase()
        {
            var conn = ConfigurationManager.ConnectionStrings[DBKey];
            CONNECTIONSTRING = conn.ConnectionString;
            switch (conn.ProviderName.ToUpper())
            {
                case "SYSTEM.DATA.SQLITE":
                    PROVIDER = Provider.SQLite;
                    break;
                default:
                    PROVIDER = Provider.SqlServer;
                    break;
            }
        }

        public static IDb GetDb()
        {
            if (PROVIDER == Provider.SQLite) return new SQLiteDb();
            return new SqlDb();
        }

        public static IQuery GetQuery()
        {
            if (PROVIDER == Provider.SQLite) return new SQLiteQuery();
            return new SQLiteQuery();
        }

        protected virtual void Open()
        {
            if (this.Connection.State == ConnectionState.Closed) this.Connection.Open();
        }

        public abstract string IDentity { get; }

        public abstract string IsNull { get; }

        public abstract string Now { get; }

        public abstract IDbConnection Connection { get; }

        public abstract IDataParameter CreateParameter(string name, object value);

        public virtual IDbCommand CreateCommand(string commandText, params object[] parameters)
        {
            var cmd = this.Connection.CreateCommand();
            var pars = new List<string>();
            if (parameters != null)
            {
                foreach (var i in parameters)
                {
                    IDataParameter par = i as IDataParameter;
                    if (par == null)
                    {
                        par = this.CreateParameter(pars.Count.ToString(), i);
                        pars.Add(par.ParameterName);
                    }
                    cmd.Parameters.Add(par);
                }
            }
            cmd.CommandText = pars.Count > 0 ? string.Format(commandText, pars.ToArray()) : commandText;
            return cmd;
        }

        public int ExecuteNonQuery(string commandText, params object[] parameters)
        {
            using (var cmd = this.CreateCommand(commandText, parameters))
            {
                this.Open();
                return cmd.ExecuteNonQuery();
            }
        }

        public IDataReader ExecuteReader(string commandText, params object[] parameters)
        {
            var cmd = this.CreateCommand(commandText, parameters);
            this.Open();
            return cmd.ExecuteReader();
        }

        public DataTable ExecuteTable(string commandText, params object[] parameters)
        {
            using (var reader = this.ExecuteReader(commandText, parameters))
            {
                var result = new DataTable();
                result.Load(reader);
                return result;
            }
        }

        public object ExecuteScalar(string commandText, params object[] parameters)
        {
            using (var cmd = this.CreateCommand(commandText, parameters))
            {
                this.Open();
                return cmd.ExecuteScalar();
            }
        }

        protected abstract DataTable GetPagex(ref int recordCount, string table, string order, int pageSize, int pageIndex, string query, string field);

        protected abstract DataTable GetPagex(string table, string order, int pageSize, int pageIndex, string query, string field);

        public DataTable GetPage(ref int recordCount, string table, string order, int pageSize, int pageIndex = 1, IQuery query = null, string field = "*")
        {
            return this.GetPagex(ref recordCount, table, order, pageSize, pageIndex, query != null ? query.ToString() : (string)null, field);
        }

        public DataTable GetPage(string table, string order, int pageSize, int pageIndex = 1, IQuery query = null, string field = "*")
        {
            return this.GetPagex(table, order, pageSize, pageIndex, query != null ? query.ToString() : (string)null, field);
        }

        public abstract void Backup(string path);

        public abstract string Name { get; }
        public abstract string Size { get; }
        public abstract string Version { get; }

        void IDisposable.Dispose()
        {
            this.Connection.Dispose();
        }
    }
}
