using System;
using System.Collections.Generic;
using System.Data.SQLite;
using System.Data;

namespace Common.Data.SqlLite
{
    /// <summary>
    /// 功能:SqlLite操作类
    /// 作者:王昊昇
    /// 时间:2012.2.8
    /// </summary>
    public class SqlLiteHelper : IDataHelper
    {
        /// <summary>
        /// 获取最后一条插入数据的自增主键值的查询语句
        /// </summary>
        public const string SELECT_IDENTITY_ID = "SELECT last_insert_rowid();";
        /// <summary>
        /// 获取本地时间部分语句
        /// </summary>
        public const string LOCAL_TIME_CMD = "DATETIME(CURRENT_TIMESTAMP,'LOCALTIME')";

        /// <summary>
        /// 处理命令
        /// </summary>
        /// <param name="conn">数据库连接</param>
        /// <param name="cmd">数据库命令对象</param>
        /// <param name="trans">事务对象</param>
        /// <param name="txt">命令</param>
        /// <param name="param">参数</param>
        private void PrepareCommand(SQLiteConnection conn, SQLiteCommand cmd,
            SQLiteTransaction trans, string txt, SQLiteParameter[] param)
        {
            cmd.Connection = conn;
            cmd.CommandText = txt;
            if (trans != null)
            {
                cmd.Transaction = trans;
            }
            cmd.CommandType = System.Data.CommandType.Text;
            if (param != null)
            {
                foreach (SQLiteParameter parm in param)
                {
                    cmd.Parameters.Add(parm);
                }
            }
        }

        /// <summary>
        /// 打开连接
        /// </summary>
        /// <param name="connString">连接字符串</param>
        /// <returns>连接对象</returns>
        public System.Data.IDbConnection OpenConnection(string connString)
        {
            SQLiteConnection conn = new SQLiteConnection();
            conn.ConnectionString = connString;
            conn.Open();
            return conn;
        }

        /// <summary>
        /// 打开连接
        /// </summary>
        /// <param name="connStrBuilder">连接字符串生成器</param>
        /// <returns>连接对象</returns>
        public System.Data.IDbConnection OpenConnection(System.Data.Common.DbConnectionStringBuilder connStrBuilder)
        {
            SQLiteConnection conn = new SQLiteConnection();
            conn.ConnectionString = connStrBuilder.ToString();
            conn.Open();
            return conn;
        }

        /// <summary>
        /// 关闭连接
        /// </summary>
        /// <param name="conn">连接对象</param>
        public void CloseConnection(System.Data.IDbConnection conn)
        {
            if (conn.State == System.Data.ConnectionState.Open)
            {
                conn.Close();
                conn.Dispose();
            }

            conn = null;
        }

        /// <summary>
        /// 读取数据
        /// </summary>
        /// <param name="conn">连接对象</param>
        /// <param name="sql">查询语句</param>
        /// <returns>数据读取器</returns>
        public System.Data.IDataReader ExecuteReader(System.Data.IDbConnection conn, string sql)
        {
            using (SQLiteCommand cmd = new SQLiteCommand(sql, (SQLiteConnection)conn))
            {
                SQLiteDataReader reader = cmd.ExecuteReader();

                return reader;
            }
        }

        /// <summary>
        /// 读取数据,支持参数
        /// </summary>
        /// <param name="conn">连接对象</param>
        /// <param name="sql">查询语句</param>
        /// <param name="param">参数</param>
        /// <returns>数据读取器</returns>
        public System.Data.IDataReader ExecuteReader(System.Data.IDbConnection conn, string sql,
            params System.Data.IDataParameter[] param)
        {
            using (SQLiteCommand cmd = new SQLiteCommand())
            {
                PrepareCommand((SQLiteConnection)conn, cmd, null, sql,
                    (SQLiteParameter[])param);
                SQLiteDataReader reader = cmd.ExecuteReader();
                cmd.Parameters.Clear();
                return reader;
            }
        }

