using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SystemX.Net.DB.DBType;
using SystemX.Common;
using SystemX.Common.Serialization;
using System.Data;
using System.Data.SqlClient;
using static SystemX.Net.Platform.Common.Util.LogMessage;
using System.Diagnostics;
using log4net.Config;

namespace SystemX.Net.DB
{
    public class XDBConnManager
    {
        public enum eDbType
        {
            Unknown,
            MS_SQL
        }

        public enum eConnCategory
        {
            Main,
            ShortTerm,
            LongTerm
        }

        private Stopwatch stMainDBAccessTime;

        private Stopwatch stShortTermDBAccessTime;

        private Stopwatch stLongTermDBAccessTime;

        private bool MAIN_CONNECT_STATE { set; get; }

        private bool SHORTTERM_CONNECT_STATE { set; get; }

        private bool LONGTERM_CONNECT_STATE { set; get; }

        public bool CONNECT_STATE
        {
            get { return MAIN_CONNECT_STATE && SHORTTERM_CONNECT_STATE && LONGTERM_CONNECT_STATE; }
        }

        protected void SET_CONNECT_STATE(eConnCategory eConn, bool bValue)
        {
            switch (eConn)
            {
                case eConnCategory.Main:
                    MAIN_CONNECT_STATE = bValue;
                    break;
                case eConnCategory.ShortTerm:
                    SHORTTERM_CONNECT_STATE = bValue;
                    break;
                case eConnCategory.LongTerm:
                    LONGTERM_CONNECT_STATE = bValue;
                    break; 
            }
        }

        protected bool GET_CONNECT_STATE(eConnCategory eConn)
        {
            switch (eConn)
            {
                case eConnCategory.Main:
                    return MAIN_CONNECT_STATE;
                case eConnCategory.ShortTerm:
                    return SHORTTERM_CONNECT_STATE;
                case eConnCategory.LongTerm:
                    return LONGTERM_CONNECT_STATE;
            }

            return false;
        }

        public string ConfigPath { get; set; }

        public XDBConnInfo InfoConnection { get; set; } = new XDBConnInfo();

        private IDBControl MgrMainConnection { set; get; }

        private IDBControl MgrShortTermConnection { set; get; }

        private IDBControl MgrLongTermConnection { set; get; }

        public XDBConnManager()
        {
            stMainDBAccessTime = new Stopwatch();
            stMainDBAccessTime.Start();

            stShortTermDBAccessTime = new Stopwatch();
            stShortTermDBAccessTime.Start();

            stLongTermDBAccessTime = new Stopwatch();
            stLongTermDBAccessTime.Start();

            MAIN_CONNECT_STATE = false;
            SHORTTERM_CONNECT_STATE = false;
            LONGTERM_CONNECT_STATE = false;
        }

        public long GetMainDBAccessTime()
        {
            if (stMainDBAccessTime != null)
                return stMainDBAccessTime.ElapsedMilliseconds;
            else
                return long.MinValue;
        }

        public void SetMainDBAccessTime()
        {
            if (stMainDBAccessTime != null)
                stMainDBAccessTime.Restart();
        }

        public long GetShortTermDBAccessTime()
        {
            if (stShortTermDBAccessTime != null)
                return stShortTermDBAccessTime.ElapsedMilliseconds;
            else
                return long.MinValue;
        }

        public void SetShortTermDBAccessTime()
        {
            if (stShortTermDBAccessTime != null)
                stShortTermDBAccessTime.Restart();
        }

        public long GetLongTermDBAccessTime()
        {
            if (stLongTermDBAccessTime != null)
                return stLongTermDBAccessTime.ElapsedMilliseconds;
            else
                return long.MinValue;
        }

        public void SetLongTermDBAccessTime()
        {
            if (stLongTermDBAccessTime != null)
                stLongTermDBAccessTime.Restart();
        }

