using Apewer.Internals;

#if NETFRAMEWORK
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.OleDb;
using System.IO;
using System.Text;
#endif

namespace Apewer.Source
{

    /// <summary>用于快速连接 Microsoft Access 数据库的辅助。</summary>
    public partial class Access
    {

        /// <summary>尝试解析 Access 文件的密码。</summary>
        /// <remarks>当操作系统启用随机化内存分配时,此方法可能会产生异常。</remarks>
        public static string[] ParsePassword(string path) => AccessHelper.GetPassword(path);

    }

#if NETFRAMEWORK

    public partial class Access : IDbClientBase, IDbClientAdo, IDisposable
    {

        #region 连接

        string _connstr = null;
        OleDbConnection _connection = null;
        Timeout _timeout = null;

        /// <summary>获取或设置日志记录。</summary>
        public Logger Logger { get; set; }

        /// <summary>获取或设置超时。</summary>
        public Timeout Timeout { get => _timeout; }

        /// <summary>构造函数。</summary>
        public Access(string connectrionString, Timeout timeout)
        {
            _connstr = connectrionString;
            _timeout = timeout ?? Timeout.Default;
        }

        #endregion

        #region 连接

        /// <summary>获取当前的 OldDbConnection 对象。</summary>
        public IDbConnection Connection { get => _connection; }

        /// <summary>数据库是否已经连接。</summary>
        public bool Online
        {
            get
            {
                if (_connection != null)
                {
                    if (_connection.State == ConnectionState.Open) return true;
                }
                return false;
            }
        }

        /// <summary>连接数据库,若未连接则尝试连接。</summary>
        /// <returns>错误信息。</returns>
        public string Connect()
        {
            if (_connection == null)
            {
                _connection = new OleDbConnection();
                _connection.ConnectionString = _connstr;
            }
            else
            {
                if (_connection.State == ConnectionState.Open) return null;
            }
            try
            {
                _connection.Open();
                if (_connection.State == ConnectionState.Open) return null;
            }
            catch (Exception ex)
            {
                Logger.Error(nameof(Access), "Connect", ex, _connstr);
                Close();
                return ex.Message;
            }
            return "连接失败。";
        }

        /// <summary>释放对象所占用的系统资源。</summary>
        public void Close()
        {
            if (_connection != null)
            {
                if (_transaction != null)
                {
                    if (_autocommit) Commit();
                    else Rollback();
                }
                _connection.Close();
                _connection.Dispose();
                _connection = null;
            }
        }

        /// <summary>释放资源。</summary>
        public void Dispose() => Close();

        #endregion

        #region Transaction

        private IDbTransaction _transaction = null;
        private bool _autocommit = false;

        /// <summary>启动事务。</summary>
        public string Begin(bool commit = true) => Begin(commit, null);

        /// <summary>启动事务。</summary>
        public string Begin(bool commit, Class<IsolationLevel> isolation)
        {
            var connect = Connect();
            if (connect.NotEmpty()) return connect;
            if (_transaction != null) return "存在已启动的事务,无法再次启动。";
            try
            {
                _transaction = isolation ? _connection.BeginTransaction(isolation.Value) : _connection.BeginTransaction();
                _autocommit = commit;
                return null;
            }
            catch (Exception ex)
            {
                Logger.Error(nameof(Access), "Begin", ex.Message());
                return ex.Message();
            }
        }

        /// <summary>提交事务。</summary>
        public string Commit()
        {
            if (_transaction == null) return "事务不存在。";
            try
            {
                _transaction.Commit();
                RuntimeUtility.Dispose(_transaction);
                _transaction = null;
                return null;
            }
            catch (Exception ex)
            {
                RuntimeUtility.Dispose(_transaction);
                _transaction = null;
                Logger.Error(nameof(Access), "Commit", ex.Message());
                return ex.Message();
            }
        }

        /// <summary>从挂起状态回滚事务。</summary>
        public string Rollback()
        {
            if (_transaction == null) return "事务不存在。";
            try
            {
                _transaction.Rollback();
                RuntimeUtility.Dispose(_transaction);
                _transaction = null;
                return null;
            }
            catch (Exception ex)
            {
                RuntimeUtility.Dispose(_transaction);
                _transaction = null;
                Logger.Error(nameof(Access), "Rollback", ex.Message);
                return ex.Message();
            }
        }

        #endregion

        #region 查询和执行

        /// <summary>使用 SQL 语句进行查询。</summary>
        public IQuery Query(string sql) => Query(sql, null);