        /// <summary>
        /// 执行带参数的更新语句,返回受影响行数
        /// </summary>
        /// <param name="conn">数据库连接</param>
        /// <param name="strSql">更新语句</param>
        /// <param name="param">参数列表</param>
        /// <returns>受影响行数</returns>
        public int ExecuteSql(System.Data.IDbConnection conn, string sql, params System.Data.IDataParameter[] param)
        {
            using (SQLiteCommand cmd = new SQLiteCommand())
            {
                PrepareCommand((SQLiteConnection)conn, cmd, null, sql,
                    (SQLiteParameter[])param);
                int r = cmd.ExecuteNonQuery();
                cmd.Parameters.Clear();

                return r;
            }
        }

        /// <summary>
        /// 执行更新语句,返回受影响行数
        /// </summary>
        /// <param name="conn">数据库连接</param>
        /// <param name="strSql">更新语句</param>
        /// <returns>受影响行数</returns>
        public int ExecuteSql(System.Data.IDbConnection conn, string sql)
        {
            using (SQLiteCommand cmd = new SQLiteCommand(sql, (SQLiteConnection)conn))
            {
                return cmd.ExecuteNonQuery();
            }
        }

        /// <summary>
        /// 执行数据处理事务
        /// </summary>
        /// <param name="conn">连接对象</param>
        /// <param name="list">执行语句列表</param>
        public void ExecuteSqlTran(System.Data.IDbConnection conn, List<string> list)
        {
            using (SQLiteCommand cmd = new SQLiteCommand())
            {
                cmd.Connection = (SQLiteConnection)conn;

                using (SQLiteTransaction trans = (SQLiteTransaction)conn.BeginTransaction())
                {
                    cmd.Transaction = trans;

                    foreach(var sql in list)
                    {
                        if (sql.Trim().Length > 0)
                        {
                            cmd.CommandText = sql;
                            cmd.ExecuteNonQuery();
                        }
                    }
                    trans.Commit();
                }
            }
        }

        /// <summary>
        /// 执行数据处理事务
        /// </summary>
        /// <param name="conn">连接对象</param>
        /// <param name="table">执行语句列表</param>
        public void ExecuteSqlTran(System.Data.IDbConnection conn, System.Collections.Hashtable table)
        {
            using (SQLiteCommand cmd = new SQLiteCommand())
            using (SQLiteTransaction trans = ((SQLiteConnection)conn).BeginTransaction())
            {
                foreach (System.Collections.DictionaryEntry de in table)
                {
                    string txt = de.Key.ToString();
                    SQLiteParameter[] param = (SQLiteParameter[])de.Value;
                    PrepareCommand((SQLiteConnection)conn, cmd, trans, txt, param);
                    int val = cmd.ExecuteNonQuery();
                    cmd.Parameters.Clear();

                    trans.Commit();
                }
            }
        }

        /// <summary>
        /// 执行查询语句,返回查询结果的第一行第一列的数据
        /// </summary>
        /// <param name="conn">连接对象</param>
        /// <param name="sql">查询语句</param>
        /// <returns>结果对象</returns>
        public object GetSingle(System.Data.IDbConnection conn, string sql)
        {
            using (SQLiteCommand cmd = new SQLiteCommand(sql, (SQLiteConnection)conn))
            {
                object obj = cmd.ExecuteScalar();

                if ((Object.Equals(obj, null)) || (Object.Equals(obj, System.DBNull.Value)))
                {
                    return null;
                }
                else
                {
                    return obj;
                }
            }
        }

        /// <summary>
        /// 执行带参数的查询语句,返回查询结果的第一行第一列的数据
        /// </summary>
        /// <param name="conn">连接对象</param>
        /// <param name="sql">查询语句</param>
        /// <param name="param">参数</param>
        /// <returns>结果对象</returns>
        public object GetSingle(System.Data.IDbConnection conn, string sql, params System.Data.IDataParameter[] param)
        {
            using (SQLiteCommand cmd = new SQLiteCommand())
            {
                PrepareCommand((SQLiteConnection)conn, cmd, null, sql,
                    (SQLiteParameter[])param);
                object obj = cmd.ExecuteScalar();
                cmd.Parameters.Clear();

                if ((Object.Equals(obj, null)) || (Object.Equals(obj, System.DBNull.Value)))
                {
                    return null;
                }
                else
                {
                    return obj;
                }
            }
        }

