#!/usr/bin/env python
# -*- coding:utf-8 -*-

import configparser
import os, json, base64, gc
from decimal import Decimal
import datetime, time
import pymongo
import mongoengine
# import MySQLdb
from common.log.loger import Logger
import datetime, time, uuid, re
import hashlib
from common.error import *
from conf.conf import BaseConf
from tornado.options import define, options
import zipfile
import psutil
import threading


def my_options(arg):
    return dict(options.items())[arg]


class Config(object):
    """
    # Config().get_content("user_information")
    """

    def __init__(self):
        file_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "conf", BaseConf.BaseCnf)
        # file_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "conf", my_options("conf"))
        self.cf = configparser.ConfigParser()
        self.cf.read(file_path,encoding='utf-8')

    def get_sections(self):
        return self.cf.sections()

    def get_options(self, section):
        return self.cf.options(section)

    def get_content(self, section):
        result = {}
        for option in self.get_options(section):
            value = self.cf.get(section, option)
            result[option] = int(value) if value.isdigit() else value
        return result


class MongoDb(object):
    def __init__(self, uri, host, port, db_name, user=None, password=None):
        self._uri = uri
        self._db_host = host
        self._db_port = int(port)
        self._user = user
        self._password = password
        self._db = db_name
        self.conn = None

    def connect(self):
        self.conn = pymongo.MongoClient(self._db_host, self._db_port)
        return self.conn

    def get_db(self, db_name):
        collection = self.conn.get_database(db_name)
        if self._user and self._password:
            collection.authenticate(self._user, self._password)
        return collection

    def close(self):
        if self.conn:
            self.conn.close()
            self.conn = None


class MongoConfig(object):
    """
    # Config().get_content("user_information")
    """

    def __init__(self):
        file_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "conf", BaseConf.BaseMongoCnf)
        self.cf = configparser.ConfigParser()
        self.cf.read(file_path,encoding='utf-8')

    def get_sections(self):
        return self.cf.sections()

    def get_options(self, section):
        return self.cf.options(section)

    def get_content(self, section):
        result = {}
        for option in self.get_options(section):
            value = self.cf.get(section, option)
            result[option] = int(value) if value.isdigit() else value
        return result


def _remove_pool_keys(d):
    if isinstance(d, dict):
        return {k: _remove_pool_keys(v) for k, v in d.items() if k != '_pool'}
    elif isinstance(d, list):
        return [_remove_pool_keys(item) for item in d]
    return d


class Pymongoengine(MongoDb):
    def __init__(self, conf_name):
        self.conf = conf_name
        process_id = os.getpid()
        self._alias_pid = f'reportDefault_{process_id}'
        conf_filtered = _remove_pool_keys(conf_name)
        super(Pymongoengine, self).__init__(**conf_filtered)


    def connect_db(self):

        # 获取或创建进程独立的连接池
        try:
            pool = get_mongo_pool(self.conf)
            if pool and pool is not None:
                # 确保连接可用
                success = pool.ensure_connection()
                # 保存连接池对象到 self.conn
                self.conn = pool
                self._alias_pid = pool._alias_pid
            else:
                # 如果创建连接池失败，使用直接连接
                if self._uri:
                    self.conn = mongoengine.connect(host=self._uri, alias=self._alias_pid)
                else:
                    if self._user and self._password:
                        self.conn = mongoengine.connect(self._db, host=self._db_host, port=self._db_port,
                                                        username=self._user,
                                                        password=self._password, authentication_source=self._db,
                                                        alias=self._alias_pid)
                    else:
                        self.conn = mongoengine.connect(self._db, host=self._db_host, port=self._db_port,
                                                        alias=self._alias_pid)
            return mongoengine.DynamicDocument
        except Exception as ex:
            print(str(ex))

    def disconnect(self):
        # 无论是否使用连接池，都清理资源
        if hasattr(self, 'conn') and self.conn:
            # 如果是连接池对象，关闭连接
            if hasattr(self.conn, 'close_all'):
                self.conn.close_all()
            # 清理引用
            del self.conn

        # 清理MongoEngine连接
        try:
            mongoengine.disconnect(alias=self._alias_pid)
        except:
            pass

        # 触发垃圾回收
        gc.collect()

    def get_db(self, db_name):
        """获取数据库对象"""
        if hasattr(self, 'conn') and self.conn:
            # 检查conn是否是连接池对象
            if hasattr(self.conn, 'mongodb_cfg'):
                # 从连接池配置中获取数据库连接
                mongodb_cfg = self.conn.mongodb_cfg
                uri = mongodb_cfg.get("uri")
                host = mongodb_cfg.get("host", "localhost")
                port = int(mongodb_cfg.get("port", 27017))
                user = mongodb_cfg.get("user", "")
                password = mongodb_cfg.get("password", "")

                # 创建直接连接获取数据库
                if uri:
                    client = pymongo.MongoClient(uri)
                elif user and password:
                    client = pymongo.MongoClient(
                        host=host,
                        port=port,
                        username=user,
                        password=password,
                        authentication_source=db_name
                    )
                else:
                    client = pymongo.MongoClient(host=host, port=port)

                return client[db_name]
            else:
                # 直接使用conn获取数据库
                collection = self.conn.get_database(db_name)
                if self._user and self._password:
                    collection.authenticate(self._user, self._password)
                return collection
        return None

    @property
    def alias_pid(self):
        return self._alias_pid


