/****************************************************************************
 *
 * MODULE:       r.colors
 *
 * AUTHOR(S):    Michael Shapiro - CERL
 *               David Johnson
 *
 * PURPOSE:      Allows creation and/or modification of the color table
 *               for a raster map layer.
 *
 * COPYRIGHT:    (C) 2006 by the GRASS Development Team
 *
 *               This program is free software under the GNU General Public
 *               License (>=v2). Read the file COPYING that comes with GRASS
 *               for details.
 *
 ***************************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include "local_proto.h"

/* color structure for default and null value */

static int read_rule(void *, DCELL, DCELL, DCELL *, int *, int *, int *, int *,
                     int *, int *);
static void badrule(int, const char *, int);
static int show_colors(FILE *);

static int rule_is_percent = 0;

int read_color_rules(FILE *fp, struct Colors *colors, DCELL min, DCELL max,
                     int is_fp, int *is_percent)
{
    DCELL rulemin, rulemax;

    if (isatty(fileno(fp))) {
        fprintf(
            stderr,
            _("Enter rules, \"end\" when done, \"help\" if you need it.\n"));

        if (is_fp) {
            char minstr[64], maxstr[64];

            sprintf(minstr, "%.15g", (double)min);
            sprintf(maxstr, "%.15g", (double)max);
            G_trim_decimal(minstr);
            G_trim_decimal(maxstr);
            fprintf(stderr, _("fp: Data range is %s to %s\n"), minstr, maxstr);
        }
        else
            fprintf(stderr, _("Data range is %ld to %ld\n"), (long)min,
                    (long)max);
    }

    if (!Rast_read_color_rules(colors, min, max, read_rule, fp))
        return 0;

    Rast_get_d_color_range(&rulemin, &rulemax, colors);
    G_debug(3, "rulemin=%.3f  rulemax=%.3f", rulemin, rulemax);

    if (rulemin > min || rulemax < max)
        G_warning(_("Your color rules do not cover the whole range of data!\n "
                    "(rules %f to %f but data %f to %f)"),
                  rulemin, rulemax, min, max);

    *is_percent = rule_is_percent;

    return 1;
}

int check_percent_rule(const char *path)
{
    FILE *fp;
    char buf[1024];

    fp = fopen(path, "r");
    if (!fp)
        G_fatal_error(_("Unable to open color rule"));

    rule_is_percent = 0;
    while (G_getl2(buf, sizeof(buf), fp)) {
        char value[80], color[80];
        double x;
        char c;

        G_strip(buf);

        if (*buf == '\0')
            continue;
        if (*buf == '#')
            continue;

        if (sscanf(buf, "%s %[^\n]", value, color) != 2)
            continue;

        if (sscanf(value, "%lf%c", &x, &c) == 2 && c == '%') {
            rule_is_percent = 1;
            break;
        }
    }
    fclose(fp);

    return rule_is_percent;
}

void rescale_colors(struct Colors *colors_tmp, struct Colors *colors,
                    double offset, double scale)
{
    int i, rcount;
    unsigned char r1, g1, b1, r2, g2, b2;
    int red, grn, blu;
    DCELL dmin, dmax;

    Rast_init_colors(colors_tmp);

    Rast_get_default_color(&red, &grn, &blu, colors);
    Rast_set_default_color(red, grn, blu, colors_tmp);

    Rast_get_null_value_color(&red, &grn, &blu, colors);
    Rast_set_null_value_color(red, grn, blu, colors_tmp);

    rcount = Rast_colors_count(colors);
    /* read the rules in reverse order,
     * see lib/raster/color_write.c:write_rules() */
    for (i = rcount - 1; i >= 0; i--) {

        Rast_get_fp_color_rule(&dmin, &r1, &g1, &b1, &dmax, &r2, &g2, &b2,
                               colors, i);

        dmin = (dmin + offset) * scale;
        dmax = (dmax + offset) * scale;

        Rast_add_d_color_rule(&dmin, r1, g1, b1, &dmax, r2, g2, b2, colors_tmp);
    }
}

static int read_rule(void *closure, DCELL min, DCELL max, DCELL *val, int *r,
                     int *g, int *b, int *norm, int *nval, int *dflt)
{
    FILE *fp = closure;
    int tty = isatty(fileno(fp));

    *norm = *nval = *dflt = 0;

    for (;;) {
        char buf[1024];
        int ret, i;
        char value[80], color[80];
        double x;
        char c;

        if (tty)
            fprintf(stderr, "> ");

        if (!G_getl2(buf, sizeof(buf), fp))
            return 0;

        for (i = 0; buf[i]; i++)
            if (buf[i] == ',')
                buf[i] = ' ';

        G_strip(buf);

        if (*buf == '\0')
            continue;
        if (*buf == '#')
            continue;

        if (strncmp(buf, "end", 3) == 0)
            return 0;

        if (strncmp(buf, "help", 4) == 0) {
            fprintf(stderr, _("Enter a rule in one of these formats:\n"));
            fprintf(stderr, _(" val color\n"));
            fprintf(stderr, _(" n%% color\n"));
            fprintf(stderr, _(" nv color\n"));
            fprintf(stderr, _(" default color\n"));
            fprintf(stderr, _("color can be one of:\n"));
            show_colors(stderr);
            fprintf(stderr, _("or an R:G:B triplet, e.g.: 0:127:255\n"));

            continue;
        }

        if (sscanf(buf, "%s %[^\n]", value, color) == 2) {
            if (sscanf(value, "%lf%c", &x, &c) == 2 && c == '%') {
                rule_is_percent = 1;
            }
        }

        ret = Rast_parse_color_rule(min, max, buf, val, r, g, b, norm, nval,
                                    dflt);
        if (ret == 0)
            return 1;

        badrule(tty, buf, ret);
    }

    return 0;
}

static void badrule(int tty, const char *s, int code)
{
    const char *err = Rast_parse_color_rule_error(code);

    if (tty)
        G_warning(_("bad rule (%s); rule not added"), err);
    else
        G_fatal_error(_("bad rule (%s): [%s]"), err, s);
}

static int show_colors(FILE *fp)
{
    int len;
    int i, n;
    const char *color;

    len = 0;
    for (i = 0; (color = G_color_name(i)); i++) {
        n = strlen(color) + 1;
        if (len + n > 78) {
            fprintf(fp, "\n");
            len = 0;
        }
        fprintf(fp, " %s", color);
        len += n;
    }
    fprintf(fp, "\n");

    return 0;
}
