# -*- coding: utf-8 -*-
"""SYLVANIA CONTINUUM（shop.sorah.io / SOR-0002）の配色に合わせた森林の世界地図。

二色の語法は同じで、役割の割り当てだけが反転する:
  紙（海）＝用紙のベージュ ／ 陸＝白インク ／ 森＝緑インク（8 段）
つまり「主役＝白」ではなく「主役＝紙から最も遠い色」。
"""
import os, sys, json
import numpy as np
sys.path.insert(0, '/home/claude/forest')
import forest1 as F
from PIL import Image

PAPER = np.array([254, 245, 233], np.float32)   # 用紙のベージュ（ポスターの海）
LANDC = np.array([255, 255, 255], np.float32)   # 白インク（陸・非森林）
INK   = np.array([70, 117, 80], np.float32)     # 緑インク（森）
OUT = '/home/claude/forest/out'

def to_lab(rgb):
    x = rgb / 255.0
    x = np.where(x > 0.04045, ((x + 0.055) / 1.055) ** 2.4, x / 12.92)
    M = np.array([[0.4124, 0.3576, 0.1805], [0.2126, 0.7152, 0.0722], [0.0193, 0.1192, 0.9505]])
    X = M @ x / np.array([0.95047, 1.0, 1.08883])
    f = np.where(X > 0.008856, np.cbrt(X), 7.787 * X + 16/116)
    return np.array([116*f[1] - 16, 500*(f[0]-f[1]), 200*(f[1]-f[2])])
def from_lab(lab):
    L, a, b = lab; fy = (L+16)/116; fx = fy + a/500; fz = fy - b/200
    def finv(t): return t**3 if t**3 > 0.008856 else (t - 16/116)/7.787
    X = np.array([0.95047*finv(fx), 1.0*finv(fy), 1.08883*finv(fz)])
    M = np.array([[3.2406, -1.5372, -0.4986], [-0.9689, 1.8758, 0.0415], [0.0557, -0.2040, 1.0570]])
    r = M @ X
    r = np.where(r <= 0.0031308, 12.92*r, 1.055*np.power(np.clip(r, 0, 1), 1/2.4) - 0.055)
    return np.clip(r*255, 0, 255)
def ramp(n):
    """陸の白から緑インクまで、Lab で等間隔に n 段。"""
    a, b = to_lab(LANDC), to_lab(INK)
    return [from_lab(a + (b - a) * (k + 0.5) / n).astype(np.uint8) for k in range(n)]

def build(size=(1350, 1080), year=2020, bands=8, bbox=(-180, -58, 180, 83), name='S1', ds=8,
          lines=True, labels=True, dense_only=False, proj='pc', cont=False):
    sc = F.Scene(bbox, size, proj=proj)
    lon, lat, ok = sc.lonlat_grid()
    la = F.land_mask(sc); land = la > 0.5
    fr = F.sample(F.frac(year, ds, dense_only)[0], lon, lat, ok)
    img = np.zeros((sc.H, sc.W, 3), np.uint8); img[:] = PAPER.astype(np.uint8)
    img[land] = LANDC.astype(np.uint8)
    if cont:   # 連続（帯に切らない）
        n = 64; cols = ramp(n); on = land & (fr > 1.0/n/2)
        idx = np.clip((fr*n).astype(int), 0, n-1)
        for k in range(n):
            b = on & (idx == k); img[b] = cols[k]
    else:
        cols = [INK.astype(np.uint8)] if bands == 1 else ramp(bands)   # 二値は最も濃いインクで塗る
        on = land & (fr > 1.0 / bands / 2)
        for k in range(bands):
            b = on & (fr > k/bands) & (fr <= (k+1)/bands + (1 if k == bands-1 else 0))
            img[b] = cols[k]
    im = Image.fromarray(img)
    # 線と文字は下地からの相対シフト（明るい所は緑へ、暗い所は紙へ）
    F.NAVY = INK; F.WHITE = PAPER
    F.ON_LIGHT = from_lab(to_lab(INK) + (to_lab(PAPER) - to_lab(INK)) * 0.32).astype(np.float32)
    F.ON_DARK = from_lab(to_lab(PAPER) + (to_lab(INK) - to_lab(PAPER)) * 0.30).astype(np.float32)
    s = (sc.W, sc.H)
    if lines:
        im = F.comp_rel(im, F.aa_mask(s, F.grat(sc)), 0.22, 0.16)
        im = F.comp_rel(im, F.aa_mask(s, F.tropics(sc)), 0.22, 0.16)
    if labels:
        for it in F.REGIONS: im = F.comp_label(im, F.aa_mask(s, F.text_fn(sc, it, 20)), F.ON_LIGHT, F.ON_DARK)
    im.save(f'{OUT}/{name}.png')
    im.resize((320, int(320*sc.H/sc.W)), Image.LANCZOS).save(f'{OUT}/{name}-320.png')
    print(name, size, dict(px_land=int(land.sum()), px_forest=int(on.sum())), flush=True)
    return im

if __name__ == '__main__':
    import sys
    build(name='S4')                       # 正距円筒・帯8段・森林全体（確定した構図）
    build(name='B1', bands=1)              # 帯 1 段（二値：森か森でないか）
    build(name='B4', bands=4)
    build(name='B8', bands=8)
    build(name='BC', cont=True)            # 帯に切らない連続
