import sys,re,json,uuid,shutil
from pathlib import Path
ROOT=Path(__file__).resolve().parent;BASE=ROOT.parent
sys.path.insert(0,str(BASE/'parity_metadata_closure_A22'))
from prepare_candidates import forms,run,sha
from align_and_verify import footprint_rows,netlist
SRC=BASE/'esd_topology_A27/vacuum_esd_candidate';DST=ROOT/'vacuum_gate_candidate';DST.mkdir(exist_ok=True)
OLD='vacuum_control_evt_a3_esd_railfree';NEW='vacuum_control_evt_a4_gate_clamp'
def uid(k):return str(uuid.uuid5(uuid.NAMESPACE_URL,'pcbapartner:A28:'+k))
for p in SRC.iterdir():
 if p.name.endswith('.pretty'):shutil.copytree(p,DST/p.name,dirs_exist_ok=True)
 elif p.name in ['Project.kicad_sym','sym-lib-table','fp-lib-table']:shutil.copyfile(p,DST/p.name)
shutil.copyfile(SRC/(OLD+'.kicad_pro'),DST/(NEW+'.kicad_pro'))
s=(SRC/(OLD+'.kicad_sch')).read_text().replace('(project "'+OLD+'"','(project "'+NEW+'"')
res=None
for st,en,b in reversed(list(forms(s,'symbol'))):
 if '(property "Reference" "R16"' in b:res=b
 if '(property "Reference" "Q4"' in b:s=s[:st]+b.replace('"2N7002"','"AO3400A"')+s[en:]
 elif '(property "Reference" "R14"' in b:s=s[:st]+b.replace('"100R"','"680R"')+s[en:]
assert res
for st,en,b in reversed(list(forms(s,'label'))):
 if '(at 510.54 255.27 0)' in b:
  assert 'FAN_FET_GATE' in b;s=s[:st]+b.replace('FAN_FET_GATE','FAN_GATE_SINK')+s[en:]
new=res.replace('"R16"','"R17"').replace('"49.9k"','"3.3k"')
# Translate all instance and property coordinates, keeping pin local coordinates untouched.
new=re.sub(r'\(at ([\d.-]+) ([\d.-]+) ([\d.-]+)\)',lambda m:'(at %.4f %.4f %s)'%(float(m[1])+88.9,float(m[2])+49.53,m[3]),new)
new=re.sub(r'\(uuid "([^\"]+)"\)',lambda m:'(uuid "'+uid('R17-'+m[1])+'")',new)
added=[new]
for y,n in [(294.64,'FAN_FET_GATE'),(304.8,'FAN_GATE_SINK')]:
 added += ['(wire (pts (xy 698.5 %s) (xy 706.12 %s)) (stroke (width 0) (type default)) (uuid "%s"))'%(y,y,uid('wire'+n)), '(label "%s" (at 706.12 %s 0) (effects (font (size 1.27 1.27)) (justify left bottom)) (uuid "%s"))'%(n,y,uid('label'+n))]
s=s.rstrip()[:-1]+'\n'+'\n'.join(added)+'\n)\n';(DST/(NEW+'.kicad_sch')).write_text(s)
s=(SRC/(OLD+'.kicad_pcb')).read_text();r17=None
for st,en,b,r,_ in reversed(list(footprint_rows(s))):
 if r=='R14':
  r17=b;s=s[:st]+b.replace('"100R"','"680R"')+s[en:]
 elif r=='Q4':
  b=b.replace('"2N7002"','"AO3400A"')
  for ps,pe,p in reversed(list(forms(b,'pad'))):
   if p.startswith('(pad "3"'):b=b[:ps]+p.replace('/FAN_FET_GATE','/FAN_GATE_SINK')+b[pe:]
  s=s[:st]+b+s[en:]
assert r17
r17=r17.replace('"R14"','"R17"').replace('"100R"','"3.3k"').replace('(at 64 49)','(at 56 53.5)')
r17=re.sub(r'\(uuid "([^\"]+)"\)',lambda m:'(uuid "'+uid('pcbR17-'+m[1])+'")',r17)
# Path UUID should correspond to the new schematic resistor.
r17=re.sub(r'\(path "([^\"]+)"\)',lambda m:'(path "'+m[1].rsplit('/',1)[0]+'/'+re.search(r'\(uuid "([^\"]+)"',new)[1]+'")',r17)
for st,en,p in reversed(list(forms(r17,'pad'))):
 n='/FAN_FET_GATE' if p.startswith('(pad "1"') else '/FAN_GATE_SINK'
 p=re.sub(r'\(net "[^\"]+"\)','(net "'+n+'")',p);r17=r17[:st]+p+r17[en:]
for st,en,b in reversed(list(forms(s,'segment'))):
 if '6726a98b-3c84-4161-b658-965b81d683a0' in b:s=s[:st]+s[en:]
 elif 'a1cf1c30-6938-4b6b-9ae9-48f8bff03322' in b:s=s[:st]+b.replace('/FAN_FET_GATE','/FAN_GATE_SINK')+s[en:]
added=[r17]
for a,b,n in [((55.0855,54.4199),(55.175,53.5),'/FAN_FET_GATE'),((56.825,53.5),(56.9375,52.5679),'/FAN_GATE_SINK')]:
 added.append('(segment (start %s %s) (end %s %s) (width 0.2) (layer "F.Cu") (net "%s") (uuid "%s"))'%(*a,*b,n,uid(str(a))))
s=s.rstrip()[:-1]+'\n'+'\n'.join(added)+'\n)\n';pcb=DST/(NEW+'.kicad_pcb');pcb.write_text(s)
for args,name in [(['sch','export','netlist','--format','kicadxml','--output',str(DST/'netlist.xml'),str(DST/(NEW+'.kicad_sch'))],'netlist.log'),(['sch','erc','--format','json','--output',str(DST/'erc.json'),str(DST/(NEW+'.kicad_sch'))],'erc.log'),(['pcb','drc','--format','json','--schematic-parity','--output',str(DST/'drc.json'),str(pcb)],'drc.log')]:assert run(args,DST/name)==0
_,oldpins=netlist(SRC/'netlist.xml');_,pins=netlist(DST/'netlist.xml')
assert {k:v for k,v in oldpins.items() if k!=('Q4','3')}=={k:v for k,v in pins.items() if k!=('Q4','3') and k[0]!='R17'}
assert pins[('Q4','3')]==pins[('R17','2')]=='/FAN_GATE_SINK';assert pins[('R17','1')]=='/FAN_FET_GATE'
d=json.loads((DST/'drc.json').read_text());e=json.loads((DST/'erc.json').read_text())
print(json.dumps({'drc':len(d['violations']),'unconnected':len(d['unconnected_items']),'parity':d['schematic_parity'],'erc':sum(len(x['violations']) for x in e['sheets'])},indent=2))
