using System;
using System.Data;
using System.Data.Common;
using System.Configuration.Provider;
using System.Configuration;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Data.OracleClient;
using Winson.Framework.LogProviders;

namespace Winson.Framework.DBProviders
{
    partial class OracleDBProvider : DataBaseProvider
    {
        #region 私有属性
        private OracleConnection _conn;
        private OracleClientFactory _provider;
        private bool _useTransaction = true;
        #endregion

        /// <summary>
        /// 获取当前连接对象
        /// </summary>
        public override DbConnection Conn()
        {
            CreateConnection();
            return _conn;
        }

        #region 公有方法

        public override void UseTransaction(bool isuse)
        {
            _useTransaction = isuse;
        }

        public override bool ExecuteBatch(DBAction dbAction,
                                            string tableName,
                                            List<ArrayList> fieldNameList,
                                            List<ArrayList> fieldValueList)
        {
            CreateConnection();
            using (_conn)
            {
                string strSql = string.Empty;
                string tempSQL = string.Empty;
                string parmName = string.Empty;
                object parmValue = null;
                int pramNo = 0;

                OracleCommand cmd = _conn.CreateCommand();
                try
                {
                    //如果tableName不为空，即进行参数创建生成SQL语句
                    if (!String.IsNullOrEmpty(tableName) && fieldNameList.Count > 0)
                    {
                        //生成相应的SQL语句
                        switch (dbAction)
                        {
                            case DBAction.Insert:
                                for (int i = 0; i < fieldNameList.Count; i++)
                                {
                                    tempSQL = "insert into " + tableName + " (";
                                    for (int n = 0; n < fieldNameList[i].Count; n++)
                                    {
                                        tempSQL += fieldNameList[i][n].ToString() + ",";
                                    }
                                    tempSQL = tempSQL.Substring(0, tempSQL.Length - 1) + ")values(";
                                    for (int n = 0; n < fieldNameList[i].Count; n++)
                                    {
                                        parmName = fieldNameList[i][n].ToString() + pramNo.ToString();
                                        parmValue = fieldValueList[i][n];
                                        tempSQL += ":" + parmName + ",";
                                        CreateParams(ref cmd, parmName, parmValue);
                                        pramNo++;
                                    }
                                    strSql += tempSQL.Substring(0, tempSQL.Length - 1) + ");";
                                }
                                break;
                            case DBAction.Update:
                                for (int i = 0; i < fieldNameList.Count; i++)
                                {
                                    tempSQL = "update " + tableName + " set ";
                                    for (int n = 0; n < fieldNameList[i].Count; n++)
                                    {
                                        parmName = fieldNameList[i][n].ToString() + pramNo.ToString();
                                        parmValue = fieldValueList[i][n];
                                        tempSQL += fieldNameList[i][n].ToString() + "=" + ":" + parmName + ",";
                                        CreateParams(ref cmd, parmName, parmValue);
                                        pramNo++;
                                    }
                                    parmName = fieldNameList[i][0].ToString() + pramNo.ToString();
                                    parmValue = fieldValueList[i][0];
                                    strSql += tempSQL.Substring(0, tempSQL.Length - 1);
                                    strSql += " where " + fieldNameList[i][0].ToString() + "=:" + parmName + ";";

                                    CreateParams(ref cmd, parmName, parmValue);

                                    pramNo++;
                                }
                                break;
                            case DBAction.Delete:
                                for (int i = 0; i < fieldNameList.Count; i++)
                                {
                                    parmName = fieldNameList[i][0].ToString() + pramNo.ToString();
                                    parmValue = fieldValueList[i][0];
                                    strSql += "delete from " + tableName + " where " + fieldNameList[i][0].ToString() + "=:" + parmName + ";";
                                    CreateParams(ref cmd, parmName, parmValue);
                                    pramNo++;
                                }
                                break;
                        }
                    }

                    cmd.CommandText = strSql;
                    cmd.CommandType = CommandType.Text;
                    _conn.Open();

                    if (_useTransaction) cmd.Transaction = _conn.BeginTransaction();

                    int result = cmd.ExecuteNonQuery();

                    if (result == fieldNameList.Count)
                    {
                        if (_useTransaction)
                            cmd.Transaction.Commit();
                        return true;
                    }
                    else
                    {
                        if (_useTransaction)
                            cmd.Transaction.Rollback();
                        return false;
                    }
                }
                catch (Exception e)
                {
                    if (_useTransaction) cmd.Transaction.Rollback();
                    LogManage.OutputErrLog(e, new Object[] { dbAction, tableName, fieldNameList, fieldValueList });
                    return false;
                }
                finally
                {
                    cmd.Dispose();
                }
            }
        }