        /// <summary>
        /// 执行带参数的数据查询
        /// </summary>
        /// <param name="conn">连接对象</param>
        /// <param name="sql">查询语句</param>
        /// <param name="param">参数</param>
        /// <returns>数据集</returns>
        public System.Data.DataSet Query(System.Data.IDbConnection conn, string sql,
            params System.Data.IDataParameter[] param)
        {
            using (SQLiteCommand cmd = new SQLiteCommand())
            {
                PrepareCommand((SQLiteConnection)conn, cmd, null, sql,
                    (SQLiteParameter[])param);
                using (SQLiteDataAdapter da = new SQLiteDataAdapter(cmd))
                {
                    System.Data.DataSet ds = new System.Data.DataSet();
                    da.Fill(ds, "ds");
                    cmd.Parameters.Clear();

                    return ds;
                }
            }
        }

        /// <summary>
        /// 执行数据查询
        /// </summary>
        /// <param name="conn">连接对象</param>
        /// <param name="sql">查询语句</param>
        /// <returns>数据集</returns>
        public System.Data.DataSet Query(System.Data.IDbConnection conn, string sql)
        {
            using (SQLiteCommand cmd = new SQLiteCommand(sql, (SQLiteConnection)conn))
            using (SQLiteDataAdapter command = new SQLiteDataAdapter(sql, (SQLiteConnection)conn))
            {
                System.Data.DataSet ds = new System.Data.DataSet();
                command.Fill(ds, "ds");

                return ds;
            }
        }

        /// <summary>
        /// 执行数据查询
        /// </summary>
        /// <param name="conn">连接对象</param>
        /// <param name="sql">查询语句</param>
        /// <returns>数据表</returns>
        public System.Data.DataTable QueryReturnDataTable(System.Data.IDbConnection conn, string sql)
        {
            using (SQLiteCommand cmd = new SQLiteCommand(sql, (SQLiteConnection)conn))
            using (SQLiteDataAdapter command = new SQLiteDataAdapter(sql, (SQLiteConnection)conn))
            {
                System.Data.DataTable dt = new System.Data.DataTable();
                command.Fill(dt);

                return dt;
            }
        }

        /// <summary>
        /// 执行数据查询
        /// </summary>
        /// <param name="conn">连接对象</param>
        /// <param name="sql">查询语句</param>
        /// <param name="param">参数</param>
        /// <returns>数据表</returns>
        public System.Data.DataTable QueryReturnDataTable(System.Data.IDbConnection conn, string sql,
            params System.Data.IDataParameter[] param)
        {
            using (SQLiteCommand cmd = new SQLiteCommand())
            {
                PrepareCommand((SQLiteConnection)conn, cmd, null, sql,
                    (SQLiteParameter[])param);

                using (SQLiteDataAdapter command = new SQLiteDataAdapter(cmd))
                {
                    System.Data.DataTable dt = new System.Data.DataTable();
                    command.Fill(dt);
                    cmd.Parameters.Clear();

                    return dt;
                }
            }
        }

        /// <summary>
        /// 构建 SQLiteCommand 对象(用来返回一个结果集,而不是一个整数值)
        /// </summary>
        /// <param name="conn">连接对象</param>
        /// <param name="storedProcName">存储过程名</param>
        /// <param name="parameters">存储过程参数</param>
        /// <returns></returns>
        private SQLiteCommand BuildQueryCommand(System.Data.IDbConnection conn, string storedProcName, IDataParameter[] param)
        {
            SQLiteCommand command = new SQLiteCommand(storedProcName, (SQLiteConnection)conn);
            command.CommandType = System.Data.CommandType.StoredProcedure;

            foreach (SQLiteParameter parameter in param)
            {
                command.Parameters.Add(parameter);
            }
            return command;
        }