        /// <summary>使用 SQL 语句进行查询。</summary>
        public IQuery Query(string sql, IEnumerable<IDataParameter> parameters)
        {
            if (sql.IsBlank()) return Example.InvalidQueryStatement;

            var connected = Connect();
            if (connected.NotEmpty()) return new Query(false, connected);

            try
            {
                using (var command = new OleDbCommand())
                {
                    command.Connection = _connection;
                    command.CommandTimeout = Timeout.Query;
                    command.CommandText = sql;
                    if (parameters != null)
                    {
                        foreach (var p in parameters)
                        {
                            if (p != null) command.Parameters.Add(p);
                        }
                    }
                    using (var ds = new DataSet())
                    {
                        using (var da = new OleDbDataAdapter(sql, _connection))
                        {
                            const string name = "result";
                            da.Fill(ds, name);
                            var table = ds.Tables[name];
                            return new Query(table);
                        }
                    }
                }
            }
            catch (Exception exception)
            {
                Logger.Error(nameof(Access), "Query", exception, sql);
                return new Query(exception);
            }
        }

        /// <summary>执行 SQL 语句。</summary>
        public IExecute Execute(string sql) => Execute(sql, null);

        /// <summary>执行 SQL 语句,并加入参数。</summary>
        public IExecute Execute(string sql, IEnumerable<IDataParameter> parameters)
        {
            if (sql.IsBlank()) return Example.InvalidExecuteStatement;

            var connected = Connect();
            if (connected.NotEmpty()) return new Execute(false, connected);

            var inTransaction = _transaction != null;
            if (!inTransaction) Begin();
            try
            {
                using (var command = new OleDbCommand())
                {
                    command.Connection = _connection;
                    command.Transaction = (OleDbTransaction)_transaction;
                    command.CommandTimeout = Timeout.Execute;
                    command.CommandText = sql;
                    if (parameters != null)
                    {
                        foreach (var parameter in parameters)
                        {
                            if (parameter == null) continue;
                            command.Parameters.Add(parameter);
                        }
                    }
                    var rows = command.ExecuteNonQuery();
                    if (!inTransaction) Commit(); // todo 此处应该检查事务提交产生的错误。
                    return new Execute(true, rows);
                }
            }
            catch (Exception exception)
            {
                Logger.Error(nameof(Access), "Execute", exception, sql);
                if (!inTransaction) Rollback();
                return new Execute(exception);
            }
        }

        #endregion

        #region Parameter

        /// <summary>创建参数列表。</summary>
        public static List<IDbDataParameter> NewParameterList()
        {
            return new List<IDbDataParameter>();
        }

        /// <summary>创建参数。</summary>
        public static IDbDataParameter CreateParameter(String field, DbType type, Int32 size, Object value)
        {
            var p = new OleDbParameter();
            p.ParameterName = field;
            p.DbType = type;
            p.Size = size;
            p.Value = value;
            return p;
        }

        /// <summary>创建参数。</summary>
        public static IDbDataParameter CreateParameter(String field, DbType type, Object value)
        {
            var p = new OleDbParameter();
            p.ParameterName = field;
            p.DbType = type;
            p.Value = value;
            return p;
        }

        #endregion

        #region protected

        /// <summary>获取或设置连接字符串。</summary>
        internal protected static string GenerateCS(string provider, string path, string pass, string jo)
        {
            if (!File.Exists(path)) return null;

            var sb = new StringBuilder();

            sb.Append("provider=", provider, "; ");

            if (!string.IsNullOrEmpty(path)) sb.Append("data source=", path, "; ");

            if (string.IsNullOrEmpty(pass)) sb.Append("persist security info=false; ");
            else sb.Append("jet oledb:database password=\"", pass, "\"; ");

            // Microsoft Access Workgroup Information
            if (!string.IsNullOrEmpty(jo)) sb.Append("jet oledb:system database=", jo, "; ");

            return sb.ToString();
        }

        #endregion

    }

    /// <summary>使用 Microsoft.Jet.OLEDB.4.0 访问 Access 97 - 2003 数据库文件。</summary>
    public class AccessJet4 : Access
    {

        const string JetOleDB4 = "microsoft.jet.oledb.4.0";

        /// <summary>创建 Access 类的新实例。</summary>
        public AccessJet4(string path, string pass = null, string jo = null, Timeout timeout = null)
            : base(GenerateCS(JetOleDB4, path, pass, jo), timeout) { }

    }

    /// <summary>使用 Microsoft.ACE.OLEDB.12.0 访问 Access 2007 数据库文件。</summary>
    public class AccessAce12 : Access
    {

        const string AceOleDB12 = "microsoft.ace.oledb.12.0";

        /// <summary>创建 Access 类的新实例。</summary>
        public AccessAce12(string path, string pass = null, string jo = null, Timeout timeout = null)
            : base(GenerateCS(AceOleDB12, path, pass, jo), timeout) { }

    }

#endif

}