#!/usr/bin/env python3
"""
DXF编码修复脚本 - 检测DXF文件实际编码，转码为$DWGCODEPAGE声明一致的编码。
用法: dxfcpgfix <DXF文件路径>
依赖: python3-chardet
"""

import sys
import os
import subprocess

try:
    import chardet
except ImportError:
    subprocess.run([
        "notify-send",
        "--app-name=DXF编码修复",
        "请安装python3-chardet",
        "",
        "--icon=dialog-error"
    ])
    sys.exit(1)


# DWGCODEPAGE 值 → Python 编码名 的映射表
DWGCODEPAGE_TO_ENCODING = {
    "ANSI_874":       "cp874",
    "ANSI_932":       "cp932",
    "ANSI_936":       "gbk",
    "ANSI_949":       "cp949",
    "ANSI_950":       "cp950",
    "ANSI_1250":      "cp1250",
    "ANSI_1251":      "cp1251",
    "ANSI_1252":      "cp1252",
    "ANSI_1253":      "cp1253",
    "ANSI_1254":      "cp1254",
    "ANSI_1255":      "cp1255",
    "ANSI_1256":      "cp1256",
    "ANSI_1257":      "cp1257",
    "ANSI_1258":      "cp1258",
    "UTF-8":          "utf-8",
    "UTF8":           "utf-8",
    "GB2312":         "gb2312",
    "BIG5":           "big5",
    "ISO8859-1":      "iso-8859-1",
    "ISO8859-2":      "iso-8859-2",
    "ISO8859-5":      "iso-8859-5",
    "ISO8859-7":      "iso-8859-7",
    "ISO8859-8":      "iso-8859-8",
    "ISO8859-9":      "iso-8859-9",
}


def notify(title, message, icon="emblem-checked"):
    subprocess.run([
        "notify-send",
        "--app-name=DXF编码修复",
        title,
        message,
        f"--icon={icon}"
    ])


def detect_encoding(filepath):
    with open(filepath, "rb") as f:
        raw = f.read()
    return chardet.detect(raw)


def codepage_to_encoding(codepage):
    if not codepage:
        return None
    return DWGCODEPAGE_TO_ENCODING.get(codepage.strip())


def extract_codepage(lines):
    """从DXF行列表中提取$DWGCODEPAGE的值"""
    for i, line in enumerate(lines):
        if line.strip() == "$DWGCODEPAGE":
            skipped_group_code = False
            for j in range(i + 1, len(lines)):
                if lines[j].strip():
                    if not skipped_group_code:
                        skipped_group_code = True
                        continue
                    return lines[j].strip()
    return None


def main():
    try:
        if len(sys.argv) < 2:
            notify("编码集修复失败", "", "dialog-error")
            sys.exit(1)

        filepath = sys.argv[1]
        if filepath.startswith("file://"):
            filepath = filepath[7:]

        if not os.path.isfile(filepath):
            notify("编码集修复失败", "", "dialog-error")
            sys.exit(1)

        # 1. 检测文件实际编码
        detect_result = detect_encoding(filepath)
        actual_encoding = detect_result.get("encoding")
        if not actual_encoding:
            notify("编码集修复失败", "", "dialog-error")
            sys.exit(1)

        # 2. 用检测到的编码读取文件
        with open(filepath, "rb") as f:
            raw = f.read()
        content = raw.decode(actual_encoding)
        lines = content.splitlines(keepends=True)

        # 3. 提取 DWGCODEPAGE 声明的目标编码
        current_codepage = extract_codepage(lines)
        if current_codepage is None:
            notify("编码集修复失败", "", "dialog-error")
            sys.exit(1)

        target_encoding = codepage_to_encoding(current_codepage)
        if target_encoding is None:
            notify("编码集修复失败", "", "dialog-error")
            sys.exit(1)

        # 4. 编码一致则无需转换
        def _norm(enc):
            return enc.lower().replace("-", "").replace("_", "")

        if _norm(actual_encoding) == _norm(target_encoding):
            notify("DXF编码正常，无需修复", "", "emblem-information")
            sys.exit(0)

        # 5. 转码
        new_raw = content.encode(target_encoding)

        # 6. 原地覆写
        with open(filepath, "wb") as f:
            f.write(new_raw)

        notify("编码集修复：", f"{_norm(actual_encoding)}→{current_codepage}", "emblem-checked")

    except Exception:
        notify("编码集修复失败", "", "dialog-error")
        sys.exit(1)


if __name__ == "__main__":
    main()