        /// <summary>
        /// 执行带返回值存储过程
        /// </summary>
        /// <param name="conn">连接对象</param>
        /// <param name="storedProcName">存储过程名</param>
        /// <param name="parameters">存储过程参数</param>
        /// <param name="RowsAffected">受影响行数</param>
        /// <returns></returns>
        private DataTable ExecutePageStoredProcedure(System.Data.IDbConnection conn, string storedProcName,
            IDataParameter[] parameters, out int rowsAffected)
        {
            SQLiteParameter OutParameters = new SQLiteParameter("@RowsAffected", DbType.Int32, 4, ParameterDirection.Output,
                                                            false, 0, 0, string.Empty, DataRowVersion.Default, null);
            using (DataSet dataSet = new DataSet())
            {
                using (SQLiteCommand command = BuildQueryCommand(conn, storedProcName, parameters))
                {
                    command.Parameters.Add(OutParameters);
                    using (SQLiteDataAdapter sqlDA = new SQLiteDataAdapter())
                    {
                        sqlDA.SelectCommand = command;
                        sqlDA.Fill(dataSet);
                    }
                    rowsAffected = Convert.ToInt32(command.Parameters["@RowsAffected"].Value);
                }
                return dataSet.Tables[0].Copy();
            }
        }

        /// <summary>
        /// 分页处理,取DataTable
        /// 使用PagingQuery分页存储过程
        /// </summary>
        /// <param name="conn">连接对象</param>
        /// <param name="tableName">表名</param>
        /// <param name="keyFieldName">以哪几列作为排序依据,多列以","分隔</param>
        /// <param name="columnList">字段列表,取表中的列,以","分隔,取全部数据使用"*"</param>
        /// <param name="where">查询条件</param>
        /// <param name="orderBy">排序方式</param>
        /// <param name="rowsAmountPerPage">每页记录数</param>
        /// <param name="pageIndex">指定页索引</param>
        /// <param name="pageConut">返回总页数</param>
        /// <param name="rowsAffected">返回总记录数</param>
        /// <returns></returns>
        public System.Data.DataTable PagingQuery(System.Data.IDbConnection conn, string tableName, string keyFieldName, string columnList, string where,
                                        OrderBy orderBy, int rowsAmountPerPage, int pageIndex, out int pageConut, out int rowsAffected)
        {
            int intRowsAffected = 0;

            SQLiteParameter[] Parameters = { new SQLiteParameter("@TableName", DbType.String), 
                                            new SQLiteParameter("@FieldName", DbType.String), 
                                            new SQLiteParameter("@OrderBy", DbType.Byte), 
                                            new SQLiteParameter("@ColList", DbType.String), 
                                            new SQLiteParameter("@StrWhere", DbType.String),
                                            new SQLiteParameter("@PageSize", DbType.Int32), 
                                            new SQLiteParameter("@PageIndex", DbType.Int32)};

            Parameters[0].Value = tableName;                // 表名
            Parameters[1].Value = keyFieldName;             // 按该列来分页
            Parameters[2].Value = orderBy.GetHashCode();    // 排序
            Parameters[3].Value = columnList;               // 每页记录数
            Parameters[4].Value = where;                    // 查询条件
            Parameters[5].Value = rowsAmountPerPage;        // 每页记录数
            Parameters[6].Value = pageIndex;                // 指定页

            DataTable dt = ExecutePageStoredProcedure(conn, "P_Paging", Parameters, out intRowsAffected);

            if (intRowsAffected % rowsAmountPerPage == 0)
            {
                pageConut = intRowsAffected / rowsAmountPerPage;
            }
            else
            {
                pageConut = intRowsAffected / rowsAmountPerPage + 1;
            }

            rowsAffected = intRowsAffected;

            return dt;
        }
    }
}