/*
 * Copyright © 2018 Keith Packard <keithp@keithp.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 */

/*
 * Generate LED images for rocketview and launchcontrol
 */

autoimport Cairo;

void led (cairo_t cr, real red, real green, real blue, bool on)
{
    translate (cr, .5, .5);

    /* basic unilluminated LED */

    if (true)
    {
	set_source_rgb (cr, red *.4, green *.4, blue *.4);
	move_to (cr, 1, 1/2);
	arc (cr, .5, .5, .5, 0, pi*2);
	fill (cr);
    }

    /* Bright spot of LED illumination */
    if (on)
    {
	pattern_t	led = Pattern::create_radial (1/2, 1/2, 0,
						      1/2, 1/2, .4);
	Pattern::add_color_stop_rgba (led, 0, red, green, blue, 1);
	Pattern::add_color_stop_rgba (led, .5, red, green, blue, .8);
	Pattern::add_color_stop_rgba (led, 1, red, green, blue, 0);
	set_source (cr, led);
	move_to (cr, 1, 1/2);
	arc (cr, .5, .5, .5, 0, pi*2);
	fill (cr);
    }

    /* Bezel */
    if (true)
    {
	pattern_t	ring = Pattern::create_radial (.5, .5, .4, .5, .5, .5);
	Pattern::add_color_stop_rgba (ring, 0, 0, 0, 0, 1);
	Pattern::add_color_stop_rgba (ring, .5, 0, 0, 0, 1);
	Pattern::add_color_stop_rgba (ring, 1, .5, .5, .5, 1);
	set_source (cr, ring);
	move_to (cr, 1, 1/2);
	arc (cr, .5, .5, .5, 0, pi*2);
	move_to (cr, 1, 1/2);
	arc_negative (cr, .5, .5, .45, pi*2, 0);
	fill (cr);
    }

    /* Specular highlight from room illumination */
    if (true)
    {
	pattern_t	room = Pattern::create_radial (1/3, 1/3, 0, 1/3, 1/3, 1/2);
	Pattern::add_color_stop_rgba (room, 0, 1, 1, 1, .4);
	Pattern::add_color_stop_rgba (room, 1, 1, 1, 1, 0);
	set_source (cr, room);
	move_to (cr, 1, 1/2);
	arc (cr, .5, .5, .5, 0, pi*2);
	fill (cr);
    }

}

/*
 * Desired LED image size in pixels
 */
int diameter = 12;

void do_one_svg (string name, real red, real green, real blue, bool on)
{
    cairo_t cr = new_svg (name, diameter, diameter);

    translate (cr, -width(cr)/2, -height(cr)/2);
    scale (cr, width(cr), height(cr));
    led (cr, red, green, blue, on);
    destroy (cr);
}

void do_one_png (string name, real red, real green, real blue, bool on)
{
    cairo_t cr = new_image (diameter, diameter);

    translate (cr, -width(cr)/2, -height(cr)/2);
    scale (cr, width(cr), height(cr));
    led (cr, red, green, blue, on);
    write_to_png (cr, name);
    destroy (cr);
}

void do_one(string name,  real red, real green, real blue, bool on)
{
    do_one_png(name + ".png", red, green, blue, on);
    do_one_svg(name + ".svg", red, green, blue, on);
}

void doit ()
{
    do_one ("redled", 1, 0, 0, true);
    do_one ("redoff", 1, 0, 0, false);
    do_one ("greenled", 0, 1, .4824, true);
    do_one ("greenoff", 0, 1, .4824, false);
    do_one ("grayled", .9, .9, .9, false);
    do_one ("grayon", .9, .9, .9, true);
}

typedef struct {
    real	red, green, blue;
    bool	on;
} stock_t;

stock_t[string] stock_leds = {
    "redled" => {
	.red = 1,
	.green = 0,
	.blue = 0,
	.on = true
    },
    "redoff" => {
	.red = 1,
	.green = 0,
	.blue = 0,
	.on = false
    },
    "greenled" => {
	.red = 0,
	.green = 1,
	.blue = .4824,
	.on = true
    },
    "greenoff" => {
	.red = 0,
	.green = 1,
	.blue = .4824,
	.on = false
    },
    "grayon" => {
	.red = .9,
	.green = .9,
	.blue = .9,
	.on = true
    },
    "grayled" => {
	.red = .9,
	.green = .9,
	.blue = .9,
	.on = false
    },
};

void main ()
{
    for (int i = 1; i < dim(argv); i++) {
	string 		name = argv[i];
	string[]	bits = String::split(name, ".");

	if (dim(bits) != 2) {
	    File::fprintf(stderr, "Filename is weird: \"%s\"\n", argv[i]);
	    exit (1);
	}

	stock_t	stock = stock_leds[bits[0]];
	switch (bits[1]) {
	case "png":
	    do_one_png(argv[i], stock.red, stock.green, stock.blue, stock.on);
	    break;
	case "svg":
	    do_one_svg(argv[i], stock.red, stock.green, stock.blue, stock.on);
	    break;
	}
    }
}

if (dim(argv) > 0) {
    main();
}