        public override DataSet ExecuteDataset(string strSql,
                                                string tableName,
                                                NameValueCollection conditionValue)
        {
            CreateConnection();
            using (_conn)
            {
                OracleCommand cmd = _conn.CreateCommand();
                using (OracleDataAdapter ad = (OracleDataAdapter)_provider.CreateDataAdapter())
                {
                    try
                    {
                        DataSet ds = new DataSet();
                        strSql = CreateSql(ref cmd, strSql, conditionValue);

                        cmd.CommandText = strSql;
                        cmd.CommandType = CommandType.Text;
                        _conn.Open();

                        ad.SelectCommand = cmd;
                        if (tableName == null || tableName.Length == 0) ad.Fill(ds);
                        else ad.Fill(ds, tableName);
                        return ds;
                    }
                    catch (Exception e)
                    {
                        LogManage.OutputErrLog(e, new Object[] { strSql, tableName, conditionValue });
                        return null;
                    }
                    finally
                    {
                        cmd.Dispose();
                    }
                }
            }
        }

        public override int ExecuteNonQuery(DBAction dbAction,
                                            string tableName,
                                            string strSql,
                                            ArrayList fieldName,
                                            ArrayList fieldValue,
                                            NameValueCollection conditionValue)
        {
            CreateConnection();
            using (_conn)
            {
                OracleCommand cmd = _conn.CreateCommand();
                try
                {
                    //如果tableName不为空，即进行参数创建生成SQL语句
                    if (!String.IsNullOrEmpty(tableName) && fieldName != null && fieldName.Count > 0)
                    {
                        //生成相应的SQL语句
                        switch (dbAction)
                        {
                            case DBAction.Insert:
                                strSql = "insert into " + tableName + " (";
                                foreach (object name in fieldName)
                                {
                                    strSql += name.ToString() + ",";
                                }
                                strSql = strSql.Substring(0, strSql.Length - 1) + ")values(";

                                foreach (object name in fieldName)
                                {
                                    strSql += ":" + name.ToString() + ",";
                                }
                                strSql = strSql.Substring(0, strSql.Length - 1) + ")";
                                break;
                            case DBAction.Update:
                                strSql = "update " + tableName + " set ";
                                foreach (object name in fieldName)
                                {
                                    strSql += name.ToString() + "=" + ":" + name.ToString() + ",";
                                }
                                strSql = strSql.Substring(0, strSql.Length - 1);
                                break;
                            case DBAction.Delete:
                                break;
                        }

                        //添加参数
                        for (int i = 0; i < fieldName.Count; i++)
                        {
                            CreateParams(ref cmd, fieldName[i].ToString(), fieldValue[i]);
                        }
                    }

                    //生成条件参数
                    if (conditionValue != null)
                    {
                        if (dbAction == DBAction.Delete)
                            strSql = "delete from " + tableName + "";
                        strSql = CreateSql(ref cmd, strSql, conditionValue);
                    }
                    else
                    {
                        if (dbAction == DBAction.Update)
                            strSql += " where " + fieldName[0].ToString() + "=" + fieldValue[0].ToString();
                    }

                    cmd.CommandText = strSql;
                    cmd.CommandType = CommandType.Text;
                    _conn.Open();

                    if (_useTransaction) cmd.Transaction = _conn.BeginTransaction();

                    int result = cmd.ExecuteNonQuery();

                    if (_useTransaction) cmd.Transaction.Commit();
                    return result;
                }
                catch (Exception e)
                {
                    if (_useTransaction) cmd.Transaction.Rollback();
                    LogManage.OutputErrLog(e, new Object[] { strSql, fieldName, fieldValue, conditionValue });
                    return 0;
                }
                finally
                {
                    cmd.Dispose();
                }
            }
        }


