#!/usr/bin/env python3
"""Converteert ongeldige slide://N externe hyperlinks naar geldige PowerPoint slide-jumps (ElementTree, geen string-chirurgie)."""
import zipfile, re, shutil, sys
from xml.etree import ElementTree as ET

RNS = 'http://schemas.openxmlformats.org/package/2006/relationships'
ET.register_namespace('', RNS)
SLIDE_TYPE = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide'

def fix(path):
    src = zipfile.ZipFile(path)
    names = src.namelist()
    jump_map = {}   # 'slideK.xml' -> {rId: 'slideN.xml'}
    new_parts = {}  # partname -> bytes
    for n in names:
        m = re.match(r'ppt/slides/_rels/(slide\d+)\.xml\.rels$', n)
        if not m:
            continue
        root = ET.fromstring(src.read(n))
        rels = {}
        for rel in root.findall(f'{{{RNS}}}Relationship'):
            tgt = rel.get('Target', '')
            if tgt.startswith('slide://'):
                num = tgt.split('//', 1)[1]
                rel.set('Type', SLIDE_TYPE)
                rel.set('Target', f'slide{num}.xml')
                if rel.get('TargetMode'):
                    del rel.attrib['TargetMode']
                rels[rel.get('Id')] = f'slide{num}.xml'
        if rels:
            jump_map[m.group(1) + '.xml'] = rels
            new_parts[n] = ET.tostring(root, encoding='UTF-8', xml_declaration=True)
    # slide-XML: action-attribuut toevoegen op bijbehorende hlinkClick
    for slide_part, rels in jump_map.items():
        n = f'ppt/slides/{slide_part}'
        txt = src.read(n).decode('utf-8')
        for rid in rels:
            txt = re.sub(rf'(<a:hlinkClick\b[^>]*?r:id="{rid}")((?:(?!action=)[^>])*?)(/?>)',
                         lambda mo: mo.group(1) + mo.group(2) + ' action="ppaction://hlinksldjump"' + mo.group(3),
                         txt)
        new_parts[n] = txt.encode('utf-8')
    # nette rebuild
    out = path + '.tmp'
    with zipfile.ZipFile(out, 'w', zipfile.ZIP_DEFLATED) as dst:
        for n in names:
            dst.writestr(n, new_parts.get(n, src.read(n)))
    src.close()
    shutil.move(out, path)
    print(f"OK {path}: {sum(len(v) for v in jump_map.values())} jumps gefixed")

for p in sys.argv[1:]:
    fix(p)
