using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;
using System.Data.SqlClient;
using System.Net;
using System.Security.Policy;
using System.Data.Common;

using DataBaseConnection.Control;

using DevExpress.XtraBars;

using SystemX.Product.ALIS.UI.View;
using SystemX.Net.Platform.Common.Util;
using SystemX.Product.ALIS.UI.Subs;
using SystemX.Product.ALIS.Interface;
using SystemX.Product.ALIS.UI.View.Base;

using static SystemX.Product.ALIS.UI.View.ViewCfg;
using static SystemX.Net.Platform.Common.Util.LogMessage;
using static SystemX.Product.ALIS.UI.Commons;
using SystemX.Common;

namespace SystemX.Product.ALIS.UI
{
    public partial class FrmMain : DevExpress.XtraBars.Ribbon.RibbonForm, IChildController, IDataController
    {
        public class UserInfo
        {
            public string UserID;
            public string Name;
            public string Dept;
            public string Email;
            public string Comment;
            public string Password;

            public UserInfo()
            {
                UserID = "";
                Name = "";
                Dept = "";
                Email = "";
                Comment = "";
                Password = "";
            }
            public void Clear()
            {
                UserID = "";
                Name = "";
                Dept = "";
                Email = "";
                Comment = "";
                Password = "";
            }
        }

        private List<FrmChild> DocFrames { get; set; }


        /*DbConnection conn { get; set; }

        DbCommand SQLCmd { get; set; }*/

        private SqlConnection SQLConnection { get; set; }
        private SqlCommand SQLCmd { get; set; }

        BackgroundWorker worker = new BackgroundWorker();
        WaitProgressForm loadForm = null;
        Stopwatch stLoadFormWait = new Stopwatch();

        private string strUserInputConnectInfo;

