import re
s = open('v22_src.html').read()
def R(a, b, cnt=1):
    global s
    n = s.count(a); assert n == cnt, (n, a[:90]); s = s.replace(a, b)
def RS(start, end, new):
    global s
    i = s.index(start); j = s.index(end, i); s = s[:i] + new + s[j:]
def RL(start, new):
    global s
    i = s.index(start); j = s.index('\n', i); s = s[:i] + new + s[j:]

# 头部
R('<title>NobadyBox v22 活动插头拆解图</title>', '<title>NobadyBox v23 通用机型拆解图</title>')
R('NOBADY BOX · 硬件方案 v22 · 有线活动插头版 · 拆解效果图', 'NOBADY BOX · 硬件方案 v23 · 通用机型版（去掉两侧挡板） · 拆解效果图')
R('<h1>AI 手机仓 v22 有线活动插头版逐级拆解</h1>', '<h1>AI 手机仓 v23 通用机型版逐级拆解</h1>')
R('<span>打印件 <b>3 + 1</b></span><span>拆解 <b>13</b> 级</span>', '<span>打印件 <b>3</b></span><span>拆解 <b>12</b> 级</span>')
R('max="13"', 'max="12"')
R('<span>12</span><span>13</span></div>', '<span>12</span></div>')
R('0 / 13</span>', '0 / 12</span>')
R('、手机框 85 × 175 mm、', '、')
R('合页、风道和 TPU 垫是我按这组参数定的估算值', '合页、风道和后挡是我按这组参数定的估算值', 0) if '合页、风道和 TPU 垫' not in s else R('合页、风道和 TPU 垫是我按这组参数定的估算值', '合页、风道和后挡是我按这组参数定的估算值')

RS('<section>\n  <h3>v22：', '<section>\n  <h3>4 个 3D 打印零件</h3>', '''<section>
  <h3>v23 改了什么：去掉手机两侧的挡板，大部分手机都能放</h3>
  <p class="lead">v22 手机两边有 TPU 条和手机框侧壁，用来把手机夹在正中。但手机宽窄不一样，一套挡板配不了所有机型，这一版全部去掉。手机不用对正中，摄像头每次先拍仓底 2 个定位标记和屏幕四个角，自己找到屏幕在哪。仓底只留一道后挡，手机推到底碰到它就停。打印件从 3 + 1 变成 3 个，不用再按机型选配件。</p>
  <div class="tbl"><table class="cmp">
    <thead><tr><th></th><th>v22 有线活动插头版</th><th>v23 通用机型版</th></tr></thead>
    <tbody>
      <tr><td>手机两侧</td><td>TPU 条 + 手机框侧壁，按机型选</td><td>什么都没有，手机平放在支撑筋上</td></tr>
      <tr><td>手机往里推到哪</td><td>没有明确停的位置</td><td>仓底一道 2 mm 后挡（底仓自带），推到底就停</td></tr>
      <tr><td>屏幕对准</td><td>靠挡板把手机夹在正中</td><td>摄像头自己找屏幕，手机偏左偏右都行</td></tr>
      <tr><td>能放的手机</td><td>一套挡板只配一种宽度</td><td>宽 ≤ 82 mm、长 ≤ 172 mm、厚 ≤ 12 mm（含壳），大部分直板手机都行；折叠屏不行</td></tr>
      <tr><td>打印件</td><td>3 + 1（TPU）</td><td>3 个，全部 PETG</td></tr>
      <tr><td>充电</td><td>有线活动插头</td><td>不变：推到底，再在前口边上插活动插头</td></tr>
    </tbody>
  </table></div>
</section>

''')
R('<h3>4 个 3D 打印零件</h3>', '<h3>3 个 3D 打印零件</h3>')
R('3 个 PETG 打印件，加 1 套按手机大小选的 TPU 垫。', '3 个 PETG 打印件，不用按机型选配件。')
R('安装板平放打；TPU 垫平放打。', '安装板平放打。')
R('        <li>放手机：屏幕朝上、充电口朝外，平着推到底。手机端面停在离外壳前面约 10 mm 的地方，充电口正对前口。</li>',
  '        <li>放手机：屏幕朝上、充电口朝外，平着推到底，碰到仓底后挡就停。两边不用对齐，偏一点没关系。162 mm 长的手机端面离外壳前面约 10 mm；短一点的手机离得远一点（147 mm 长约 25 mm），手指一样够得着。</li>')
