import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Path2D;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;

/**
 * ツールバーの絵を描く。<b>明暗 2 組</b>を出す。
 *
 * <p>1 色で両方を賄おうとすると、暗い配色と明るい配色のどちらに対しても対比が 3:1 程度にしか
 * ならない ―― 単色の理屈上の上限がそこである。3:1 の絵は「押せない状態」に見える。
 * 環境の共有アイコンが明暗で差し替わっているのと同じことを、自前の絵でもやる。
 */
public final class MakeIcons {

    /** 暗い配色(#3C3F41 前後)に載せる線。 */
    private static final Color INK_ON_DARK = new Color(0xD6, 0xD8, 0xDA);
    /** 明るい配色(#F0F0F0 前後)に載せる線。 */
    private static final Color INK_ON_LIGHT = new Color(0x45, 0x48, 0x4B);
    private static final int N = 16;

    public static void main(String[] args) throws Exception {
        File root = new File(args[0]);
        emit(new File(root, "light"), INK_ON_LIGHT);
        emit(new File(root, "dark"), INK_ON_DARK);
        System.out.println("wrote light/ and dark/ under " + root);
    }

    private static void emit(File dir, Color ink) throws Exception {
        dir.mkdirs();
        write(new File(dir, "expandall.png"), ink, g -> {
            rows(g);
            chevron(g, true);
        });
        write(new File(dir, "collapseall.png"), ink, g -> {
            rows(g);
            chevron(g, false);
        });
        write(new File(dir, "exporttree.png"), ink, g -> {
            rows(g);
            exportArrow(g);
        });
        write(new File(dir, "exportpdf.png"), ink, MakeIcons::sheet);
    }

    /** 右側の 3 本。木の行(段が下がるほど字下げ)を表す。 */
    private static void rows(Graphics2D g) {
        g.setStroke(new BasicStroke(1.6f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
        g.drawLine(8, 3, 14, 3);
        g.drawLine(10, 8, 14, 8);
        g.drawLine(12, 13, 14, 13);
    }

    /** 左側の山形。下向きが「開く」、上向きが「畳む」。 */
    private static void chevron(Graphics2D g, boolean down) {
        g.setStroke(new BasicStroke(1.8f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
        double top = down ? 5.0 : 10.5;
        double tip = down ? 10.5 : 5.0;
        Path2D p = new Path2D.Double();
        p.moveTo(1.2, top);
        p.lineTo(4.0, tip);
        p.lineTo(6.8, top);
        g.draw(p);
    }

    /**
     * 左側の下向き矢印と、それを受ける皿。書き出し(取り出す)の定型。
     *
     * <p>皿は<b>コの字</b>にする。1 本の線だと、開くときの山形と見分けが付かない ――
     * 16 画素では「矢印か山形か」の差はほとんど出ないので、別の形を足して区別を作る。
     */
    private static void exportArrow(Graphics2D g) {
        g.setStroke(new BasicStroke(1.8f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
        g.drawLine(4, 1, 4, 7);
        Path2D head = new Path2D.Double();
        head.moveTo(1.4, 4.6);
        head.lineTo(4.0, 7.6);
        head.lineTo(6.6, 4.6);
        g.draw(head);
        Path2D tray = new Path2D.Double();
        tray.moveTo(1.0, 10.6);
        tray.lineTo(1.0, 13.6);
        tray.lineTo(7.0, 13.6);
        tray.lineTo(7.0, 10.6);
        g.draw(tray);
    }

    /**
     * 紙 1 枚と、そこから取り出す矢印。報告書の書き出し。
     *
     * <p>木の書き出しとは<b>主題で分ける</b> ―― あちらは行(木)、こちらは紙(報告書)。
     * どちらも矢印を持つので、矢印以外の所で違いを付ける必要がある。
     */
    private static void sheet(Graphics2D g) {
        g.setStroke(new BasicStroke(1.5f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
        // 角を折った紙
        Path2D page = new Path2D.Double();
        page.moveTo(2.0, 1.2);
        page.lineTo(8.4, 1.2);
        page.lineTo(11.4, 4.2);
        page.lineTo(11.4, 14.4);
        page.lineTo(2.0, 14.4);
        page.closePath();
        g.draw(page);
        Path2D fold = new Path2D.Double();
        fold.moveTo(8.4, 1.2);
        fold.lineTo(8.4, 4.2);
        fold.lineTo(11.4, 4.2);
        g.draw(fold);
        // 中の文字
        g.drawLine(4, 7, 9, 7);
        g.drawLine(4, 10, 9, 10);
    }

    private interface Draw {
        void on(Graphics2D g);
    }

    private static void write(File out, Color ink, Draw d) throws Exception {
        BufferedImage img = new BufferedImage(N, N, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = img.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
        g.setColor(ink);
        d.on(g);
        g.dispose();
        ImageIO.write(img, "png", out);
    }
}
