using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using parkMonitor.tools;
using MySql.Data.MySqlClient;
using System.Configuration;
using parkMonitor.entity;

namespace parkMonitor.Database2
{
    /// <summary>
    /// 连接池管理
    /// </summary>
    class ConnectionPoolManager
    {
        //public static BlockingQueue bq = new BlockingQueue();
        public static bool malfunctionRemote = false;
        public static bool malfunctionLocal = false;
        /// <summary>
        /// 连接字符串
        /// </summary>
        public static string localStr = "SqlConnectionLocation";
        public static string remoteStr = "SqlConnectionStr";
        public static string localConf, remoteConf;
        public static string localIP, remoteIP;
        /// <summary>
        /// 数据库连接字符串配置文件初始化
        /// </summary>
        public static void Init()
        {
            try
            {
                localConf = ConfigurationManager.AppSettings[localStr];
                remoteConf = ConfigurationManager.AppSettings[remoteStr];
                localIP = ConfigurationManager.AppSettings["localDBIP"];
                remoteIP = ConfigurationManager.AppSettings["remoteDBIP"];
            }
            catch
            {
                Console.WriteLine("配置文件有误");
            }
        }
        /// <summary>
        /// 初始化连接池，在项目界面初始化时，进行数据库连接池初始化一般设为10个连接
        /// </summary>
        /// <param name="max"></param>
        /// <param name="connectionString"></param>
        /// <returns></returns>
        public static BlockingQueue InitConnPooling(int max, string connectionString)
        {
            BlockingQueue bq = new BlockingQueue();
            for (int i = 0; i < max; i++)
            {
                Connection conn = DatabaseConnPoolFactory.CreateConnection(connectionString);
                if (conn != null && conn.mySqlConnFlag)
                {
                    bq.Enqueue(conn);
                    Console.WriteLine("连接成功入队");
                }
            }
            return bq;
        }
        /// <summary>
        /// 获取连接
        /// </summary>
        /// <returns></returns>
        public static Connection GetConnection(BlockingQueue bq)
        {
            Connection connection = (Connection)bq.Dequeue();
            if (connection != null && !CheckConnection(connection, bq))
            {
                connection.mySqlConnFlag = false;
                while (!connection.mySqlConnFlag)
                {
                    connection.Dispose();
                    AddConnToPooling(1, remoteConf);
                    connection = (Connection)bq.Dequeue();
                }
            }
            Console.WriteLine("连接成功出队");
            return connection;
        }
        /// <summary>
        /// 获取连接，超时返回null
        /// </summary>
        /// <param name="bq"></param>
        /// <param name="millisecondsTimeout"></param>
        /// <returns></returns>
        public static Connection GetConnection(BlockingQueue bq, int millisecondsTimeout)
        {
            object conn = null;
            Connection connection = null;
            bq.Dequeue(out conn, millisecondsTimeout);
            connection = (Connection)conn;
            Console.WriteLine("连接出队检测");
            Console.WriteLine("输入参数连接池个数：" + bq.Count());
            if (!CheckConnection(connection,bq))
            {
                CheckConnPooling(2, 10, remoteConf, bq);
                bq.Dequeue(out conn, millisecondsTimeout);
                connection = (Connection)conn;
            }
            Console.WriteLine("连接成功出队");
            return connection;
        }
        /// <summary>
        /// 移除连接
        /// </summary>
        /// <param name="conn"></param>
        public static void RemoveConnection(Connection conn)
        {
            if (conn != null)
            {
                conn.Dispose();
            }
        }
        /// <summary>
        /// 定时重置连接
        /// </summary>
        /// <param name="max"></param>
        /// <param name="connectionString"></param>
        /// <param name="bq"></param>
        public static void ResetConnPooling(int max, string connectionString, BlockingQueue bq)
        {
            CloseAll(bq);
            InitConnPooling(max, connectionString);
        }
        /// <summary>
        /// 添加连接到池中
        /// </summary>
        /// <param name="max"></param>
        /// <param name="connectionString"></param>
        public static void AddConnToPooling(int max, string connectionString)
        {
            InitConnPooling(max, connectionString);
        }
        /// <summary>
        /// 检查连接池连接是否可用，3<=连接数<=10        
        /// </summary>
        /// <param name="min"> min = 3</param>
        /// <param name="max">max = 10</param>
        /// <param name="bq">server=59.175.148.85;uid=root;pwd=x5;database=zxpark</param>
        public static void CheckConnPooling(int min, int max, string connectionString, BlockingQueue bq)
        {
            Connection conn = null;
            int total = bq.Count();
            if (total == 0)
            {
                Console.WriteLine("请工作人员检查数据库是否开启，网络是否通畅！等待50秒");
                //Thread.Sleep(5000);
                //在此可以切换数据库
            }
            else
            {
                for (int i = 0; i < total; i++)
                {
                    conn = GetConnection(bq, 1000);
                    CheckConnection(conn, bq);
                    ReleaseConnection(conn, bq);
                }
            }
            if (bq.Count() < min)
            {
                AddConnToPooling(max - min, connectionString);
            }
        }
        /// <summary>
        /// 释放连接，将连接返回阻塞队列
        /// </summary>
        /// <param name="conn"></param>
        /// <param name="bq"></param>
        public static void ReleaseConnection(Connection conn, BlockingQueue bq)
        {
            bq.Enqueue(conn);
        }
        /// <summary>
        /// 检查连接
        /// </summary>
        /// <param name="conn"></param>
        /// <param name="bq"></param>
        /// <returns></returns>
        public static bool CheckConnection(Connection conn, BlockingQueue bq)
        {
            bool isUseful = true;
            try
            {
                string sql = "select count(*) from garage";
                if (conn != null)
                {
                    DBAccess access = new DBAccess(sql, conn, CommandTypes.SCALARCOMMAND);
                    object result = access.GetResult();
                    if (result != null)
                    {
                        int r = Convert.ToInt32(result);
                        isUseful = true;
                        Console.WriteLine("连接测试正常");
                    }
                }
            }
            catch (Exception ex)
            {
                if (conn != null)
                {
                    conn.Dispose();
                }
                AddConnToPooling(1, remoteConf);
                Console.WriteLine("连接检测失败，重新添加一个连接入队");
                isUseful = false;
                Console.WriteLine(ex.Message);
            }
            return isUseful;
        }
        /// <summary>
        /// 关闭所有连接
        /// </summary>
        public static void CloseAll(BlockingQueue bq)
        {
            if (bq != null)
            {
                while (bq.Count() > 0)
                {
                    Connection connection = (Connection)bq.Dequeue();
                    if (connection != null)
                    {
                        connection.Close();
                    }
                }
            }
            Console.WriteLine("所有连接成功关闭！");
        }
    }
}