R('手机线穿过后端出线口、压在右侧支撑筋外边', '手机线从后挡后面绕过、压在右侧支撑筋外边')
R('，压 4 颗磁铁，放 TPU 条，做一次标定。', '，压 4 颗磁铁，做一次标定。')
R('穿过手机框后端的出线口', '从后挡后面绕过')

# INFO
R("手机框 2.0 mm，支撑筋 4 mm 高", "支撑筋 4 mm 高，后挡 2 mm")
R("带插头座、右侧走线槽、支撑筋、手机框侧壁、后壁线槽", "带插头座、右侧走线槽、支撑筋、后挡、后壁线槽")
R("role:'屏幕朝上，充电口朝外，从前口推到底，再在前口边上插线。屏幕离盒底 16 mm。'}", "role:'屏幕朝上，充电口朝外，从前口推到底碰到后挡，再在前口边上插活动插头。两侧不用对齐。图中是 76 × 162 × 9 mm，屏幕离盒底 16 mm。'}")

# STEPS
R("  {p:['tpu'], t:'取出 TPU 条', d:'两侧条把手机卡在中间，屏幕对准镜头。按手机宽度选 1 套。'},\n", "")
R("拉手机不会碰到线。放手机反过来：推到底，再插线。'}", "拉手机不会碰到线。放手机反过来：推到底碰到后挡，再插线。'}", 0) if "拉手机不会碰到线。放手机反过来：推到底，再插线。" not in s else R("拉手机不会碰到线。放手机反过来：推到底，再插线。", "拉手机不会碰到线。放手机反过来：推到底碰到后挡，再插线。两侧没有挡板，什么手机都一样放。")
R("前口、电源口、插头座、右侧走线槽、支撑筋、", "前口、电源口、插头座、右侧走线槽、支撑筋、后挡、")

# 底仓：去掉手机框，后端换成一道后挡；插头座往外挪，宽手机也不碰
R("  g.add(boxR(39.6,XI,FL,14,73,79.5,m), boxR(46.5,XI,FL,14,79.5,92.4,m));", "  g.add(boxR(41,XI,FL,14,73,79.5,m), boxR(47.4,XI,FL,14,79.5,92.4,m));")
RS("  for(const sd of [-1,1]){                                                   // 手机框", "\n\n", "  g.add(boxR(-32,32,FL,12,-79.5,-77.5,m));   // 后挡：手机推到底碰到这里就停")
R("const PLUG_PARK=new T.Vector3(43.2,8.7,84)", "const PLUG_PARK=new T.Vector3(44.2,8.7,84)")
R("[37.3,7.8,88.4]]", "[38.3,7.8,88.4]]")
R("[[46,14,76],'插头座']", "[[47,14,76],'插头座']")
R("lab(hBody,[46,14,76],", "lab(hBody,[47,14,76],")
s = re.sub(r"\[\[FX\+2,15,60\],'手机框侧壁'\],", "[[32,12,-78.5],'后挡'],", s); assert "'后挡']" in s

# 去掉 TPU
R("const hTPU = holder(asm,0,0,0); hTPU.add(addEdges(buildTPU(mTPU))); reg('tpu',hTPU,[mTPU]);\n", "")
R("[[-300,'盘 1 · PETG HF · 约 11 h'],[0,'盘 2 · PETG HF · 约 4.5 h'],[300,'盘 3 · TPU 95A · 约 0.4 h']]", "[[-150,'盘 1 · PETG HF · 约 11 h'],[150,'盘 2 · PETG HF · 约 4.5 h']]")
R("b.position.set(-300,0,0)", "b.position.set(-150,0,0)")
R("new T.Vector3(-300,120,-40)", "new T.Vector3(-150,120,-40)")
R("s.position.set(-55,H,0)", "s.position.set(95,H,0)")
R("new T.Vector3(-55,20,-40)", "new T.Vector3(95,20,-40)")
R("p.position.set(55,-SPLIT,0)", "p.position.set(205,-SPLIT,0)")
R("new T.Vector3(55,4,40)", "new T.Vector3(205,4,40)")
RL("  const tp=addEdges(buildTPU(mTPU));", "")
R("PID.tpu=lab(hTPU,[-FX,13,-40],'<em>P4</em>TPU 条','printed tpu',()=>true);\n", "")
R("打印件 4 个：P1 底仓、P2 顶盖外壳、P3 摄像头安装板、P4 TPU 条。", "打印件 3 个：P1 底仓、P2 顶盖外壳、P3 摄像头安装板。手机两侧没有挡板，大部分手机都能放。")
R("['body','shell','plate','tpu'].map", "['body','shell','plate'].map")

