#!/usr/bin/env python3
# fig_전체흐름도.py — 스테이션기반 플레이어 전체 흐름 다이어그램 (보고서 삽입용 PNG/PDF)
#   입력(폴더) → 자동 파싱 → 좌표·측점 계산 → 화면 출력, 오피스 단색 스타일.
#   weasyprint SVG 텍스트 디센더 잘림 이슈 회피를 위해 PIL 직접 드로잉.
# 실행: python3 scripts/fig_전체흐름도.py  → docs/그림_전체흐름도.png / .pdf
import math, os
from PIL import Image, ImageDraw, ImageFont

OUT_DIR = os.path.join(os.path.dirname(__file__), '..', 'docs')
FB = os.path.expanduser('~/.local/share/fonts/malgunbd.ttf')
FR = os.path.expanduser('~/.local/share/fonts/malgun.ttf')

W, H = 2400, 1100
im = Image.new('RGB', (W, H), 'white')
d = ImageDraw.Draw(im)

GRAY, BLUE, GREEN, AMBER = (89, 89, 89), (46, 117, 182), (112, 173, 71), (191, 144, 0)
PURPLE, CAPTION = (124, 58, 237), (64, 64, 64)

def fit(text, path, size, maxw):
    """maxw 안에 들어올 때까지 폰트 크기를 줄여 반환."""
    while size > 20:
        f = ImageFont.truetype(path, size)
        if d.textlength(text, font=f) <= maxw:
            return f
        size -= 2
    return ImageFont.truetype(path, size)

def box(x1, y1, x2, y2, color, main, sub, subcolor):
    d.rectangle((x1, y1, x2, y2), fill=color)
    cx, cy, maxw = (x1 + x2) // 2, (y1 + y2) // 2, (x2 - x1) - 40
    d.text((cx, cy - 24), main, font=fit(main, FB, 40, maxw), fill='white', anchor='mm')
    d.text((cx, cy + 32), sub, font=fit(sub, FR, 28, maxw), fill=subcolor, anchor='mm')

def arrow(x1, y1, x2, y2):
    d.line((x1, y1, x2, y2), fill=PURPLE, width=7)
    ang = math.atan2(y2 - y1, x2 - x1)
    L, Wd = 34, 20
    d.polygon([(x2, y2),
               (x2 - L*math.cos(ang) + Wd*math.sin(ang), y2 - L*math.sin(ang) - Wd*math.cos(ang)),
               (x2 - L*math.cos(ang) - Wd*math.sin(ang), y2 - L*math.sin(ang) + Wd*math.cos(ang))],
              fill=PURPLE)

cap = ImageFont.truetype(FB, 34)
d.text((310, 100), '입력 — 데이터 폴더 1개', font=cap, fill=CAPTION, anchor='mm')
d.text((880, 100), '① 자동 파싱', font=cap, fill=CAPTION, anchor='mm')
d.text((1440, 100), '② 좌표·측점 계산', font=cap, fill=CAPTION, anchor='mm')
d.text((2080, 100), '③ 화면 출력', font=cap, fill=CAPTION, anchor='mm')

# 입력 그룹 (테두리 + 4종)
d.rectangle((60, 150, 560, 950), fill=(245, 245, 245), outline=(176, 176, 176), width=3)
box(90, 190, 530, 340, GRAY, '영상 (mp4)', '드론 촬영 철도시설물 영상', (232, 232, 232))
box(90, 380, 530, 530, GRAY, '드론 비행로그 (csv)', '프레임별 위치·자세각·초점거리', (232, 232, 232))
box(90, 570, 530, 720, GRAY, '측점 (csv)', '좌표 · 실측 정표고', (232, 232, 232))
box(90, 760, 530, 910, GRAY, 'POI·구조물 (kmz)', '+ 노선 보정 (json·선택)', (232, 232, 232))

# 파싱
box(680, 460, 1080, 640, BLUE, '자동 파싱', '인코딩 자동감지 · KMZ 해제', (219, 233, 247))

# 계산 2종
box(1180, 320, 1700, 480, GREEN, '시간↔측점 대응표 생성', 'GPS를 선로에 투영 → 시간·측점 짝', (230, 242, 220))
box(1180, 580, 1700, 740, GREEN, '좌표 투영 계산', '드론 위치·자세각 → 화면 픽셀', (230, 242, 220))

# 출력 3종
box(1820, 210, 2340, 370, AMBER, '측점 스테이션바', '측점축 탐색 · 측점 검색', (247, 236, 208))
box(1820, 480, 2340, 640, AMBER, '영상 AR 오버레이', '시설물 정보 실시간 정합 표출', (247, 236, 208))
box(1820, 750, 2340, 910, AMBER, '대용량 영상 재생', '2GB+ 스트리밍 (Range/HLS)', (247, 236, 208))

# 화살표
arrow(560, 550, 672, 550)     # 입력 → 파싱
arrow(1080, 510, 1172, 420)   # 파싱 → 대응표
arrow(1080, 590, 1172, 640)   # 파싱 → 투영
arrow(1700, 400, 1812, 305)   # 대응표 → 스테이션바
arrow(1700, 660, 1812, 575)   # 투영 → AR 오버레이
# 영상 원본 → 재생 (계산 우회, 하단 엘보 경로)
d.line((310, 950, 310, 1030), fill=PURPLE, width=7)
d.line((310, 1030, 2080, 1030), fill=PURPLE, width=7)
arrow(2080, 1030, 2080, 922)
lbl = ImageFont.truetype(FR, 26)
d.text((1195, 998), '영상 원본은 계산 없이 곧바로 스트리밍 재생', font=lbl, fill=(102, 102, 102), anchor='mm')

png = os.path.join(OUT_DIR, '그림_전체흐름도.png')
im.save(png)
print('PNG 저장:', png, im.size)

# PDF (이미지 삽입 + 압축)
import fitz
doc = fitz.open()
rect = fitz.Rect(0, 0, W / 2, H / 2)
page = doc.new_page(width=rect.width, height=rect.height)
page.insert_image(rect, filename=png)
pdf = os.path.join(OUT_DIR, '그림_전체흐름도.pdf')
doc.save(pdf, deflate=True, garbage=4)
print('PDF 저장:', pdf)
