# GESP等级：三级 | GESP Python 三级考点

"""
================================================================================
 练习2 ★★ — 配置切换器（dict + set 实践）
================================================================================

  练习目标：
    为绘图程序实现「配置方案」的保存、切换、对比功能。

  背景：
    用户希望保存多组画笔配置方案（profile），
    并在不同方案之间快速切换，还能对比差异。
================================================================================
"""
from pprint import pprint

print("=" * 60)
print("练习2 ★★ — 配置切换器")
print("=" * 60)

# ========== 基础画笔配置 ==========
BASE_PEN = {
    "color": "black",
    "width": 2,
    "opacity": 1.0,
    "shape": "round",
}

# ========== 多个配置方案：dict 的嵌套使用 ==========
profiles = {
    "default": {
        "pen1": dict(BASE_PEN),
        "pen2": dict(BASE_PEN),
    },
    "sketch": {
        "pen1": {"color": "gray",  "width": 1, "opacity": 0.8, "shape": "round"},
        "pen2": {"color": "black", "width": 2, "opacity": 1.0, "shape": "round"},
    },
    "marker": {
        "pen1": {"color": "red",   "width": 5, "opacity": 0.7, "shape": "square"},
        "pen2": {"color": "blue",  "width": 8, "opacity": 0.6, "shape": "square"},
    },
    "watercolor": {
        "pen1": {"color": "green", "width": 6, "opacity": 0.3, "shape": "round"},
        "pen2": {"color": "cyan",  "width": 4, "opacity": 0.2, "shape": "diamond"},
    },
}

print(f"\n已定义配置方案：{list(profiles.keys())}")

# ========== 1. 配置切换 ==========
current_profile = "default"
print(f"\n1. 当前方案：{current_profile}")
pprint(profiles[current_profile])


def switch_profile(name: str) -> bool:
    """切换到指定方案，成功返回 True"""
    global current_profile
    if name in profiles:
        current_profile = name
        print(f"   已切换到方案：{name}")
        return True
    print(f"   错误：方案 '{name}' 不存在")
    return False


switch_profile("marker")
print(f"   当前方案画笔数：{len(profiles[current_profile])}")


# ========== 2. 配置差异对比（集合运算）==========
def diff_profiles(name_a: str, name_b: str) -> dict:
    """对比两个方案的差异"""
    pa = profiles.get(name_a, {})
    pb = profiles.get(name_b, {})

    pens_a = set(pa.keys())
    pens_b = set(pb.keys())

    return {
        "only_in_a": pens_a - pens_b,
        "only_in_b": pens_b - pens_a,
        "common": pens_a & pens_b,
        "union": pens_a | pens_b,
    }


print("\n2. 方案对比（sketch vs marker）：")
diff = diff_profiles("sketch", "marker")
print(f"   仅在 sketch 中的画笔：{diff['only_in_a']}")
print(f"   仅在 marker 中的画笔：{diff['only_in_b']}")
print(f"   共同画笔：{diff['common']}")

# 深入对比共同画笔的具体差异
print("\n   共同画笔的配置差异：")
for pen_name in sorted(diff["common"]):
    cfg_a = profiles["sketch"][pen_name]
    cfg_b = profiles["marker"][pen_name]
    changes = {k: (cfg_a[k], cfg_b[k]) for k in cfg_a if cfg_a[k] != cfg_b[k]}
    if changes:
        print(f"     {pen_name}:")
        for k, (va, vb) in changes.items():
            print(f"       {k}: {va} → {vb}")


# ========== 3. 导出活跃画笔的配置快照 ==========
print("\n3. 快照导出（当前方案的所有画笔配置）：")


def export_snapshot(profile_name: str = None) -> dict:
    """导出配置快照"""
    if profile_name is None:
        profile_name = current_profile
    cfg = profiles.get(profile_name)
    if cfg is None:
        return {}
    # 深拷贝快照
    return {name: dict(pen_cfg) for name, pen_cfg in cfg.items()}


snapshot = export_snapshot()
pprint(snapshot)


# ========== 4. 合并配置（dict.update + 集合控制）==========
print("\n4. 配置合并（将 marker 的 pen1 合并到 default）：")


def merge_pen_config(base: dict, override: dict) -> dict:
    """合并两个配置，override 覆盖 base"""
    result = dict(base)
    result.update(override)
    return result


merged = merge_pen_config(
    profiles["default"]["pen1"],
    profiles["marker"]["pen1"],
)
print(f"   基础：{profiles['default']['pen1']}")
print(f"   覆盖：{profiles['marker']['pen1']}")
print(f"   合并：{merged}")


# ========== 5. 验证所有配置的完整性 ==========
print("\n5. 配置完整性校验：")
REQUIRED_KEYS = {"color", "width", "opacity", "shape"}

for pname, cfg in profiles.items():
    for pen_name, pen_cfg in cfg.items():
        missing = REQUIRED_KEYS - set(pen_cfg.keys())
        extra = set(pen_cfg.keys()) - REQUIRED_KEYS
        status = "OK"
        if missing:
            status = f"缺字段：{missing}"
        elif extra:
            status = f"多余字段：{extra}"
        print(f"   {pname}/{pen_name}: {status}")


# ========== 总结 ==========
print()
print(">>> 练习2 核心技能 <<<")
print("✓ 嵌套 dict 管理多方案配置")
print("✓ set 运算（-、&、|）快速对比方案差异")
print("✓ dict 快照保证配置可回滚")
print("✓ 集合推导式做配置完整性校验")