        public override DataSet ExecuteProcDataset(string procName,
                                                    string tableName,
                                                    NameValueCollection conditionValue)
        {
            CreateConnection();
            using (_conn)
            {
                OracleCommand cmd = _conn.CreateCommand();
                using (OracleDataAdapter ad = (OracleDataAdapter)_provider.CreateDataAdapter())
                {
                    DataSet ds = new DataSet();
                    cmd.CommandText = procName;
                    cmd.CommandType = CommandType.StoredProcedure;
                    CreateProcParams(ref cmd, conditionValue);
                    _conn.Open();
                    ad.SelectCommand = cmd;

                    try
                    {
                        if (tableName == null || tableName.Length == 0) ad.Fill(ds);
                        else ad.Fill(ds, tableName);
                        return ds;
                    }
                    catch (Exception e)
                    {
                        LogManage.OutputErrLog(e, new Object[] { procName, tableName, conditionValue });
                        return null;
                    }
                    finally
                    {
                        cmd.Dispose();
                    }
                }
            }
        }

        public override bool ExecuteProcedure(string procName, NameValueCollection conditionValue)
        {
            CreateConnection();
            using (_conn)
            {
                OracleCommand cmd = _conn.CreateCommand();
                cmd.CommandText = procName;
                cmd.CommandType = CommandType.StoredProcedure;
                CreateProcParams(ref cmd, conditionValue);
                _conn.Open();
                try
                {
                    if (cmd.ExecuteNonQuery() > 0)
                        return true;
                    else
                        return false;
                }
                catch (Exception e)
                {
                    LogManage.OutputErrLog(e, new Object[] { procName, conditionValue });
                    return false;
                }
                finally
                {
                    cmd.Dispose();
                }
            }
        }

        public override object ExecuteProcScalar(string procName, NameValueCollection conditionValue)
        {
            CreateConnection();
            using (_conn)
            {
                OracleCommand cmd = _conn.CreateCommand();
                cmd.CommandText = procName;
                cmd.CommandType = CommandType.StoredProcedure;
                CreateProcParams(ref cmd, conditionValue);
                _conn.Open();

                try
                {
                    return cmd.ExecuteScalar();
                }
                catch (Exception e)
                {
                    LogManage.OutputErrLog(e, new Object[] { procName, conditionValue });
                    return null;
                }
                finally
                {
                    cmd.Dispose();
                }
            }
        }

        public override DbDataReader ExecuteReader(DbConnection conn,
                                                    string strSql,
                                                    NameValueCollection conditionValue)
        {
            _conn = (OracleConnection)conn;

            OracleCommand cmd = _conn.CreateCommand();
            strSql = CreateSql(ref cmd, strSql, conditionValue);
            cmd.CommandText = strSql;
            cmd.CommandType = CommandType.Text;
            _conn.Open();
            try
            {
                OracleDataReader rdr = cmd.ExecuteReader();
                if (rdr.HasRows)
                    return (DbDataReader)rdr;
                else
                    return null;
            }
            catch (Exception e)
            {
                LogManage.OutputErrLog(e, new Object[] { strSql, conditionValue });
                return null;
            }
            finally
            {
                cmd.Dispose();
            }
        }

        public override object ExecuteScalar(string strSql, NameValueCollection conditionValue)
        {
            CreateConnection();
            using (_conn)
            {
                OracleCommand cmd = _conn.CreateCommand();
                try
                {
                    strSql = CreateSql(ref cmd, strSql, conditionValue);

                    cmd.CommandText = strSql;
                    cmd.CommandType = CommandType.Text;
                    _conn.Open();

                    return cmd.ExecuteScalar();
                }
                catch (Exception e)
                {
                    LogManage.OutputErrLog(e, new Object[] { strSql, conditionValue });
                    return null;
                }
                finally
                {
                    cmd.Dispose();
                }
            }
        }

        public override string GetPrimeKey(string tableName)
        {
            CreateConnection();
            using (_conn)
            {
                OracleCommand cmd = _conn.CreateCommand();
                using (DbDataAdapter ad = _provider.CreateDataAdapter())
                {
                    try
                    {
                        object primarykey = Utility.CacheHelper.Get(tableName + "_PrimeKey");

                        if (primarykey == null)
                        {
                            DataTable dt = new DataTable();
                            cmd.CommandText = "Select  * from " + tableName + " rownum = 1 ";
                            cmd.CommandType = CommandType.Text;
                            _conn.Open();
                            ad.SelectCommand = cmd;
                            ad.FillSchema(dt, SchemaType.Mapped);

                            if (dt.PrimaryKey.Length > 0)
                                primarykey = dt.PrimaryKey.GetValue(0);
                            else
                                return "";
                            Utility.CacheHelper.Insert(tableName + "_PrimeKey", primarykey);
                        }

                        return primarykey.ToString();
                    }
                    catch (Exception e)
                    {
                        LogManage.OutputErrLog(e, new Object[] { tableName });
                        return "";
                    }
                }
            }
        }