def get_optimal_pool_size():
    """根据服务器资源获取最佳连接池大小"""
    cpu_count = psutil.cpu_count(logical=True)
    memory = psutil.virtual_memory()

    max_pool = 50

    if cpu_count:
        cpu_based = cpu_count * 10
        max_pool = min(max_pool, cpu_based)

    if memory.total:
        memory_gb = memory.total / (1024 ** 3)
        memory_based = int(memory_gb * 5)
        max_pool = min(max_pool, memory_based)

    max_pool = max(10, max_pool)
    min_pool = max(5, max_pool // 10)

    return max_pool, min_pool


class MongoConnectionPool:
    """MongoDB连接池管理器 - 优化大数据量查询性能"""
    
    # 大数据量查询优化配置
    DEFAULT_BATCH_SIZE = 10000
    DEFAULT_MAX_DOCUMENTS = 1000000
    SLOW_QUERY_THRESHOLD_MS = 5000
    
    def __init__(self, mongodb_cfg, max_connections=50, min_connections=5):
        self.mongodb_cfg = mongodb_cfg
        self.max_connections = max_connections
        self.min_connections = min_connections
        self._lock = threading.Lock()
        self._connected = False
        self._last_health_check = 0
        self._health_check_interval = 60  # 健康检查间隔（秒）
        
        process_id = os.getpid()
        self._alias_pid = f'reportDefault_{process_id}'
        
        # 慢查询记录
        self._slow_queries = []
        self._query_stats = {}
        
        # 连接池统计
        self._total_queries = 0
        self._total_query_time_ms = 0
        self._max_query_time_ms = 0
        
        self._try_connect()

    def _try_connect(self):
        """尝试建立连接 - 优化超时配置"""
        try:
            mongoengine.disconnect(alias=self._alias_pid)
        except:
            pass

        uri = self.mongodb_cfg.get("uri")
        host = self.mongodb_cfg.get("host", "localhost")
        port = int(self.mongodb_cfg.get("port", 27017))
        db_name = self.mongodb_cfg.get("db_name", "admin")
        user = self.mongodb_cfg.get("user", "")
        password = self.mongodb_cfg.get("password", "")

        # 优化的连接参数
        connect_params = {
            "alias": self._alias_pid,
            "connect": True,
            "maxPoolSize": self.max_connections,
            "minPoolSize": self.min_connections,
            "maxIdleTimeMS": 600000,      # 最大空闲时间10分钟 - 平衡性能与资源回收
            "socketTimeoutMS": 300000,     # Socket超时5分钟 - 适应大数据量查询
            "connectTimeoutMS": 30000,     # 连接超时30秒 - 给足够时间建立连接
            "serverSelectionTimeoutMS": 60000,  # 服务器选择超时60秒
            "waitQueueTimeoutMS": 60000,   # 等待队列超时60秒
            "retryWrites": True,
            "retryReads": True,
            "compressors": "snappy,zstd",
            "heartbeatFrequencyMS": 10000,  # 心跳频率10秒 - 及时检测连接状态
            "appname": "zkey_report"  # 应用标识，便于MongoDB监控
        }

        try:
            if uri:
                connect_params["host"] = uri
                mongoengine.connect(**connect_params)
            elif user and password:
                connect_params.update({
                    "db": db_name,
                    "host": host,
                    "port": port,
                    "username": user,
                    "password": password,
                    "authentication_source": db_name
                })
                mongoengine.connect(**connect_params)
            else:
                connect_params.update({
                    "db": db_name,
                    "host": host,
                    "port": port
                })
                mongoengine.connect(**connect_params)

            self._connected = True
            self._last_health_check = time.time()
            return True
        except Exception as e:
            print(f"MongoDB连接失败: {str(e)}")
            self._connected = False
            return False

    def ensure_connection(self):
        """确保连接可用 - 智能重试机制"""
        # 定期健康检查
        self._check_health()
        
        max_retries = 3
        retry_interval = 2

        for attempt in range(max_retries):
            if self._connected:
                return True

            with self._lock:
                if not self._connected:
                    success = self._try_connect()
                    if success:
                        return True

                    if attempt < max_retries - 1:
                        time.sleep(retry_interval)

        return self._connected

    def _check_health(self):
        """健康检查 - 自动检测并重建失效连接"""
        current_time = time.time()
        if current_time - self._last_health_check < self._health_check_interval:
            return

        self._last_health_check = current_time

        if not self._connected:
            return

        try:
            # 尝试执行简单查询验证连接
            from mongoengine import get_db
            db = get_db(alias=self._alias_pid)
            db.command('ping')
        except Exception as e:
            print(f"连接健康检查失败，尝试重建连接: {str(e)}")
            with self._lock:
                self._try_connect()

    def get_connection(self, timeout=30):
        """获取连接 - 返回配置信息用于重建连接"""
        return self.mongodb_cfg

    def release_connection(self, alias):
        """释放连接 - 空操作，由连接池自动管理"""
        pass

    def close_all(self):
        """关闭连接"""
        try:
            mongoengine.disconnect(alias=self._alias_pid)
        except:
            pass
        self._connected = False

    @property
    def alias_pid(self):
        return self._alias_pid

    def batch_query(self, collection_name, query_filter, projection=None, 
                   batch_size=DEFAULT_BATCH_SIZE, max_documents=DEFAULT_MAX_DOCUMENTS):
        """
        批量查询优化 - 适用于大数据量查询
        
        :param collection_name: 集合名称
        :param query_filter: 查询条件
        :param projection: 投影字段
        :param batch_size: 每批返回的文档数
        :param max_documents: 最大返回文档数
        :return: 生成器，逐批返回文档
        """
        if not self.ensure_connection():
            raise Exception("MongoDB连接不可用")

        try:
            from mongoengine import get_db
            db = get_db(alias=self._alias_pid)
            collection = db[collection_name]

            cursor = collection.find(query_filter, projection).batch_size(batch_size)
            
            count = 0
            for document in cursor:
                if count >= max_documents:
                    break
                yield document
                count += 1
                
        except Exception as e:
            print(f"批量查询失败: {str(e)}")
            raise

    def batch_aggregate(self, collection_name, pipeline, 
                       allow_disk_use=True, batch_size=DEFAULT_BATCH_SIZE,
                       data_set_id=None, data_set_flag=None, max_time_ms=None,
                       version=None):
        """
        批量聚合查询优化 - 适用于大数据量聚合分析
        
        :param collection_name: 集合名称
        :param pipeline: 聚合管道
        :param allow_disk_use: 是否允许使用磁盘（大数据量必须开启）
        :param batch_size: 每批返回的文档数
        :param data_set_id: 数据集ID
        :param data_set_flag: 数据集标识
        :param max_time_ms: 最大执行时间（毫秒），超时会抛出异常
        :param version: 版本号
        :return: 生成器，逐批返回结果
        """
        if not self.ensure_connection():
            raise Exception("MongoDB连接不可用")

        try:
            from mongoengine import get_db
            db = get_db(alias=self._alias_pid)
            collection = db[collection_name]

            # 当data_set_flag不是'vw'或'True'时，在pipeline开头追加match条件
            modified_pipeline = pipeline.copy()
            match_filter = {}
            
            if data_set_flag not in ['vw', 'True'] and data_set_id is not None:
                match_filter["dataSetId"] = data_set_id
            
            # 添加版本筛选条件
            if version is not None and data_set_flag != 'vw':
                match_filter["version"] = version
            
            # 如果有筛选条件，添加到pipeline开头
            if match_filter:
                modified_pipeline.insert(0, {"$match": match_filter})

            # 构建聚合参数
            aggregate_kwargs = {
                "allowDiskUse": allow_disk_use,
                "batchSize": batch_size
            }
            
            if max_time_ms is not None:
                aggregate_kwargs["maxTimeMS"] = max_time_ms

            cursor = collection.aggregate(
                modified_pipeline,
                **aggregate_kwargs
            )
            
            for document in cursor:
                yield document
                
        except Exception as e:
            print(f"批量聚合失败: {str(e)}")
            raise

    def insert_many_with_retry(self, collection_name, documents, batch_size=1000):
        """
        批量插入带重试 - 提高大数据量插入性能
        
        :param collection_name: 集合名称
        :param documents: 文档列表
        :param batch_size: 每批插入的文档数
        :return: 插入结果
        """
        if not self.ensure_connection():
            raise Exception("MongoDB连接不可用")

        try:
            from mongoengine import get_db
            db = get_db(alias=self._alias_pid)
            collection = db[collection_name]

            results = []
            total_docs = len(documents)
            
            for i in range(0, total_docs, batch_size):
                batch = documents[i:i + batch_size]
                result = collection.insert_many(batch, ordered=False)
                results.extend(result.inserted_ids)
            
            return results
            
        except Exception as e:
            print(f"批量插入失败: {str(e)}")
            raise

    def update_many_with_retry(self, collection_name, filter_query, update_query):
        """
        批量更新带重试
        
        :param collection_name: 集合名称
        :param filter_query: 过滤条件
        :param update_query: 更新操作
        :return: 更新结果
        """
        if not self.ensure_connection():
            raise Exception("MongoDB连接不可用")

        try:
            from mongoengine import get_db
            db = get_db(alias=self._alias_pid)
            collection = db[collection_name]

            result = collection.update_many(filter_query, update_query)
            return result
            
        except Exception as e:
            print(f"批量更新失败: {str(e)}")
            raise

    def monitor_query(self, query_name, duration_ms, result_count=0):
        """
        监控查询性能 - 记录慢查询
        
        :param query_name: 查询名称
        :param duration_ms: 查询耗时（毫秒）
        :param result_count: 返回结果数量
        """
        self._total_queries += 1
        self._total_query_time_ms += duration_ms
        self._max_query_time_ms = max(self._max_query_time_ms, duration_ms)
        
        # 记录慢查询
        if duration_ms > self.SLOW_QUERY_THRESHOLD_MS:
            self._slow_queries.append({
                'query_name': query_name,
                'duration_ms': duration_ms,
                'result_count': result_count,
                'timestamp': time.time()
            })
            # 只保留最近100条慢查询记录
            if len(self._slow_queries) > 100:
                self._slow_queries.pop(0)

    def get_query_stats(self):
        """获取查询统计信息"""
        avg_time = self._total_query_time_ms / self._total_queries if self._total_queries > 0 else 0
        
        return {
            'total_queries': self._total_queries,
            'total_time_ms': self._total_query_time_ms,
            'avg_time_ms': avg_time,
            'max_time_ms': self._max_query_time_ms,
            'slow_query_count': len(self._slow_queries)
        }

    def get_slow_queries(self, limit=10):
        """获取慢查询列表"""
        sorted_queries = sorted(
            self._slow_queries,
            key=lambda x: x['duration_ms'],
            reverse=True
        )
        return sorted_queries[:limit]
    
    def explain_aggregate(self, collection_name, pipeline, 
                        allow_disk_use=True, data_set_id=None, 
                        data_set_flag=None, version=None, verbose=False):
        """
        获取聚合查询的执行计划，用于性能调试
        
        :param collection_name: 集合名称
        :param pipeline: 聚合管道
        :param allow_disk_use: 是否允许使用磁盘
        :param data_set_id: 数据集ID
        :param data_set_flag: 数据集标识
        :param version: 版本号
        :param verbose: 是否返回详细执行计划
        :return: 查询执行计划
        """
        if not self.ensure_connection():
            raise Exception("MongoDB连接不可用")

        try:
            from mongoengine import get_db
            db = get_db(alias=self._alias_pid)
            collection = db[collection_name]

            # 构建匹配条件
            modified_pipeline = pipeline.copy()
            match_filter = {}
            
            if data_set_flag not in ['vw', 'True'] and data_set_id is not None:
                match_filter["dataSetId"] = data_set_id
            
            if version is not None and data_set_flag != 'vw':
                match_filter["version"] = version
            
            if match_filter:
                modified_pipeline.insert(0, {"$match": match_filter})

            # 执行explain
            explain_mode = "allPlansExecution" if verbose else "queryPlanner"
            explain_result = collection.aggregate(
                modified_pipeline,
                allowDiskUse=allow_disk_use,
                explain=explain_mode
            )
            
            return explain_result
            
        except Exception as e:
            print(f"获取执行计划失败: {str(e)}")
            raise


# 全局连接池缓存，按进程ID和配置键分组
_pool_cache = {}
_pool_cache_lock = threading.Lock()


def get_pool_key(mongodb_cfg):
    """获取连接池的唯一键"""
    if mongodb_cfg.get("uri"):
        return mongodb_cfg["uri"]
    return f"{mongodb_cfg.get('host', 'localhost')}:{mongodb_cfg.get('port', 27017)}:" \
        f"{mongodb_cfg.get('db_name', 'admin')}"


def get_mongo_pool(mongodb_cfg):
    """获取或创建MongoDB连接池 - 每个进程独立"""
    global _pool_cache

    try:
        process_id = os.getpid()
        pool_key = get_pool_key(mongodb_cfg)

        # 构建进程特定的缓存键
        cache_key = (process_id, pool_key)
        with _pool_cache_lock:
            # 检查当前进程是否已有该配置的连接池
            if cache_key in _pool_cache:
                pool = _pool_cache[cache_key]
                if pool and pool._connected:
                    return pool
                # 如果连接池存在但未连接，移除它
                del _pool_cache[cache_key]

            # 创建新的连接池
            max_pool, min_pool = get_optimal_pool_size()

            pool = MongoConnectionPool(
                mongodb_cfg,
                max_connections=max_pool,
                min_connections=min_pool
            )

            # 缓存新创建的连接池
            _pool_cache[cache_key] = pool
            return pool
    except Exception as e:
        print(str(e))
        return None


def result(status, value=None, message=None):
    """
    staatus:
    2000, 什么都ok
    4000, 客户上传的文件格式不正确
    4001， 客户上传的文件列超过5400
    4002， 值传递错误
    5000， 服务器错误
    5001， 数据表已经存在
    5002,  sql语句错误
    """
    if not message:
        try:
            message = CODEMSG[int(status)]
        except:
            message = "Unknown Error!!!"
    return {
        "statuscode": status,
        "statusmessage": message,
        "value": value
    }


class my_datetime():
    """
    Basic usage:

        a = datetime.datetime(2016, 9, 21, 13, 42, 8)
        b = "2016-11-15 15:32:12"
        c = u'2016-09-21 13:37:34'
        print type(c)
        d = 1474436826.0
        e = 13710788676.0
        ret = my_datetime()
        res = ret.become_datetime(e)
        print res
        print type(res)
    """

    def __init__(self):
        # 缺少对utc时间的判断
        pass

    def become_timestamp(self, dtdt):
        # 将时间类型转换成时间戳
        if isinstance(dtdt, datetime.datetime):
            timestamp = time.mktime(dtdt.timetuple())
            return timestamp

        elif isinstance(dtdt, str):
            if dtdt.split(" ")[1:]:
                a_datetime = datetime.datetime.strptime(dtdt, "%Y-%m-%d  %H:%M:%S")
                timestamp = time.mktime(a_datetime.timetuple())
            else:
                a_datetime = datetime.datetime.strptime(dtdt, "%Y-%m-%d")
                timestamp = time.mktime(a_datetime.timetuple())
            return timestamp

        elif isinstance(dtdt, float):
            return dtdt

            # elif isinstance(dtdt, unicode):
            #     if dtdt.split(" ")[1:]:
            #         a_datetime = datetime.datetime.strptime(dtdt, "%Y-%m-%d %H:%M:%S")
            #         timestamp = time.mktime(a_datetime.timetuple())
            #     else:
            #         a_datetime = datetime.datetime.strptime(dtdt, "%Y-%m-%d")
            #         timestamp = time.mktime(a_datetime.timetuple())
            #     return timestamp

    def become_datetime(self, dtdt):
        # 将时间类型转换成datetime类型
        if isinstance(dtdt, datetime.datetime):
            return dtdt

        elif isinstance(dtdt, str):
            if dtdt.split(" ")[1:]:
                a_datetime = datetime.datetime.strptime(dtdt, "%Y-%m-%d %H:%M:%S")
            else:
                a_datetime = datetime.datetime.strptime(dtdt, "%Y-%m-%d")
            return a_datetime

        elif isinstance(dtdt, float):
            # 把时间戳转换成datetime类型
            a_datetime = datetime.datetime.fromtimestamp(dtdt)
            return a_datetime

            # elif isinstance(dtdt, unicode):
            #     if dtdt.split(" ")[1:]:
            #         a_datetime = datetime.datetime.strptime(dtdt, "%Y-%m-%d %H:%M:%S")
            #     else:
            #         a_datetime = datetime.datetime.strptime(dtdt, "%Y-%m-%d")
            #     return a_datetime

    def become_str(self, dtdt):
        # 把时间类型转换成字符串
        if isinstance(dtdt, datetime.datetime):
            a_datetime = dtdt.strftime("%Y-%m-%d %H:%M:%S")
            return a_datetime

        elif isinstance(dtdt, str):
            return dtdt

        elif isinstance(dtdt, float):
            a_datetime_local = datetime.datetime.fromtimestamp(dtdt)
            a_datetime = a_datetime_local.strftime("%Y-%m-%d %H:%M:%S")
            return a_datetime

            # elif isinstance(dtdt, unicode):
            #     # 区别：一个是strp， 一个是strf
            #     if dtdt.split(" ")[1:]:
            #         a_datetime = datetime.datetime.strptime(dtdt, "%Y-%m-%d %H:%M:%S")
            #         a_datetime = a_datetime.strftime("%Y-%m-%d %H:%M:%S")
            #     else:
            #         a_datetime = datetime.datetime.strptime(dtdt, "%Y-%m-%d")
            #         a_datetime = a_datetime.strftime("%Y-%m-%d")
            #     return a_datetime

    @staticmethod
    def str_datetime():
        return (datetime.datetime.now()).strftime("%Y-%m-%d %H:%M:%S")


def MyGuid():
    date = datetime.datetime.now().strftime('%Y%m%d%H%M%S')

    us = ("%.7f" % time.time())[-7:]

    res = "".join(re.findall('\d+', str(uuid.uuid4())))[:7]

    ret = date + us + res

    return ret


def FormatMyStr(arg, type=None):
    if isinstance(arg, str):
        return arg.replace(' ', '').replace('\\', '').replace('/', '').replace("'", '').replace('"', '')
    elif isinstance(arg, list):
        if type:
            if type == int:
                return str([int(i) for i in arg]).replace("[", "(").replace("]", ")")
            elif type == float:
                return str([float(i) for i in arg]).replace("[", "(").replace("]", ")")
            elif type == str:
                return str([str(i) for i in arg]).replace("[", "(").replace("]", ")")
            else:
                return str(arg).replace("[", "(").replace("]", ")").replace("，", ",")
        else:
            return arg
    else:
        return ""


def GetFileSize(filePath, size=0):
    for root, dirs, files in os.walk(filePath):
        for f in files:
            size += os.path.getsize(os.path.join(root, f))
    return size


"""
    获取文件Md5值
    file_path = r'/opt/code/my_code/zk_css/zk_css.cnf'
    md5_02 = GetBigFileMd5Value(file_path)

"""


class ComplexEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, (datetime.datetime, datetime.date)):
            return str(obj.strftime("%Y-%m-%d %H:%M:%S"))
        elif isinstance(obj, Decimal):
            return str(obj)
        else:
            # return json.JSONEncoder.default(self, obj)
            return str(obj)


