import './workspace.css';
import { DEFAULT_SETTINGS, generateDrawing, VIEW_TITLES, formatMm } from './drawing';
import { drawingSvg } from './svg';
import { exportDxf } from './dxf';
import { LAYERS, type DrawingDocument, type DrawingSettings, type DrawingSnapshot, type Layer, type Rect, type ViewId } from './types';
import type { PierModel } from '../src/core/geometry';
import { defaultSheet, parseSheetConfig } from './template';
import { createSheetEditor } from './sheet-editor';
import { shortenedBounds } from './breaks';
import { createQualityPanel } from './quality-panel';
export function createDrawingWorkspace(host: HTMLElement,read:()=>DrawingSnapshot,select:(id:string)=>void,openMaterials?:()=>void): { update:()=>void } {
host.className='ga-workspace';
host.innerHTML=`
프로젝트 미지정교각 일반도
교각 형상을 생성하면 일반도가 표시됩니다.
`;
const node=(id:string)=>host.querySelector(`#${id}`)!;
if(openMaterials){
const button=window.document.createElement('button');button.type='button';button.id='ga-materials';button.textContent='재료표';button.addEventListener('click',openMaterials);
host.querySelector('.ga-toolbar-actions')!.prepend(button);
}
const pier=node('ga-pier'),view=node('ga-view'),paper=node('ga-paper'),scale=node('ga-scale');
const bearing=node('ga-bearing');
const canvas=node('ga-canvas'),empty=node('ga-empty'),warnings=node('ga-warnings'),note=node('ga-data-note');
const visible=new Set((Object.keys(LAYERS) as Layer[]).filter(l=>l!=='HIDDEN'));
let sheetConfig=defaultSheet(),sheetKey='',lastContextModels:(PierModel|null)[]=[];
let document:DrawingDocument|undefined,lastModel:PierModel|undefined,lastKey='',optionKey='',camera:Rect={x:0,y:0,width:420,height:297};
let press:{x:number;y:number;anchor:DOMPoint;entity?:string}|undefined;
const settings=():DrawingSettings=>({paper:paper.value as DrawingSettings['paper'],scale:scale.value==='auto'?'auto':Number(scale.value),
dimensions:node('ga-dimensions').checked,centers:node('ga-centers').checked,elevations:node('ga-elevations').checked,
shorten:node('ga-shorten').checked,detailBearing:bearing.value,hatches:node('ga-hatches').checked,isoDirection:Number(node('ga-iso').value),sheet:sheetConfig});
const svg=()=>canvas.querySelector('svg');
const setCamera=()=>svg()?.setAttribute('viewBox',`${camera.x} ${camera.y} ${camera.width} ${camera.height}`);
const fit=()=>{
if(!document)return;
const target=document.views.find(v=>v.id===view.value);
if(target){const b=shortenedBounds(target.bounds,target.breaks),width=Math.max(target.slot.width,(b.maxX-b.minX)/target.scale),height=Math.max(target.slot.height,(b.maxY-b.minY)/target.scale);camera={x:target.slot.x+(target.slot.width-width)/2-5,y:target.slot.y+(target.slot.height-height)/2-5,width:width+10,height:height+12};}
else camera={x:0,y:0,width:document.paper.width,height:document.paper.height};
setCamera();
};
const redraw=(reset=false)=>{
if(!document){canvas.replaceChildren();empty.hidden=false;return;}
empty.hidden=true;canvas.innerHTML=drawingSvg(document,visible,true,view.value==='sheet'?undefined:view.value as ViewId);if(reset)fit();else setCamera();
node('ga-count').textContent=`${document.views.reduce((n,v)=>n+v.entities.filter(e=>visible.has(e.layer)).length,0)} 객체 · 간섭 ${document.quality?.after??'미검사'}건 · mm / EL m`;
};
const enable=(on:boolean)=>['ga-dxf','ga-dwg','ga-quality','ga-svg','ga-preview','ga-generate','ga-update','ga-regenerate'].forEach(id=>{node(id).disabled=!on;});
const update=(force=false)=>{
host.style.height=`${Math.max(480,window.innerHeight-host.getBoundingClientRect().top-12)}px`;
const snapshot=read(),items=snapshot.piers;
const nextSheetKey=`pierzainer.ga.sheet.v1:${snapshot.project.name}|${snapshot.project.bridge}`;
if(sheetKey!==nextSheetKey){sheetKey=nextSheetKey;sheetConfig=defaultSheet();try{const saved=localStorage.getItem(sheetKey);if(saved)sheetConfig=parseSheetConfig(JSON.parse(saved));}catch{/* Keep original template if browser storage is unavailable or corrupt. */}}
const nextOptionKey=items.map(p=>`${p.input.name}:${p.input.type}:${!!p.model}`).join('|');
if(optionKey!==nextOptionKey){optionKey=nextOptionKey;pier.replaceChildren();
if(!items.length)pier.add(new Option('교각 없음',''));
for(const p of items)pier.add(new Option(`${p.input.name} · ${p.input.type}${p.model?'':' · 형상 없음'}`,p.input.name));}
pier.value=snapshot.selected??items[0]?.input.name??'';
const selected=items.find(p=>p.input.name===pier.value);
node('ga-project').textContent=[snapshot.project.name,snapshot.project.bridge].filter(Boolean).join(' · ')||'프로젝트 미지정';
node('ga-title').textContent=selected?`${selected.input.name} 교각 일반도`:'교각 일반도';
host.dataset.pier=selected?.input.name??'';
note.textContent=selected?.dirty?'현재 입력이 3D 형상에 아직 반영되지 않았습니다. 상단에서 형상을 다시 생성하면 도면도 갱신됩니다.':'현재 생성된 3D 형상 데이터를 사용합니다. 모델 변경 시 자동 갱신합니다.';
enable(!!selected?.model);warnings.replaceChildren();
if(!selected?.model){document=undefined;lastModel=undefined;empty.textContent=selected?'선택한 교각의 형상이 없습니다. 형상 생성 오류를 먼저 확인하세요.':'교각 형상을 생성하면 일반도가 표시됩니다.';redraw();return;}
if(lastModel!==selected.model){const previous=bearing.value;bearing.replaceChildren();for(const b of selected.model.blocks)bearing.add(new Option(`${b.row} ${b.no}`,`${b.row}:${b.no}`));if(Array.from(bearing.options).some(o=>o.value===previous))bearing.value=previous;}
const key=JSON.stringify([settings(),snapshot.project.name,snapshot.project.bridge]);
try{
const models=items.map(p=>p.model),contextChanged=models.length!==lastContextModels.length||models.some((m,i)=>m!==lastContextModels[i]);
if(force||lastModel!==selected.model||lastKey!==key||contextChanged){document=generateDrawing(selected.model,selected.input,snapshot.project,settings(),{models:models.filter((m):m is PierModel=>!!m)});lastModel=selected.model;lastContextModels=models;lastKey=key;redraw(true);}
for(const message of document?.warnings??[]){const li=window.document.createElement('li');li.textContent=message;warnings.append(li);}
}catch(error){document=undefined;lastModel=undefined;enable(false);empty.textContent=(error as Error).message;redraw();}
};
const download=(text:string,extension:string,mime:string)=>{
if(!document)return;
const url=URL.createObjectURL(new Blob([text],{type:mime})),link=window.document.createElement('a');
link.href=url;link.download=`${document.bridge||document.project||'교량'}_${document.pier}_일반도.${extension}`.replace(/[\\/:*?"<>|]/g,'_');link.click();window.setTimeout(()=>URL.revokeObjectURL(url),1000);
};
pier.addEventListener('change',()=>select(pier.value));view.addEventListener('change',()=>redraw(true));
[paper,scale,bearing,node('ga-iso'),node('ga-hatches'),node('ga-shorten'),node('ga-dimensions'),node('ga-centers'),node('ga-elevations')].forEach(e=>e.addEventListener('change',()=>update(true)));
const editor=createSheetEditor(host,config=>{sheetConfig=config;try{localStorage.setItem(sheetKey,JSON.stringify(config));}catch{node('ga-object-info').textContent='브라우저 저장 공간이 부족합니다. 도곽/노트 JSON 저장을 사용하세요.';}update(true);});
node('ga-sheet-editor').addEventListener('click',()=>editor.open(sheetConfig));
['ga-generate','ga-update','ga-regenerate'].forEach(id=>node(id).addEventListener('click',()=>update(true)));
node('ga-fit').addEventListener('click',fit);
host.querySelectorAll('[data-layer]').forEach(checkbox=>checkbox.addEventListener('change',()=>{const layer=checkbox.dataset.layer as Layer;if(checkbox.checked)visible.add(layer);else visible.delete(layer);redraw();}));
const point=(event:{clientX:number;clientY:number}):DOMPoint=>new DOMPoint(event.clientX,event.clientY).matrixTransform(svg()!.getScreenCTM()!.inverse());
const zoom=(factor:number,anchor?:DOMPoint)=>{
if(!document||!svg())return;
const target=anchor??new DOMPoint(camera.x+camera.width/2,camera.y+camera.height/2),width=Math.min(document.paper.width*20,Math.max(document.paper.width*.025,camera.width*factor)),ratio=width/camera.width;
camera={x:target.x-(target.x-camera.x)*ratio,y:target.y-(target.y-camera.y)*ratio,width,height:camera.height*ratio};setCamera();
};
node('ga-zoom-in').addEventListener('click',()=>zoom(.8));node('ga-zoom-out').addEventListener('click',()=>zoom(1.25));
canvas.addEventListener('wheel',event=>{if(svg()){event.preventDefault();zoom(Math.exp(Math.max(-.4,Math.min(.4,event.deltaY*.0015))),point(event));}},{passive:false});
canvas.addEventListener('pointerdown',event=>{if(!svg()||event.button>1)return;event.preventDefault();press={x:event.clientX,y:event.clientY,anchor:point(event),entity:(event.target as Element).closest('[data-entity]')?.dataset.entity};canvas.setPointerCapture(event.pointerId);canvas.classList.add('is-panning');});
canvas.addEventListener('pointermove',event=>{if(!press||!svg())return;const current=point(event);camera.x+=press.anchor.x-current.x;camera.y+=press.anchor.y-current.y;setCamera();});
const release=(event:PointerEvent)=>{if(!press)return;const clicked=Math.hypot(event.clientX-press.x,event.clientY-press.y)<4;if(clicked&&press.entity&&document){const [viewId,index]=press.entity.split(':');const e=document.views.find(v=>v.id===viewId)?.entities[Number(index)];if(e)node('ga-object-info').textContent=`${e.source.pier} / ${e.source.member} ${e.source.index+1} · ${e.layer}${e.kind==='dimension'?` · ${formatMm(e.value)} mm`:''}`;}press=undefined;canvas.classList.remove('is-panning');};
canvas.addEventListener('pointerup',release);canvas.addEventListener('pointercancel',()=>{press=undefined;canvas.classList.remove('is-panning');});
node('ga-dxf').addEventListener('click',()=>{if(document)download(exportDxf(document,visible),'dxf','application/dxf;charset=utf-8');});
const qualityPanel=createQualityPanel(host,()=>document,id=>{view.value=id;redraw(true);});
node('ga-quality').addEventListener('click',qualityPanel);
node('ga-dwg').addEventListener('click',async()=>{
const snapshot=document;if(!snapshot)return;const button=node('ga-dwg');button.disabled=true;button.textContent='DWG 검증 중…';
try{
const response=await fetch('/__pierzainer/general-arrangement/dwg',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({dxf:exportDxf(snapshot,new Set(visible))})});
if(!response.ok){const error=await response.json().catch(()=>({error:'DWG 출력 서버를 찾을 수 없습니다. 개발 서버를 다시 실행하세요.'}));throw new Error(error.error);}
snapshot.dwgValidation=JSON.parse(decodeURIComponent(response.headers.get('X-Pierzainer-Validation')??'%7B%7D'));
const url=URL.createObjectURL(await response.blob()),a=window.document.createElement('a');a.href=url;a.download=`${snapshot.bridge||snapshot.project}_${snapshot.pier}_일반도.dwg`.replace(/[\\/:*?"<>|]/g,'_');a.click();setTimeout(()=>URL.revokeObjectURL(url),1000);
node('ga-object-info').textContent='DWG 2000 변환 · 내부 객체/치수 비교 통과(CAD 직접 열기 미검증). 열리지 않으면 DXF 내보내기를 사용하고 CAD 오류 문구를 확인하세요.';
}catch(error){node('ga-object-info').textContent=`DWG 출력 실패: ${(error as Error).message}`;}finally{button.disabled=false;button.textContent='DWG 내보내기';}
});
node('ga-svg').addEventListener('click',()=>{if(document)download(drawingSvg(document,visible),'svg','image/svg+xml;charset=utf-8');});
const preview=node('ga-print-dialog');
node('ga-preview').addEventListener('click',()=>{if(!document)return;node('ga-print-sheet').innerHTML=drawingSvg(document,visible);node('ga-print-paper').textContent=`${document.paper.name} 가로 · 각 뷰 축척 적용`;preview.showModal();});
node('ga-print-close').addEventListener('click',()=>preview.close());
node('ga-print').addEventListener('click',()=>{
if(!document)return;const frame=window.document.createElement('iframe');frame.style.cssText='position:fixed;width:1px;height:1px;left:-9999px;border:0';
frame.srcdoc=`교각 일반도${drawingSvg(document,visible)}`;
frame.onload=()=>{frame.contentWindow?.addEventListener('afterprint',()=>frame.remove(),{once:true});frame.contentWindow?.print();};host.append(frame);
});
window.addEventListener('resize',()=>{if(!host.hidden)host.style.height=`${Math.max(480,window.innerHeight-host.getBoundingClientRect().top-12)}px`;});
return{update:()=>update()};
}