#!D:\IDE\Anaconda3\envs\Microscope_Scan python
# -*- coding: UTF-8 -*-

"""
 @Author: Administrator
 @FileName: AppConvert.py
 @DateTime: 2025/3/25 10:14
 @SoftWare: PyCharm
 @Author  ：xsh
"""
import datetime
import json
import yaml
import base64
from PyQt5 import Qt
import hashlib
class AppConvert:

    @staticmethod
    def index_alpha_begin(string: str) -> int:
        index = -1
        if not isinstance(string, str) or len(string) <= 0:
            return index
        for _index, _char in enumerate(string):
            if AppConvert.is_alpha_char(_char):
                index = _index
                break
        return index

    @staticmethod
    def clear_special_char(string: str) -> int:
        special: str = ''
        if not isinstance(string, str) or len(string) <= 0:
            return special
        for _index, _char in enumerate(string):
            if AppConvert.is_alpha_char(_char):
                special += _char
        return special

    """判断字符是否为特殊符号"""
    @staticmethod
    def is_special_char(s) -> bool:
        if len(s) != 1:
            return False
        # 定义特殊字符集：所有非字母、非数字、非空格的字符
        return not (s.isalpha() or s.isdigit() or s.isspace())
    """判断字符是否为字母或数据"""
    @staticmethod
    def is_alpha_char(s) -> bool:
        if len(s) != 1:
            return False
        return not s.isspace() and (s.isalpha() or s.isdigit())

    @staticmethod
    def isBase(buffer) -> bool:
        if isinstance(buffer, (int, float, bool)):
            return True
        elif isinstance(buffer, str):
            return True
        elif isinstance(buffer, dict):

            return True
        elif isinstance(buffer, (list, tuple)):
            return True
        return False
        # return isinstance(buffer, (int, str, float, bool, dict, list, set))
    @staticmethod
    def toMD5(buffer: str) -> str:
        if not isinstance(buffer, str) or len(buffer) <= 0:
            return ''
        md5hash = hashlib.md5(buffer.encode('utf-8'))
        md5 = md5hash.hexdigest()
        return f'{md5}'

    class _YamlDumper(yaml.Dumper):
        """自定义 YAML Dumper 以处理日期时间类型"""

        def represent_datetime(self, data):
            return self.represent_scalar('tag:yaml.org,2002:timestamp', data.isoformat())

        def represent_date(self, data):
            return self.represent_scalar('tag:yaml.org,2002:date', data.isoformat())

        def represent_time(self, data):
            return self.represent_scalar('tag:yaml.org,2002:timestamp', data.isoformat())

        def represent_qdatetime(self, data):
            return self.represent_scalar('tag:yaml.org,2002:timestamp', data.toString("yyyy-MM-dd hh:mm:ss"))

        def represent_qdate(self, data):
            return self.represent_scalar('tag:yaml.org,2002:date', data.toString("yyyy-MM-dd"))

        def represent_qtime(self, data):
            return self.represent_scalar('tag:yaml.org,2002:timestamp', data.toString("hh:mm:ss"))

    _YamlDumper.add_representer(datetime.datetime   , _YamlDumper.represent_datetime)
    _YamlDumper.add_representer(datetime.date       , _YamlDumper.represent_date)
    _YamlDumper.add_representer(datetime.time       , _YamlDumper.represent_time)
    _YamlDumper.add_representer(Qt.QDateTime    , _YamlDumper.represent_qdatetime)
    _YamlDumper.add_representer(Qt.QDate        , _YamlDumper.represent_qdate)
    _YamlDumper.add_representer(Qt.QTime        , _YamlDumper.represent_qtime)

    @staticmethod
    def ReadFile(filename: str) -> str:
        info: Qt.QFileInfo = Qt.QFileInfo(filename)
        buffer: str = ""
        if not info.exists():
            return buffer
        fp: Qt.QFile = Qt.QFile(info.absoluteFilePath())
        if fp.open(Qt.QIODevice.ReadOnly | Qt.QIODevice.Text):
            stream: Qt.QTextStream = Qt.QTextStream(fp)
            stream.setCodec('UTF-8')
            stream >> buffer
            fp.close()

        return buffer

    @staticmethod
    def SaveFile(filename: str, buffer: str) -> bool:
        isRight: bool = False
        info: Qt.QFileInfo = Qt.QFileInfo(filename)
        if not info.dir().exists():
            info.dir().mkpath(info.absolutePath())
        fp: Qt.QFile = Qt.QFile(info.absoluteFilePath())
        if fp.open(Qt.QIODevice.WriteOnly | Qt.QIODevice.Text):
            try:
                stream: Qt.QTextStream = Qt.QTextStream(fp)
                stream.setCodec('UTF-8')
                stream << buffer
                isRight = True
            except Exception:
                isRight = False
            fp.close()

        return isRight


    @staticmethod
    def toYaml(buffer) -> str:
        """将任意 Python 对象转换为 YAML 字符串"""
        return yaml.dump(buffer, encoding='utf-8', allow_unicode=True, default_flow_style=False, Dumper=AppConvert._YamlDumper)

    @staticmethod
    def asYaml(buffer: str):
        """将 YAML 字符串转换为 Python 对象"""
        return yaml.safe_load(buffer)

    @staticmethod
    def toJson(buffer) -> str:
        """将任意 Python 对象转换为 JSON 字符串"""
        return json.dumps(buffer, default=AppConvert.convert_to_serializable, ensure_ascii=False, indent=2)

    @staticmethod
    def asJson(buffer: str):
        """将 JSON 字符串转换为 Python 对象"""
        try:
            return json.loads(buffer)
        except json.JSONDecodeError as e:
            print(f"JSONDecodeError: {e}")
            try:
                return json.loads(buffer, object_hook=AppConvert.convert_from_serializable, ensure_ascii=False,
                                  indent=2)
            except Exception as e1:
                print(f"JSONDecodeError: {e1}")
                return None

    @staticmethod
    def isJson(buffer) -> bool:
        try:
            json.dumps(buffer, default=AppConvert.convert_to_serializable)
            return True
        except Exception as e:
            return False
    @staticmethod
    def asBase64(string: str) -> str:
        return base64.b64encode(string.encode('utf-8')).decode('utf-8')

    @staticmethod
    def asString(string: str) -> str:
        return base64.b64decode(string.encode('utf-8')).decode('utf-8')

    @staticmethod
    def asBytes(string: str) -> bytes:
        return base64.b64decode(string.encode('utf-8'))

    @staticmethod
    def base64ToBytes(string: str) -> bytes:
        return base64.b64decode(string.encode('utf-8'))

    @staticmethod
    def isBase64(string: str) -> bool:
        try:
            base64.b64decode(string.encode('utf-8'))
            return True
        except:
            return False
    @staticmethod
    def isList(buffer: str) -> bool:
        try:
            _buffer = json.loads(buffer)
            return isinstance(_buffer, list)
        except:
            return False
    @staticmethod
    def toList(buffer: str) -> list:
        if not isinstance(buffer, str) or AppConvert.isEmpty(buffer):
            return []
        try:
            _buffer = json.loads(buffer)
            return [AppConvert.convert_from_serializable(item) for item in _buffer]
        except:
            return []
        
    @staticmethod
    def isDict(buffer: str) -> bool:
        try:
            _buffer = json.loads(buffer)
            return isinstance(_buffer, dict)
        except:
            return False
        
    @staticmethod
    def toDict(buffer: str) -> dict:
        if not isinstance(buffer, str) or AppConvert.isEmpty(buffer):
            return {}
        try:
            _buffer = json.loads(buffer)
            return {key: AppConvert.convert_from_serializable(value) for key, value in _buffer.items()}
        except:
            return {}

    @staticmethod
    def isChinese(string: str) -> bool:
        for ch in string:
            if '\u4e00' <= ch <= '\u9fff':
                return True
        return False

    @staticmethod
    def isEnglish(string: str) -> bool:
        for ch in string:
            if 'a' <= ch <= 'z' or 'A' <= ch <= 'Z':
                return True
        return False

    @staticmethod
    def isHex(string: str) -> bool:
        try:
            int(string, 16)
            return True
        except ValueError:
            return False

    @staticmethod
    def asHex(string: str) -> str:
        try:
            return hex(int(string))
        except ValueError:
            return None

    @staticmethod
    def isBool(buffer: str) -> bool:
        try:
            return buffer in (True, 1, 'true', '1', 't', 'y', 'yes', False, 0, 'false', '0', 'f', 'n', 'no')
        except:
            return False
    @staticmethod
    def toBool(buffer: str) -> bool:
        if isinstance(buffer, bool):
            return buffer
        if isinstance(buffer, int):
            return buffer >= 1
        if not isinstance(buffer, str) or AppConvert.isEmpty(buffer):
            return False
        try:
            return buffer in (True, 1, 'true', '1', 't', 'y', 'yes', 'True')
        except:
            return False
        
    @staticmethod
    def isInt(buffer: str) -> bool:
        try:
            return isinstance(int(buffer), int)
        except:
            return False
        
    @staticmethod
    def toInt(buffer: str) -> int:
        try:
            return int(buffer)
        except:
            return 0

    @staticmethod
    def isFloat(buffer: str) -> bool:
        try:
            return isinstance(float(buffer), float)
        except:
            return False
        
    @staticmethod
    def toFloat(buffer: str) -> float:
        try:
            return round(float(buffer), 4)
        except:
            return 0.0
        
        
    @staticmethod
    def isStr(buffer: str) -> bool:
        return isinstance(buffer, str)
    

    @staticmethod
    def isTime(buffer: str) -> bool:
        try:
            return isinstance(datetime.datetime.strptime(buffer, '%H:%M:%S'), datetime.datetime)
        except:
            return False
    
    @staticmethod
    def TimeToString(buffer: datetime.time) -> str:
        if not isinstance(buffer, datetime.time):
            return datetime.time.now().strftime('%H:%M:%S')
        return buffer.strftime('%H:%M:%S')
    
    @staticmethod
    def StringToTime(buffer: str) -> datetime.time:
        if not isinstance(buffer, str) or AppConvert.isEmpty(buffer):
            return datetime.time.now()
        try:
            return datetime.datetime.strptime(buffer, '%H:%M:%S').time()
        except:
            return datetime.time.now()
    
    @staticmethod
    def isDate(buffer: str) -> bool:
        if not isinstance(buffer, str) or AppConvert.isEmpty(buffer):
            return False
        try:
            return isinstance(datetime.datetime.strptime(buffer, '%Y-%m-%d'), datetime.datetime)
        except:
            return False
        
    @staticmethod
    def DateToString(buffer: datetime.date) -> str:
        if not isinstance(buffer, datetime.date):
            return datetime.date.today().strftime('%Y-%m-%d')
        return buffer.strftime('%Y-%m-%d')
    
    @staticmethod   
    def StringToDate(buffer: str) -> datetime.date:
        if not isinstance(buffer, str) or AppConvert.isEmpty(buffer):
            return datetime.date.today()
        try:
            return datetime.datetime.strptime(buffer, '%Y-%m-%d').date()
        except:
            return datetime.date.today()    
        
    
    @staticmethod
    def isDateTime(buffer: str) -> bool:
        try:
            return datetime.datetime.strptime(buffer, '%Y-%m-%d %H:%M:%S')
        except:
            return False
    @staticmethod
    def DateTimeToString(buffer: datetime.datetime) -> str:
        if not isinstance(buffer, datetime.datetime):
            return datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        return buffer.strftime('%Y-%m-%d %H:%M:%S')

    @staticmethod
    def StringToDateTime(buffer: str) -> datetime.datetime: 
        if not isinstance(buffer, str) or AppConvert.isEmpty(buffer):
            return datetime.datetime.now()
        try:
            return datetime.datetime.strptime(buffer, '%Y-%m-%d %H:%M:%S')
        except:
            return datetime.datetime.now()
        
        
    @staticmethod
    def isQDateTime(buffer: str) -> bool:
        try:
            return isinstance(Qt.QDateTime.fromString(buffer, 'yyyy-MM-dd HH:mm:ss'), Qt.QDateTime)
        except:
            return False    
    
    @staticmethod
    def QDateTimeToString(buffer: Qt.QDateTime) -> str:
        if not isinstance(buffer, Qt.QDateTime):
            return Qt.QDateTime.currentDateTime().toString('yyyy-MM-dd HH:mm:ss')
        return buffer.toString('yyyy-MM-dd HH:mm:ss')

    @staticmethod
    def QDateTimeToPath(buffer: Qt.QDateTime, split: str = '-') -> str:
        format_string: str = 'yyyy{0}MM{0}dd{0}HH{0}mm{0}ss'.format(split if isinstance(split, str) else '-')
        if not isinstance(buffer, Qt.QDateTime):
            return Qt.QDateTime.currentDateTime().toString(format_string)
        return buffer.toString(format_string)

    @staticmethod
    def QDateTimeMsecToPath(buffer: Qt.QDateTime, split: str = '-') -> str:
        format_string: str = 'yyyy{0}MM{0}dd{0}HH{0}mm{0}ss{0}zzz'.format(split if isinstance(split, str) else '-')
        if isinstance(buffer, Qt.QDateTime):
            return buffer.toString(format_string)
        elif isinstance(buffer, datetime.datetime):
            return buffer.strftime('%Y{0}%m{0}%d{0}%H{0}%M{0}%S').format(split if isinstance(split, str) else '-')
        else:
            return Qt.QDateTime.currentDateTime().toString(format_string)

    @staticmethod
    def QDateToPath(buffer: Qt.QDate, split_no: str = '-') -> str:
        format_str: str = f'yyyy{split_no}MM{split_no}dd'
        if not isinstance(buffer, Qt.QDate):
            return Qt.QDate.currentDate().toString(format_str)
        return buffer.toString(format_str)

    @staticmethod
    def StringToQDateTime(buffer: str) -> Qt.QDateTime:
        if not isinstance(buffer, str) or AppConvert.isEmpty(buffer):
            return Qt.QDateTime()
        try:
            return Qt.QDateTime.fromString(buffer, 'yyyy-MM-dd HH:mm:ss')
        except:
            return Qt.QDateTime()
        
    @staticmethod
    def isQDate(buffer: str) -> bool:
        try:
            return isinstance(Qt.QDate.fromString(buffer, 'yyyy-MM-dd'), Qt.QDate)
        except:
            return False
    
    @staticmethod
    def QDateToString(buffer: Qt.QDate) -> str:
        if not isinstance(buffer, Qt.QDate):
            return Qt.QDate.currentDate().toString('yyyy-MM-dd')
        return buffer.toString('yyyy-MM-dd')
    
    @staticmethod
    def StringToQDate(buffer: str) -> Qt.QDate:
        if not isinstance(buffer, str) or AppConvert.isEmpty(buffer):
            return Qt.QDate()
        try:
            return Qt.QDate.fromString(buffer, 'yyyy-MM-dd')
        except:
            return Qt.QDate()   
        
    @staticmethod
    def isQTime(buffer: str) -> bool:
        try:
            return isinstance(Qt.QTime.fromString(buffer, 'HH:mm:ss'), Qt.QTime)
        except:
            return False
        
    @staticmethod
    def QTimeToString(buffer: Qt.QTime) -> str:
        if not isinstance(buffer, Qt.QTime):
            return Qt.QTime.currentTime().toString('HH:mm:ss')
        return buffer.toString('HH:mm:ss')
    
    @staticmethod
    def StringToQTime(buffer: str) -> Qt.QTime:
        if not isinstance(buffer, str) or AppConvert.isEmpty(buffer):
            return Qt.QTime()
        try:
            return Qt.QTime.fromString(buffer, 'HH:mm:ss')
        except:
            return Qt.QTime()
    
    
    @staticmethod
    def isQColor(buffer: str) -> bool:
        try:
            return isinstance(Qt.QColor(buffer), Qt.QColor)
        except:
            return False

    @staticmethod
    def QColorToString(buffer: Qt.QColor) -> str:
        if not isinstance(buffer, Qt.QColor):
            return ''
        return buffer.name()

    @staticmethod
    def StringToQColor(buffer: str) -> Qt.QColor:
        if not isinstance(buffer, str) or AppConvert.isEmpty(buffer):
            return Qt.QColor()
        return Qt.QColor(buffer)

    @staticmethod
    def isNull(buffer: str) -> bool:
        return buffer in (None, 'null', 'Null', 'NULL')
    
    
    
    @staticmethod
    def isEmpty(buffer: str) -> bool:
        return not isinstance(buffer, str) or buffer == '' or buffer.isspace() or len(buffer) == 0 or len(buffer.strip()) == 0
            
            
            
    @staticmethod
    def ObjectConvert(buffer: object, dst_type: type) -> any:
        if buffer is None or dst_type is None or AppConvert.isNull(buffer):
            return None
        _buffer: dst_type = None
        try:
            if dst_type is str:
                _buffer =  f"{buffer}"
            elif dst_type is int:
                _buffer =   AppConvert.toInt(buffer)
            elif dst_type is float:
                _buffer =   AppConvert.toFloat(buffer)
            elif dst_type is bool:
                _buffer =   AppConvert.toBool(buffer)
            elif dst_type is list:
                _buffer =   AppConvert.toList(buffer)
            elif dst_type is dict:
                _buffer =   AppConvert.toDict(buffer)
            elif dst_type is datetime.datetime:
                _buffer =   AppConvert.StringToDateTime(buffer)
            elif dst_type is datetime.date:
                _buffer =   AppConvert.StringToDate(buffer)
            elif dst_type is datetime.time:
                _buffer =   AppConvert.StringToTime(buffer)
            elif dst_type is Qt.QDateTime:
                _buffer =   AppConvert.StringToQDateTime(buffer)
            elif dst_type is Qt.QDate:
                _buffer =   AppConvert.StringToQDate(buffer)
            elif dst_type is Qt.QTime:
                _buffer =   AppConvert.StringToQTime(buffer)
            elif dst_type is Qt.QColor:
                _buffer =   AppConvert.StringToQColor(buffer)
            else:
                _buffer =   json.loads(buffer)
        except:
            _buffer =  buffer
        return _buffer
            
            
    @staticmethod
    def serializable(buffer):
        if isinstance(buffer, datetime.datetime):
            return AppConvert.DateTimeToString(buffer)
        elif isinstance(buffer, datetime.date):
            return AppConvert.DateToString(buffer)
        elif isinstance(buffer, datetime.time):
            return AppConvert.TimeToString(buffer)
        elif isinstance(buffer, Qt.QDateTime):
            return AppConvert.QDateTimeToString(buffer)
        elif isinstance(buffer, Qt.QDate):
            return AppConvert.QDateToString(buffer)
        elif isinstance(buffer, Qt.QTime):
            return AppConvert.QTimeToString(buffer)
        elif isinstance(buffer, Qt.QColor):
            return AppConvert.QColorToString(buffer)
        elif isinstance(buffer, list):
            return AppConvert.toJson([AppConvert.convert_to_serializable(item) for item in buffer])
        elif isinstance(buffer, dict):
            return AppConvert.toJson({key: AppConvert.convert_to_serializable(value) for key, value in buffer.items()})
        else:
            return AppConvert.toJson(buffer)

    @staticmethod
    def isSerializable(buffer) -> bool:
        try:
            AppConvert.serializable(buffer)
            return True
        except Exception as e:
            return False

    @staticmethod
    def serialize(obj):
        if isinstance(obj, datetime.datetime):
            return AppConvert.DateTimeToString(obj)
        elif isinstance(obj, datetime.date):
            return AppConvert.DateToString(obj)
        elif isinstance(obj, datetime.time):
            return AppConvert.TimeToString(obj)
        elif isinstance(obj, Qt.QDateTime):
            return AppConvert.QDateTimeToString(obj)
        elif isinstance(obj, Qt.QDate):
            return AppConvert.QDateToString(obj)
        elif isinstance(obj, Qt.QTime):
            return AppConvert.QTimeToString(obj)
        elif isinstance(obj, Qt.QColor):
            return AppConvert.QColorToString(obj)
        elif isinstance(obj, list):
            return [AppConvert.convert_to_serializable(item) for item in obj]
        elif isinstance(obj, dict):
            return {key: AppConvert.convert_to_serializable(value) for key, value in obj.items()}
        else:
            return obj

    @staticmethod
    def convert_to_serializable(obj):
        if isinstance(obj, datetime.datetime):
            return AppConvert.DateTimeToString(obj)
        elif isinstance(obj, datetime.date):
            return AppConvert.DateToString(obj)
        elif isinstance(obj, datetime.time):
            return AppConvert.TimeToString(obj)
        elif isinstance(obj, Qt.QDateTime):
            return AppConvert.QDateTimeToString(obj)
        elif isinstance(obj, Qt.QDate):
            return AppConvert.QDateToString(obj)
        elif isinstance(obj, Qt.QTime):
            return AppConvert.QTimeToString(obj)
        elif isinstance(obj, Qt.QColor):
            return AppConvert.QColorToString(obj)
        elif isinstance(obj, list): 
            return [AppConvert.convert_to_serializable(item) for item in obj]
        elif isinstance(obj, dict):
            return {key: AppConvert.convert_to_serializable(value) for key, value in obj.items()}
        elif isinstance(obj, float):
            return '%.2f' % obj
        else:
            return obj
        
    @staticmethod
    def convert_from_serializable(dct):
        if isinstance(dct, str):
            if AppConvert.isDateTime(dct):
                return AppConvert.StringToDateTime(dct)
            elif AppConvert.isDate(dct):
                return AppConvert.StringToDate(dct)
            elif AppConvert.isTime(dct):
                return AppConvert.StringToTime(dct)
            elif AppConvert.isQDateTime(dct):
                return AppConvert.StringToQDateTime(dct)
            elif AppConvert.isQDate(dct):
                return AppConvert.StringToQDate(dct)
            elif AppConvert.isQTime(dct):
                return AppConvert.StringToQTime(dct)
            elif AppConvert.isQColor(dct):
                return AppConvert.StringToQColor(dct)
            elif AppConvert.isList(dct):
                return AppConvert.toList(dct)
            elif AppConvert.isDict(dct):
                return AppConvert.toDict(dct)
            elif AppConvert.isFloat(dct):
                return AppConvert.toFloat(dct)
            else:
                return dct
        elif isinstance(dct, dict):
            return {key: AppConvert.convert_from_serializable(value) for key, value in dct.items()}
        elif isinstance(dct, list):
            return [AppConvert.convert_from_serializable(item) for item in dct]
        elif isinstance(dct, tuple):
            return tuple([AppConvert.convert_from_serializable(item) for item in dct])
        elif isinstance(dct, set):
            return tuple([AppConvert.convert_from_serializable(item) for item in dct])
        else:
            return dct
            