        public IDBControl CurrentConnection(eConnCategory eConn)
        {
            if (GET_CONNECT_STATE(eConn))
            {
                switch (eConn)
                {
                    case eConnCategory.Main:
                        {
                            if (stMainDBAccessTime != null)
                                stMainDBAccessTime.Restart();
                        }
                        return MgrMainConnection;
                    case eConnCategory.ShortTerm:
                        {
                            if (stShortTermDBAccessTime != null)
                                stShortTermDBAccessTime.Restart();
                        }
                        return MgrShortTermConnection;
                    case eConnCategory.LongTerm:
                        {
                            if (stLongTermDBAccessTime != null)
                                stLongTermDBAccessTime.Restart();
                        }
                        return MgrLongTermConnection;          
                }

                return null;
            }
            else
                return null;
        }

        private bool ReadyForConnection(eConnCategory eConn)
        {
            bool bResult = true;

            try
            {
                string strSetType = string.Empty;

                eDbType eType = eDbType.Unknown;

                switch (eConn)
                {
                    case eConnCategory.Main:
                        strSetType = InfoConnection.ConnMain.Type;
                        break;
                    case eConnCategory.ShortTerm:
                        strSetType = InfoConnection.ConnShortTerm.Type;
                        break;
                    case eConnCategory.LongTerm:
                        strSetType = InfoConnection.ConnLongTerm.Type;
                        break;
                }

                if (!Enum.TryParse(strSetType, out eType))
                    throw new Exception("Failed Database type check.");

                switch (eConn)
                {
                    case eConnCategory.Main:
                        MgrMainConnection = CreateDBConnMgr(eType);
                        MgrMainConnection.ConnectionText = InfoConnection.GetConnectionStatement(eType, eConn);
                        break;
                    case eConnCategory.ShortTerm:
                        MgrShortTermConnection = CreateDBConnMgr(eType);
                        MgrShortTermConnection.ConnectionText = InfoConnection.GetConnectionStatement(eType, eConn);
                        break;
                    case eConnCategory.LongTerm:
                        MgrLongTermConnection = CreateDBConnMgr(eType);
                        MgrLongTermConnection.ConnectionText = InfoConnection.GetConnectionStatement(eType, eConn);
                        break;
                }
            }
            catch (Exception e)
            {
                bResult = false;

                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"Failed make connection.[SystemX.Net.DB : XDBConnManager.MakeConnection]\r\n" + e.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);
            }

            return bResult;
        }

        private bool MakeConnection(eConnCategory eConn)
        {
            bool bResult = true;

            try
            {
                bResult = ReadyForConnection(eConn);

                if(bResult)
                {
                    switch (eConn)
                    {
                        case eConnCategory.Main:
                            if (!MgrMainConnection.OpenConnection())
                                throw new Exception("Failed [Main] IDBControl.OpenConnection()");
                            break;
                        case eConnCategory.ShortTerm:
                            if (!MgrShortTermConnection.OpenConnection())
                                throw new Exception("Failed [ShortTerm] IDBControl.OpenConnection()");
                            break;
                        case eConnCategory.LongTerm:
                            if (!MgrLongTermConnection.OpenConnection())
                                throw new Exception("Failed [LongTerm] IDBControl.OpenConnection()");
                            break;
                    }
                }
            }
            catch (Exception e)
            {
                bResult = false;

                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"Failed make connection.[SystemX.Net.DB : XDBConnManager.MakeConnection]\r\n" + e.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);
            }