def GetBigFileMd5Value(file_path):
    f = open(file_path, 'rb')
    md5_obj = hashlib.md5()
    while True:
        d = f.read(8096)
        if not d:
            break
        md5_obj.update(d)
    hash_code = md5_obj.hexdigest()
    f.close()
    md5 = str(hash_code).lower()
    return md5


def JoinWhooshAPi(WhooshApiRet):
    i = WhooshApiRet["protocol"] + "://"
    # i = "http://"
    i += WhooshApiRet["host"] + ":" + str(WhooshApiRet['port'])
    return i


# -----<base64加密解密>----- #

class MyBase64:
    # 加密
    @staticmethod
    def encryption(arg):
        bytesString = arg.encode(encoding="utf-8")

        # base64 编码
        encodestr = base64.b64encode(bytesString)
        return encodestr.decode()

    @staticmethod
    def decryption(arg):
        decodestr = base64.b64decode(arg)

        return decodestr.decode()


def format_content(arg):
    if type(arg) == str:
        return str(arg).replace('<', "&lt").replace('>', "&gt")
    elif type(arg) == list or type(arg) == tuple:
        li = []
        for i in arg:
            if type(i) == str:
                li.append(str(i).replace('<', "&lt").replace('>', "&gt"))
            else:
                li.append(i)
        return li
    else:
        return arg


def addzip(li, filepathname):
    f = zipfile.ZipFile(filepathname,'w',zipfile.ZIP_DEFLATED)
    for i in li:
        file = i.split('/')[-1]
        f.write(i, file)
    f.close()


def JoinTableName(myBaseList):
    myTable = ""
    for i in range(len(myBaseList)):
        if myTable:
            myTable += str(myBaseList[i]["DatabaseName"]) + "." + str(myBaseList[i]["DataTableName"]) + " AS a" + str(i) + " ON " + "a" + str(
                i - 1) + ".mycustomid=a" + str(i) + ".mycustomid  INNER JOIN "
        else:
            myTable += str(myBaseList[i]["DataTableName"]) + " AS a" + str(i) + " INNER JOIN "

    myTable = myTable.rstrip("INNER JOIN ")
    return myTable


try:
    logDict = Config().get_content("log")
    logPath = logDict['logpath']
    logName = logDict['logname']

except Exception as e:
    logPath = None
    logName = None

my_log = Logger(filepath=logPath, filename=logName)

max_columns_count = 500

if __name__ == '__main__':
    # ret = FormatMyStr('"asdf/n')
    # print(ret)
    print(my_datetime.str_datetime())