# 每一级重新编号
RS("mv(hPhone,2,0,0,210);", "/* ---------- 打印摆放", """mv(hPhone,2,0,0,210);
hHinge.forEach((h,i)=> mv(h,4,(i?1:-1)*45,0,0));
mv(lidPivot,5,0,190,40);
mv(hShell,6,0,85,0);
mv(hFan,7,0,45,0);
mv(hPCB,8,0,22,0);
mv(hCable,9,85,0,0);
hMag.forEach(o=> mv(o.h,10,0,o.up?18:22,0));
hIns.forEach(k=> mv(k,11,...k.userData.dir));

""")
for a,b in [("'合页销 M3×30','',after(5)","'合页销 M3×30','',after(4)"),("'3007 风扇','',after(8)","'3007 风扇','',after(7)"),("'PCB + 摄像头','',after(9)","'PCB + 摄像头','',after(8)"),
            ("'电源分线板 + 手机充电线','',after(10)","'电源分线板 + 手机充电线','',after(9)"),("'钕磁铁 Ø6×3','',after(11)","'钕磁铁 Ø6×3','',after(10)"),("'热熔螺母 M2','',after(12)","'热熔螺母 M2','',after(11)"),
            ("k=>k>=1&&k<10","k=>k>=1&&k<9"),("forEach(([p,t])=>lab(hBody,p,t,'feat',after(13)))","forEach(([p,t])=>lab(hBody,p,t,'feat',after(12)))"),
            ("tOf(4,v) * (1-tOf(6,v))","tOf(3,v) * (1-tOf(5,v))"),("const tc=tOf(10,v)","const tc=tOf(9,v)"),("const tu=tOf(5,v);","const tu=tOf(4,v);"),
            ("const s0=c(x), s=c(x-3), s2=c((x-5)/3);","const s0=c(x), s=c(x-2), s2=c((x-4)/3);")]:
    R(a,b)
# 清单
R("['P1 底仓','打印','1','PETG HF 黑','13'],['P2 顶盖外壳','打印','1','PETG HF 黑','7'],['P3 摄像头安装板','打印','1','PETG HF 黑','6'],['P4 TPU 条','打印','按手机选 1 套','TPU 95A','3'],",
  "['P1 底仓','打印','1','PETG HF 黑','12'],['P2 顶盖外壳','打印','1','PETG HF 黑','6'],['P3 摄像头安装板','打印','1','PETG HF 黑','5'],")
R("电源从 XH 3P 进','9'],['3007 风扇','采购','1','30 × 30 × 7 mm，5 V 滚珠','8']", "电源从 XH 3P 进','8'],['3007 风扇','采购','1','30 × 30 × 7 mm，5 V 滚珠','7']")
s = s.replace("XH 3P','10'],", "XH 3P','9'],").replace("另一头接分线板','10'],", "另一头接分线板','9'],").replace("两端 XH 3P','10'],", "两端 XH 3P','9'],")
R("['合页销','采购','2','M3×30 + 防松螺母','5'],['钕磁铁','采购','4','Ø6 × 3 mm','11']", "['合页销','采购','2','M3×30 + 防松螺母','4'],['钕磁铁','采购','4','Ø6 × 3 mm','10']")
R("['热熔螺母','采购','10','M2','12']", "['热熔螺母','采购','10','M2','11']")
assert 'hTPU' not in s
open('v23_src.html', 'w').write(s); print('ok')