            return bResult;
        }


        private bool MakeConnection(eConnCategory eConn, bool bUseHostInfo, string strHostTableName, string strUserTableName)
        {
            bool bResult = true;

            try
            {
                bResult = ReadyForConnection(eConn);

                if (bResult)
                {
                    switch (eConn)
                    {
                        case eConnCategory.Main:
                            if (!MgrMainConnection.OpenConnection(bUseHostInfo, strHostTableName, strUserTableName))
                                throw new Exception("Failed [Main] IDBControl.OpenConnection()");
                            break;
                        case eConnCategory.ShortTerm:
                            if (!MgrShortTermConnection.OpenConnection(bUseHostInfo, strHostTableName, strUserTableName))
                                throw new Exception("Failed [ShortTerm] IDBControl.OpenConnection()");
                            break;
                        case eConnCategory.LongTerm:
                            if (!MgrLongTermConnection.OpenConnection(bUseHostInfo, strHostTableName, strUserTableName))
                                throw new Exception("Failed [LongTerm] IDBControl.OpenConnection()");
                            break;
                    }
                }
            }
            catch (Exception e)
            {
                bResult = false;

                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"Failed make connection.[SystemX.Net.DB : XDBConnManager.MakeConnection]\r\n" + e.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);
            }

            return bResult;
        }

        public bool OpenConnection(bool bReadCfgFile = true)
        {
            return CONNECT_STATE;
        }
        public bool OpenConnection(bool bUseHostInfo, string strHostTableName, string strUserTableName, bool bReadCfgFile = true)
        {
            SET_CONNECT_STATE(eConnCategory.Main, true);
            SET_CONNECT_STATE(eConnCategory.ShortTerm, true);
            SET_CONNECT_STATE(eConnCategory.LongTerm, true);

            try
            {
                if (bReadCfgFile)
                {
                    if (InfoConnection.ReadConfig(ConfigPath) == false)
                    {
                        MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"Fail read DB info file.[SystemX.Net.DB : XDBConnManager.OpenConnection]", ConsoleColor.Yellow, LogMessageLevel.DEBUG);

                        throw new Exception("Failed ReadConfig()");
                    }
                }

                SET_CONNECT_STATE(eConnCategory.Main, MakeConnection(eConnCategory.Main, bUseHostInfo, strHostTableName, strUserTableName));
                SET_CONNECT_STATE(eConnCategory.ShortTerm, MakeConnection(eConnCategory.ShortTerm));
                SET_CONNECT_STATE(eConnCategory.LongTerm, MakeConnection(eConnCategory.LongTerm));

                if (GET_CONNECT_STATE(eConnCategory.Main) == false ||
                    GET_CONNECT_STATE(eConnCategory.ShortTerm) == false ||
                    GET_CONNECT_STATE(eConnCategory.LongTerm) == false)
                    throw new Exception();
            }
            catch (Exception e)
            {
                MessageOutput.ConsoleWrite(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss>>") + @"Fail db connect.[SystemX.Net.DB : XDBConnManager.OpenConnection - Parameter Type]\r\n" + e.Message, ConsoleColor.Yellow, LogMessageLevel.DEBUG);
            }

            return CONNECT_STATE;
        }

        IDBControl CreateDBConnMgr(eDbType eType)
        {
            switch (eType)
            {
                case eDbType.MS_SQL:
                    return new XDBTMSSQL();
                default:
                    return null;
            }
        }
        public SqlDataReader QueryDatabase(eConnCategory eConn, string strStmt)
        {
            IDBControl ctrlDB = null;

            switch (eConn)
            {
                case eConnCategory.Main:
                    ctrlDB = MgrMainConnection; 
                    break;
                case eConnCategory.ShortTerm:
                    ctrlDB = MgrShortTermConnection;
                    break;
                case eConnCategory.LongTerm:
                    ctrlDB = MgrLongTermConnection;
                    break;
            }

            SqlDataReader drResult = ctrlDB.QueryDatabase(strStmt);

            return drResult;
        }
        public DataTable QueryDatabaseInTable(eConnCategory eConn, string strStmt)
        {
            IDBControl ctrlDB = null;

            switch (eConn)
            {
                case eConnCategory.Main:
                    ctrlDB = MgrMainConnection;
                    break;
                case eConnCategory.ShortTerm:
                    ctrlDB = MgrShortTermConnection;
                    break;
                case eConnCategory.LongTerm:
                    ctrlDB = MgrLongTermConnection;
                    break;
            }

            DataTable dtResult = ctrlDB.QueryDataTable(strStmt);

            return dtResult;
        }
        public DataSet QueryDatabaseInSet(eConnCategory eConn, string strStmt)
        {
            IDBControl ctrlDB = null;

            switch (eConn)
            {
                case eConnCategory.Main:
                    ctrlDB = MgrMainConnection;
                    break;
                case eConnCategory.ShortTerm:
                    ctrlDB = MgrShortTermConnection;
                    break;
                case eConnCategory.LongTerm:
                    ctrlDB = MgrLongTermConnection;
                    break;
            }

            DataSet dsResult = ctrlDB.QueryDataSet(strStmt);

            return dsResult;
        }
    }
}
