# -*- coding: utf-8 -*-
import os
import configparser
import traceback
import jpype
import socket
from multiprocessing import Lock
from .sqlclijdbc import connect as jdbcconnect
from .testcliexception import TestCliException


# TestCli的Meta管理，使用H2数据库作为管理方式
class TestCliMeta(object):
    def __init__(self):
        self.JobManagerEnabled = False
        self.dbConn = None
        self.MetaServer = None
        self.MetaURL = None
        self.MetaPort = 0
        self.JarList = None

    def setJVMJarList(self, p_JarList):
        self.JarList = p_JarList

    def DisConnect(self):
        if self.dbConn is not None:
            self.dbConn.close()

    def ShutdownServer(self):
        if self.MetaServer is not None:
            # 先停止数据库连接
            if self.dbConn is not None:
                self.dbConn.close()
            # 再停止数据库服务
            try:
                self.MetaServer.stop()
                self.MetaServer.shutdown()
            except Exception:
                if "TESTCLI_DEBUG" in os.environ:
                    print('traceback.print_exc():\n%s' % traceback.print_exc())
                    print('traceback.format_exc():\n%s' % traceback.format_exc())
            self.MetaServer = None

    def StartAsServer(self, p_ServerParameter):
        # 检查TESTCLI_HOME是否存在
        try:
            # 读取配置文件，并连接数据库
            m_AppOptions = configparser.ConfigParser()
            m_conf_filename = os.path.join(os.path.dirname(__file__), "conf", "testcli.ini")
            m_AppOptions.read(m_conf_filename)
            m_MetaClass = m_AppOptions.get("meta_driver", "driver")
            m_MetaDriverFile = os.path.join(os.path.dirname(__file__),
                                            "jlib", m_AppOptions.get("meta_driver", "filename"))
            if not os.path.exists(m_MetaDriverFile):
                raise TestCliException("TestCli-0000: "
                                       "TestCliMeta:: Driver file [" + m_MetaDriverFile +
                                       "] does not exist! JobManager Aborted!")
            m_MetaDriverURL = m_AppOptions.get("meta_driver", "jdbcurl")
            self.dbConn = jdbcconnect(jclassname=m_MetaClass, url=m_MetaDriverURL,
                                      driver_args={'user': 'sa', 'password': 'sa'},
                                      jars=self.JarList)
            if self.dbConn is None:
                raise TestCliException("TestCli-0000: "
                                       "TestCliMeta:: Connect to meta failed! JobManager Aborted!")
            # 设置AutoCommit为False
            self.dbConn.setAutoCommit(False)

            # 获得一个可用的端口
            if "TESTCLI_METAPORT" in os.environ:
                self.MetaPort = int(os.environ["TESTCLI_METAPORT"])
            else:
                m_PortFileLocker = Lock()
                m_PortFileLocker.acquire()
                self.MetaPort = 0
                try:
                    sock = socket.socket()
                    sock.bind(('', 0))
                    self.MetaPort = sock.getsockname()[1]
                    sock.close()
                except Exception:
                    if "TESTCLI_DEBUG" in os.environ:
                        print('traceback.print_exc():\n%s' % traceback.print_exc())
                        print('traceback.format_exc():\n%s' % traceback.format_exc())
                    self.MetaPort = 0
                m_PortFileLocker.release()
                if self.MetaPort == 0:
                    raise TestCliException("TestCli-0000: "
                                           "TestCliMeta:: Can't get avalable port! JobManager Aborted!")

            # 启动一个TCP Server，用来给其他后续的H2连接（主要是子进程）
            # 端口号为随机获得，或者利用固定的参数
            self.MetaServer = jpype.JClass("org.h2.tools.Server").\
                createTcpServer("-tcp", "-tcpAllowOthers", "-tcpPort", str(self.MetaPort))
            self.MetaServer.start()
            self.MetaURL = "tcp://127.0.0.1:" + str(self.MetaPort)

            # 初始化Meta数据库表
            m_db_cursor = self.dbConn.cursor()

            m_SQL = "Create Table IF Not Exists TESTCLI_ServerInfo" \
                    "(" \
                    "ProcessID       Integer," \
                    "ParentProcessID Integer," \
                    "ProcessPath     VARCHAR(500)," \
                    "Parameter       VARCHAR(500)," \
                    "StartTime       TimeStamp," \
                    "EndTime         TimeStamp" \
                    ")"
            m_db_cursor.execute(m_SQL)
            m_SQL = "CREATE TABLE IF Not Exists TESTCLI_JOBS" \
                    "(" \
                    "JOB_ID                     Integer," \
                    "JOB_Name                   VARCHAR(500)," \
                    "JOB_TAG                    VARCHAR(500)," \
                    "Starter_Interval           Integer," \
                    "Starter_Last_Active_Time   TimeStamp," \
                    "Parallel                   Integer," \
                    "Loop                       Integer," \
                    "Started_JOBS               Integer," \
                    "Failed_JOBS                Integer," \
                    "Finished_JOBS              Integer," \
                    "Active_JOBS                Integer," \
                    "Error_Message              VARCHAR(500)," \
                    "Script                     VARCHAR(500)," \
                    "Script_FullName            VARCHAR(500)," \
                    "Think_Time                 Integer," \
                    "Timeout                    Integer," \
                    "Submit_Time                TimeStamp," \
                    "Start_Time                 TimeStamp," \
                    "End_Time                   TimeStamp," \
                    "Blowout_Threshold_Count    Integer," \
                    "Status                     VARCHAR(500)" \
                    ")"
            m_db_cursor.execute(m_SQL)
            m_SQL = "CREATE TABLE IF Not Exists TESTCLI_WORKERS" \
                    "(" \
                    "JOB_ID                     Integer," \
                    "JOB_Name                   VARCHAR(500)," \
                    "JOB_TAG                    VARCHAR(500)," \
                    "WorkerHandler_ID           Integer," \
                    "ProcessID                  Integer," \
                    "start_time                 BIGINT," \
                    "end_time                   BIGINT," \
                    "exit_code                  Integer," \
                    "Finished_Status            VARCHAR(500)," \
                    "Timer_Point                VARCHAR(500)" \
                    ")"
            m_db_cursor.execute(m_SQL)
            m_SQL = "CREATE TABLE IF Not Exists TESTCLI_WORKERS_HISTORY" \
                    "(" \
                    "JOB_ID                     Integer," \
                    "JOB_Name                   VARCHAR(500)," \
                    "JOB_TAG                    VARCHAR(500)," \
                    "WorkerHandler_ID           Integer," \
                    "ProcessID                  Integer," \
                    "start_time                 BIGINT," \
                    "end_time                   BIGINT," \
                    "exit_code                  Integer," \
                    "Finished_Status            VARCHAR(500)," \
                    "Timer_Point                VARCHAR(500)" \
                    ")"
            m_db_cursor.execute(m_SQL)
            m_SQL = "CREATE TABLE IF Not Exists TESTCLI_TRANSACTIONS" \
                    "(" \
                    "Transaction_Name           VARCHAR(500)," \
                    "Transaction_StartTime      Integer," \
                    "Transaction_EndTime        Integer,"\
                    "Transaction_Status         Integer" \
                    ")"
            m_db_cursor.execute(m_SQL)
            m_SQL = "CREATE TABLE IF Not Exists TESTCLI_TRANSACTIONS_STATISTICS" \
                    "(" \
                    "Transaction_Name           VARCHAR(500)," \
                    "Max_Transaction_Time       Integer," \
                    "Min_Transaction_Time       Integer," \
                    "Sum_Transaction_Time       Integer," \
                    "Transaction_Count          Integer," \
                    "Transaction_Failed_Count   Integer," \
                    "Transaction_Items          ARRAY default ARRAY[]" \
                    ")"
            m_db_cursor.execute(m_SQL)
            m_db_cursor.close()

            m_ProcessID = os.getpid()
            m_ParentProcessID = os.getppid()
            m_ProcessPath = os.path.dirname(__file__)
            m_SQL = "Insert Into TESTCLI_ServerInfo(ProcessID, ParentProcessID, ProcessPath, Parameter, StartTime)" \
                    "Values(" + str(m_ProcessID) + "," + str(m_ParentProcessID) + \
                    ",'" + str(m_ProcessPath) + "','" + str(p_ServerParameter) + "', CURRENT_TIMESTAMP())"
            m_db_cursor = self.dbConn.cursor()
            m_db_cursor.execute(m_SQL)
            m_db_cursor.close()
            self.dbConn.commit()

            # 任务调度管理只有在Meta能够成功连接的情况下才可以使用
            self.JobManagerEnabled = False
        except TestCliException as se:
            raise se
        except Exception as e:
            if "TESTCLI_DEBUG" in os.environ:
                print('traceback.print_exc():\n%s' % traceback.print_exc())
                print('traceback.format_exc():\n%s' % traceback.format_exc())
            raise TestCliException("TestCli-0000: "
                                   "TestCliMeta:: " + str(e) + " JobManager Aborted!")

    def ConnectServer(self, p_MetaServerURL):
        if p_MetaServerURL is None:
            # 如果没有Meta的连接信息，直接退出
            return

        try:
            # 读取配置文件，并连接数据库
            m_AppOptions = configparser.ConfigParser()
            m_conf_filename = os.path.join(os.path.dirname(__file__), "conf", "testcli.ini")
            if os.path.exists(m_conf_filename):
                m_AppOptions.read(m_conf_filename)
            else:
                if "TESTCLI_DEBUG" in os.environ:
                    print("DEBUG:: TestCliMeta:: testcli.ini does not exist! JobManager Connect Failed!")
                return
            m_MetaClass = m_AppOptions.get("meta_driver", "driver")
            m_MetaDriverFile = os.path.join(os.path.dirname(__file__),
                                            "jlib", m_AppOptions.get("meta_driver", "filename"))
            if not os.path.exists(m_MetaDriverFile):
                if "TESTCLI_DEBUG" in os.environ:
                    print("DEBUG:: TestCliMeta:: Driver file does not exist! JobManager Connect Failed!")
                return
            m_MetaDriverURL = m_AppOptions.get("meta_driver", "jdbcurl")
            m_MetaDriverURL = m_MetaDriverURL.replace("mem", p_MetaServerURL + "/mem")
            self.dbConn = jdbcconnect(jclassname=m_MetaClass, url=m_MetaDriverURL,
                                      driverArgs={'user': 'sa', 'password': 'sa'},
                                      jars=self.JarList)
            if self.dbConn is None:
                if "TESTCLI_DEBUG" in os.environ:
                    print("DEBUG:: TestCliMeta:: Connect to meta failed! JobManager Connect Failed!")
                return

            # 设置AutoCommit为False
            self.dbConn.setAutoCommit(False)
        except Exception:
            if "TESTCLI_DEBUG" in os.environ:
                print('traceback.print_exc():\n%s' % traceback.print_exc())
                print('traceback.format_exc():\n%s' % traceback.format_exc())

    def DisConnectServer(self):
        if self.dbConn:
            self.dbConn.close()