        private async void ReadingCompleted(object args)
        {
            loadForm.BringToFront();
            loadForm.Focus();

            if (stLoadFormWait.ElapsedMilliseconds <= 1000)
            {
                int iremainTime = 1000 - (int)stLoadFormWait.ElapsedMilliseconds;
                await Task.Delay(iremainTime);
            }

            if (loadForm != null)
            {
                loadForm.Close();
                loadForm = null;
            }

            if (SQLConnection == null)
            {
                bDatabaseConnState = false;

                MessageBox.Show("DB connection failed. Check the DB status or check the connection address.", "[SystemX.Product.ALIS.UI]", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            if (bDatabaseConnState == false)
            {
                //this.Close();

                SetDBConn();
            }
            else
            {
                ConnectInfoINICtrl CCtrl = new ConnectInfoINICtrl();
                CCtrl.SetLastestConnectInfo(strUserInputConnectInfo);

                barStaticItemConn.Visibility = BarItemVisibility.Always;

                barStaticItemConn.ShowImageInToolbar = true;

                string strAddress = (strConnIPAddress == string.Empty ? "LocalHost" : strConnIPAddress);

                strAddress += " , " + nConnPort.ToString();

                barStaticItemConn.Caption += " [" + strAddress + "] [" + strConnCN /*DatabaseConnControl.CatalogName*/ + "] [" + strConnUID + "]";

                barButtonItemConnect.Enabled = false;
                barButtonItemLogout.Enabled = true;
            }
        }

        private void CheckSqlOption(SqlConnection SqlConn)
        {
            //옵션 확인 및 ON
            //DECLARE @ARITHABORT VARCHAR(3) = 'OFF'; IF ( (64 & @@OPTIONS) = 64 ) SET @ARITHABORT = 'ON'; SELECT @ARITHABORT AS ARITHABORT;
            string strGetQuery1 = "DECLARE @ARITHABORT VARCHAR(3) = 'OFF'; IF ( (64 & @@OPTIONS) = 64 ) SET @ARITHABORT = 'ON'; SELECT @ARITHABORT AS ARITHABORT;";
            string strGetQuery2 = "DECLARE @ARITHIGNORE VARCHAR(3) = 'OFF'; IF ( (128 & @@OPTIONS) = 128 ) SET @ARITHIGNORE = 'ON'; SELECT @ARITHIGNORE AS ARITHIGNORE;";
            /*
            SET ARITHIGNORE ON

             - 쿼리 실행 중 오버플로 또는 0으로 나누기 오류에서 오류 메시지를 반환할지 여부를 제어

　                 오류 메시지가 반환될지 여부만 제어하며 이 설정에 상관 없이 오버플로 또는 0으로 나누기 오류를  
　                 발생시킨 계산에 NULL을 반환한다. 없는 값 처리를 해야하므고 오류를 발생시킨 것에서  null 반환을 받아야 한다!

            SET ARITHABORT ON이면 오버플로 또는 0으로 나누기 오류 발생 시 쿼리나 일괄 처리가 종료 
　                 트랜잭션에서 해당 오류가 발생하면 트랜잭션이 롤백시킨다.  그러나 이 설정이 INSERT, UPDATE, DELETE 문 실행 중에  
　                 발생한 오류에는 영향을 주지 않는다.  
            */

            DataTable dtResult1 = new DataTable();
            DataTable dtResult2 = new DataTable();

            using (SqlCommand SqlCommand = new SqlCommand(strGetQuery1, SqlConn))
            {
                SqlCommand.CommandTimeout = 300;

                DbDataReader dtReader = SqlCommand.ExecuteReader();

                dtResult1.Load(dtReader);

                dtReader.Close();
            }
            //
            using (SqlCommand SqlCommand = new SqlCommand(strGetQuery2, SqlConn))
            {
                SqlCommand.CommandTimeout = 300;

                DbDataReader dtReader = SqlCommand.ExecuteReader();

                dtResult2.Load(dtReader);

                dtReader.Close();
            }
            //
            if (XCommons.isHasRow(dtResult1))
            {
                bool bOptionState = dtResult1.Rows[0]["ARITHABORT"].ToString() == "ON" ? true : false;

                if (bOptionState == false)
                    SetSqlOption(SqlConn, "SET ARITHABORT ON");
            }
            if (XCommons.isHasRow(dtResult2))
            {
                bool bOptionState = dtResult2.Rows[0]["ARITHIGNORE"].ToString() == "ON" ? true : false;

                if (bOptionState == false)
                    SetSqlOption(SqlConn, "SET ARITHIGNORE ON");
            }
        }

        private void SetSqlOption(SqlConnection SqlConn, string strQuery)
        {
            using (SqlCommand SqlCommand = new SqlCommand(strQuery, SqlConn))
            {
                SqlCommand.CommandTimeout = 300;

                int nRows = SqlCommand.ExecuteNonQuery();
            }
        }

        private void PerformDatabaseConnect()
        {
            SQLConnection = null;

            try
            {
                try
                {
                    //TODO : Conn Database
                    if (strConnIPAddress == string.Empty)
                        SQLConnection = DatabaseConnControl.ConnectDB(strConnCN);
                    else
                        SQLConnection = DatabaseConnControl.ConnectDB(strConnIPAddress,
                            strConnCN,
                            strConnUID,
                            strConnPW,
                            nConnPort);

                    SQLCmd = new SqlCommand();
                    SQLCmd.Connection = DatabaseConnControl.conn;

                    CheckSqlOption(SQLConnection);

                    bDatabaseConnState = true;
                }
                catch (Exception ex)
                {
                    bDatabaseConnState = false;

                    MessageOutput.ConsoleWrite($"DB Connection Error: {ex.Message}", ConsoleColor.Red, LogMessage.LogMessageLevel.FATAL);
                }
            }
            finally
            {
                if (SQLConnection == null)
                {
                    bDatabaseConnState = false;

                    MessageBox.Show("DB connection failed. Check DB status. Automatically close the program.", "[SystemX.Product.ALIS.UI]", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        public UserInfo CurrentUser;

        public LoginAccessLevel ACCESS_LEVEL { internal set; get; }

        private string strTitleLabel;

        private Stopwatch stCheckLoginTime;

        private string strConnIPAddress;

        private int nConnPort;

        private string strConnCN;

        private string strConnUID;

        private string strConnPW;

        eAppFunctionType eCurrentSelectFuncType;

        public string GetServerConnectIP()
        {
            return strConnIPAddress;
        }

        public int GetServerConnectPort()
        {
            return nConnPort;
        }

        private bool bDatabaseConnState;

        public FrmMain()
        {
            InitializeComponent();

            ConsoleUtil.ConsoleHide();

            CurrentUser = new UserInfo();

            ACCESS_LEVEL = LoginAccessLevel.None;

            strTitleLabel = this.Text;

            SetOnOperationMarker(false);

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

            worker.DoWork += (sender, args) => PerformDatabaseConnect();
            worker.RunWorkerCompleted += (sender, args) => ReadingCompleted(bDatabaseConnState);

            stLoadFormWait.Start();

            ribbon.SelectedPage = ribbonPageMain;

            this.KeyPreview = true;

            eCurrentSelectFuncType = eAppFunctionType.None;
        }

        protected override void WndProc(ref Message message)
        {
            if (LoginCheck(LoginAccessLevel.Basic))
                stCheckLoginTime.Restart();

            base.WndProc(ref message);
        }

        private bool CheckDatabaseConnState()
        {
            if (bDatabaseConnState == false)
                MessageBox.Show("No database connected. Connect first.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);

            return bDatabaseConnState;
        }

        void RefreshView(eAppFunctionType funcType)
        {
            if (CheckDatabaseConnState() == false)
                return;

            try
            {
                FrmChild frmFound = DocFrames.Find(x => x.DocType == funcType);

                if (frmFound == null)
                    return;
                else
                {
                    frmFound.RefreshView();
                }
            }
            catch (Exception ex)
            {
                LogMessage.MessageOutput.ConsoleWrite($"Error On Open View. Error Message: {ex.Message}");
            }

            return;
        }

        UserControl OpenViewModel(eAppFunctionType funcType, LoginAccessLevel CreateAccessLevel, eSelectType eSelType = eSelectType.None, bool bLoginState = false)
        {
            if (CheckDatabaseConnState() == false)
                return null;

            if (DocFrames == null)
                DocFrames = new List<FrmChild>();

            try
            {
                FrmChild frmFound = DocFrames.Find(x => x.DocType == funcType);

                if (frmFound == null)
                {
                    frmFound = new FrmChild(this, funcType, eSelType, funcType.ToString(), CreateAccessLevel, bLoginState);
                    frmFound.Text = funcType.ToString();

                    DocFrames.Add(frmFound);

                    frmFound.Show();
                }
                else
                {
                    frmFound.Select();
                }

                return frmFound.WindowControl as UcBaseView;
            }
            catch (Exception ex)
            {
                LogMessage.MessageOutput.ConsoleWrite($"Error On Open View. Error Message: {ex.Message}");

                return null;
            }
        }

        private void SetDBConn()
        {
            strConnIPAddress = string.Empty;

            strConnCN = DatabaseConnControl.CatalogName;

            strConnUID = DatabaseConnControl.CatalogConnUID;

            strConnPW = DatabaseConnControl.CatalogConnPW;

            nConnPort = DatabaseConnControl.CatalogConnPort;

            this.BringToFront();
            this.Focus();

            ConnectForm connFrm = new ConnectForm(null);
            DialogResult dr = connFrm.ShowDialog();

            if (dr == DialogResult.OK || dr == DialogResult.Ignore)
            {
                strUserInputConnectInfo = connFrm.strInputText;

                strConnIPAddress = connFrm.strGetConnIPAddress;

                nConnPort = connFrm.nGetConnPort;

                strConnCN = connFrm.strGetConnCN;

                strConnUID = connFrm.strGetConnUID;

                strConnPW = connFrm.strGetConnPW;

                loadForm = new WaitProgressForm();
                loadForm.setDescription("Connecting ...");
                loadForm.Location = new Point(this.Width / 2, this.Height / 2);

                //loadForm.ShowOnTopMode = DevExpress.XtraWaitForm.ShowFormOnTopMode.AboveAll;

                stLoadFormWait.Restart();

                worker.RunWorkerAsync(null);

                loadForm.ShowDialog();
            }
            else
                this.Close();
        }

        private void FrmMain_Load(object sender, EventArgs e)
        {
            SetDBConn();
        }

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            switch (msg.Msg)
            {
                case 0x100:
                case 0x104:
                    switch (keyData)
                    {
                        case Keys.Control | Keys.I:
                            MessageBox.Show("Ctrl + I pressed");
                            break;
                    }
                    break;
            }
            return base.ProcessCmdKey(ref msg, keyData);
        }

        private void LoginProc()
        {
            //SetOnOperationMarker(false);

            if (CheckDatabaseConnState() == false)
                return;

            LoginForm loginForm = new LoginForm(this);

            using (GetOnOperationUserLoginMarker())
            {
                DialogResult dr = loginForm.ShowDialog();
                switch (dr)
                {
                    case DialogResult.OK:
                        {
                            LoginInfoINICtrl LCtrl = new LoginInfoINICtrl();
                            LCtrl.SetLastestLoginInfo(loginForm.UserID);

                            CurrentUser.UserID = loginForm.UserID;
                            CurrentUser.Name = loginForm.UserName;
                            CurrentUser.Dept = loginForm.UserDept;
                            CurrentUser.Email = loginForm.UserEmail;
                            CurrentUser.Comment = loginForm.UserComment;
                            CurrentUser.Password = loginForm.UserPassword;

                            if (CurrentUser.UserID.CompareTo("Admin") == 0)
                                ACCESS_LEVEL = LoginAccessLevel.Admin;
                            else
                                ACCESS_LEVEL = LoginAccessLevel.Basic;

                            SetOnOperationMarker(true);

                            ribbon.SelectedPage = ribbonPageManagement;
                        }
                        break;
                    case DialogResult.Cancel:
                        {
                            SetOnOperationMarker(false);
                        }
                        break;
                }
            }
        }

        private void barButtonItem_Login_ItemClick(object sender, ItemClickEventArgs e)
        {
            LoginProc();
        }

        private void barButtonItemUserLogout_ItemClick(object sender, ItemClickEventArgs e)
        {
            SetOnOperationMarker(false);
        }

        private void timerSystem_Tick(object sender, EventArgs e)
        {
            if (LoginCheck(LoginAccessLevel.Basic))
            {
                if (Commons.DEBUG_MODE == false)
                {
                    DispLoginTimeText();

                    /* Login Timeout Disabled
                    if (stCheckLoginTime.ElapsedMilliseconds >= 600000)
                        SetOnOperationMarker(false);
                    */
                }
            }
        }

        private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (SQLConnection != null) // && bDatabaseConnState)
            {
                if (MessageBox.Show("You want to program exit?", "[SystemX.Product.ALIS.UI]", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
                    e.Cancel = true;
                else
                {
                    DatabaseConnControl.DisconnectDB();

                    e.Cancel = false;
                }
            }
        }

        private void barButtonItemConsole_ItemClick(object sender, ItemClickEventArgs e)
        {
            ConsoleUtil.ConsoleVisibleControl();
        }

        private void barButtonItemConnect_ItemClick(object sender, ItemClickEventArgs e)
        {
            using (GetOnOperationDBConnMarker(true))
            {
                if (bDatabaseConnState)
                {
                    ;//
                }

                SetDBConn();
            }
        }

        private void barButtonItemLogout_ItemClick(object sender, ItemClickEventArgs e)
        {
            using (GetOnOperationDBConnMarker(false))
            {
                SetOnOperationMarker(false);

                CloseAllChildForm();

                DatabaseConnControl.DisconnectDB();

                bDatabaseConnState = false;
            }
        }

        private void FrmMain_KeyDown(object sender, KeyEventArgs e)
        {
            switch(e.KeyCode)
            {
                case Keys.F1: LoginProc(); break;
                case Keys.F2: OpenViewModel(eAppFunctionType.M_TestListFile, LoginAccessLevel.Basic, eSelectType.TestListFile, LoginCheck(LoginAccessLevel.Basic)); break;
                case Keys.F3: OpenViewModel(eAppFunctionType.M_TestListVariant, LoginAccessLevel.Basic, eSelectType.TestListVariant, LoginCheck(LoginAccessLevel.Basic)); break;
                case Keys.F4: OpenViewModel(eAppFunctionType.M_TestListRelease, LoginAccessLevel.Basic, eSelectType.TestListRelease, LoginCheck(LoginAccessLevel.Basic)); break;
                case Keys.F5: RefreshView(eCurrentSelectFuncType); break;
                case Keys.F6: OpenViewModel(eAppFunctionType.M_HostList, LoginAccessLevel.Basic, eSelectType.HostList, LoginCheck(LoginAccessLevel.Basic)); break;
                case Keys.F7: OpenViewModel(eAppFunctionType.M_GroupList, LoginAccessLevel.Basic, eSelectType.GroupList, LoginCheck(LoginAccessLevel.Basic)); break;
                case Keys.F8: OpenViewModel(eAppFunctionType.M_TestCodeList, LoginAccessLevel.Basic, eSelectType.TestCodeList, LoginCheck(LoginAccessLevel.Basic)); break;
                case Keys.F9: OpenViewModel(eAppFunctionType.M_UserList, LoginAccessLevel.Admin, eSelectType.UserList, LoginCheck(LoginAccessLevel.Admin)); break;
            }
        }
    }
}