        public override string GeneratePagerSql(string tableName, int limit,
                                                int currpage, string criteria,
                                                string orderby, string order)
        {
            string _order = string.Empty;
            string _criteria = String.IsNullOrEmpty(criteria) ? "" : " AND " + criteria;

            string QueryPageCommandText = "SELECT * FROM " + tableName +
                " WHERE 1=1 {4} ORDER BY {2} {3} LIMIT  {0} , {1} ";

            string sql = String.Format(QueryPageCommandText,
                limit * (currpage) - limit, // {0} --> 开始记录数 
                limit,	                    // {1} --> 每页记录数
                orderby,					// {2} --> 排序关键字
                order,                      // {3} --> 排序方式,决定了最终排序
                _criteria);                 // {4} --> 查询条件

            return sql;
        }

        public override string GenerateGetOneEntitySql(string tableName, string primeKey)
        {
            return "select * from " + tableName + "order by " + primeKey + " desc limit 1";
        }

        #endregion

        #region 私有方法
        /// <summary>
        /// 创建数据库连接
        /// </summary>
        private void CreateConnection()
        {
            try
            {
                string providerName = ConfigurationManager.ConnectionStrings[connStringName].ProviderName;
                _provider = OracleClientFactory.Instance;
                _conn = (OracleConnection)_provider.CreateConnection();
                _conn.ConnectionString = ConfigurationManager.ConnectionStrings[connStringName].ConnectionString;
            }
            catch (Exception e)
            {
                LogManage.OutputErrLog(e, new Object[] { });
            }
        }
        /// <summary>
        /// 生成带条件参数的SQL语句
        /// </summary>
        /// <param name="cmd">DbCommand</param>
        /// <param name="strSql">SQL语句</param>
        /// <param name="conditionValue">参数列表</param>
        /// <returns>构建好的SQL语句</returns>
        private string CreateSql(ref OracleCommand cmd, string strSql, NameValueCollection conditionValue)
        {
            if (conditionValue != null && conditionValue.Count > 0)
            {
                string conWhere = string.Empty;
                string conSql = string.Empty;
                string orderby = " order by ";
                bool hasorder = false;
                string sqlOperator = "and";
                //只有order by 语句时
                if (!(conditionValue.Count == 1 && conditionValue.GetKey(0).ToLower() == "order"))
                    strSql += " where ";
                for (int i = 0; i < conditionValue.Count; i++)
                {
                    OracleParameter pa = (OracleParameter)_provider.CreateParameter();
                    if (conditionValue.GetKey(i).ToLower() == "operator")
                    {
                        sqlOperator = conditionValue.GetValues(i).GetValue(0).ToString();
                        continue;
                    }
                    //如参数名为where，则为自定义查询条件;如为sql,则为自定义的sql语句
                    if (conditionValue.GetKey(i).ToLower() == "where")
                    {
                        conWhere = conditionValue.GetValues(i).GetValue(0).ToString();
                        break;
                    }
                    else if (conditionValue.GetKey(i).ToLower() == "sql")
                    {
                        conSql = conditionValue.GetValues(i).GetValue(0).ToString();
                        break;
                    }
                    else if (conditionValue.GetKey(i).ToLower().IndexOf("in") > 0)
                    {
                        //处理in条件语句
                        string str = string.Empty;
                        string[] values = conditionValue.GetValues(i).GetValue(0).ToString().Split(',');
                        for (int n = 0; n < values.Length; n++)
                        {
                            pa.ParameterName = ":con_" + n.ToString();
                            pa.Value = values[n];
                            cmd.Parameters.Add(pa);
                            str += pa.ParameterName + ",";
                            pa = (OracleParameter)_provider.CreateParameter();
                        }
                        strSql += conditionValue.GetKey(i) + " (" + str.Substring(0, str.Length - 1) + ") " + sqlOperator + " ";
                    }
                    else if (conditionValue.GetKey(i).ToLower() == "order")
                    {
                        orderby += conditionValue.GetValues(i).GetValue(0).ToString();
                        hasorder = true;
                    }
                    else
                    {
                        string[] oper = conditionValue.GetKey(i).Split(' ');
                        if (oper != null)
                        {
                            pa.ParameterName = ":" + oper[0].Replace("]", "").Replace("[", "");
                            pa.Value = conditionValue.GetValues(i).GetValue(0);
                            cmd.Parameters.Add(pa);

                            if (oper.Length == 1)
                                //处理直接赋值的条件语句(i.e cond["age"]="30";)
                                strSql += conditionValue.GetKey(i) + "=" + pa.ParameterName + " " + sqlOperator + " ";
                            else
                            {
                                //处理Like语句(i.e cond["name like left"]="winson";
                                //cond["name like right"]="winson";
                                //cond["name like all"]="winson";)
                                if (oper[1].ToLower() == "like")
                                {
                                    if (oper.Length > 2)
                                    {
                                        if (oper[2].ToLower() == "left")
                                            strSql += oper[0] + " like '%'+ " + pa.ParameterName + " " + sqlOperator + " ";
                                        else if (oper[2].ToLower() == "right")
                                            strSql += oper[0] + " like " + pa.ParameterName + " + '%' " + sqlOperator + " ";
                                    }
                                    else
                                        strSql += oper[0] + " like '%'+ " + pa.ParameterName + " + '%' " + sqlOperator + " ";
                                }
                                else
                                    //处理其他赋值的条件语句(i.e cond["age >"]="30";)
                                    strSql += conditionValue.GetKey(i) + " " + pa.ParameterName + " " + sqlOperator + " ";
                            }
                        }
                    }
                    sqlOperator = "and";//reset the operator for default
                }
                if (conWhere.Length > 0)
                    strSql += conWhere;
                else if (conSql.Length > 0)
                    strSql = conSql;
                else if (strSql.EndsWith("and "))
                    strSql = strSql.Substring(0, strSql.Length - 4);//删除后面的 " and "
                else if (strSql.EndsWith("or "))
                    strSql = strSql.Substring(0, strSql.Length - 3);//删除后面的 " or "

                if (conSql.Length == 0 && hasorder)
                    strSql += orderby;
            }
            return strSql;
        }
        /// <summary>
        /// 设置变量参数
        /// </summary>
        /// <param name="cmd">DbCommand</param>
        /// <param name="paraName">参数名</param>
        /// <param name="paraValue">参数值</param>
        private void CreateParams(ref OracleCommand cmd, string paraName, object paraValue)
        {
            OracleParameter pa = (OracleParameter)_provider.CreateParameter();
            pa.ParameterName = ":" + paraName;
            pa.Value = paraValue;
            pa.DbType = getDbType(paraValue.GetType().ToString().Split('.')[1]);
            cmd.Parameters.Add(pa);
        }
        /// <summary>
        /// 生成存储过程参数
        /// </summary>
        /// <param name="cmd">DbCommand</param>
        /// <param name="conditionValue">条件参数集合</param>
        private void CreateProcParams(ref OracleCommand cmd, NameValueCollection conditionValue)
        {
            if (conditionValue != null && conditionValue.Count > 0)
            {
                for (int i = 0; i < conditionValue.Count; i++)
                {
                    OracleParameter pa = (OracleParameter)_provider.CreateParameter();
                    pa.ParameterName = ":" + conditionValue.GetKey(i);
                    pa.Value = conditionValue.GetValues(i).GetValue(0);
                    cmd.Parameters.Add(pa);
                }
            }
        }

        /// <summary>
        ///私有: 获取数据类型(DbType)
        /// </summary>
        /// <param name="typename">数据类型名称</param>
        /// <returns>DbType</returns>
        private DbType getDbType(string typename)
        {
            //DbType t;
            #region switch datatype
            switch (typename.ToLower())
            {
                case "bigint":
                case "int64":
                    return DbType.Int64;
                case "int":
                case "int32":
                    return DbType.Int32;
                case "smallint":
                case "int16":
                    return DbType.Int16;
                case "binary":
                case "image":
                case "byte[]":
                case "varbinary":
                    return DbType.Binary;
                case "tinyint":
                case "bit":
                case "boolean":
                    return DbType.Boolean;
                case "varchar":
                case "text":
                case "nvarchar":
                case "ntext":
                case "nchar":
                case "char":
                case "string":
                    return DbType.String;
                case "datetime":
                case "smalldatetime":
                case "timestamp":
                    return DbType.DateTime;
                case "float":
                    return DbType.Double;
                case "decimal":
                case "money":
                case "smallmoney":
                    return DbType.Decimal;
                default:
                    return DbType.Object;
            }
            #endregion

        }
        #endregion

    }
}
