/* Function: ps_fcolortable
**
** Author: Radim Blazek, leto 02
*/

#include <string.h>
#include <grass/glocale.h>

#include "ps_info.h"
#include "colortable.h"
#include "local_proto.h"


#define NSTEPS 3
#define NNSTEP 4 /* number of nice steps */

extern int verbose;

int PS_fcolortable (void)
{
    char buf[512], *ch;
    int i, k;
    int R, G, B;
    DCELL dmin, dmax, val;
    double t, l, r; /* legend top, left, right */
    double x1, x2, y, dy, fontsize;
    double col_width;
    double width;  /* width of legend in map units */
    double height; /* width of legend in map units */
    double cwidth; /* width of one color line */
    double lwidth; /* line width - frame, ... */
    double step;   /* step between two values */
    int    ncols, cur_step, ddig;
    double nice_steps[NNSTEP] = { 1.0, 2.0, 2.5, 5.0 }; /* nice steps */
    struct Colors colors;
    struct FPRange range;
    double ex, cur_d, cur_ex;
    int do_color;
    double grey_color_val;

    /* let user know what's happenning */
    if (verbose > 1)
    {
        fprintf (stdout,"PS-PAINT: creating color table for <%s in %s> ...",
	    ct.name, ct.mapset);
        fflush(stdout);
    }

    /* Get color range */
    if (G_read_fp_range(ct.name, ct.mapset, &range) == -1) {
	G_warning(_("Range information not available (run r.support)."));
	return 1;
    }

    G_get_fp_range_min_max(&range, &dmin, &dmax);

    /* override if range command is set */
    if(ct.range_override) {
	dmin = ct.min;
	dmax = ct.max;
    }

    if(dmin == dmax) { /* if step==0 all sorts of infinite loops and DIV by 0 errors follow */
	G_warning(_("A floating point colortable must contain a range of values."));
	return 1;
    }

    if (G_read_colors(ct.name, ct.mapset, &colors) == -1)
	G_warning(_("Unable to read colors for colorbar"));

    do_color = (PS.grey == 0 && PS.level == 2);

    /* set font */
    fontsize = (double)ct.fontsize;
    fprintf(PS.fp, "(%s) FN %.1f SF\n", ct.font, fontsize);

    /* set colortable location,  */
    /* if height and width are not given, calculate defaults */
    if ( ct.width <= 0 )
	ct.width = 2 * ct.fontsize / 72.0 ;
    if ( ct.height <= 0 )
	ct.height = 10 * ct.fontsize / 72.0 ;

    dy = 1.5 * fontsize;

    G_debug(3, "pwidth = %f pheight = %f", PS.page_width, PS.page_height);
    G_debug(3, "ct.width = %f ct.height = %f", ct.width, ct.height);
    G_debug(3, "ct.x = %f ct.y = %f", ct.x, ct.y);

    /* reset position to get at least something in BBox */
    if (ct.y < PS.top_marg ) { /* higher than top margin */
	G_warning(_("Colorbar y location beyond page margins. Adjusting."));
       	ct.y = PS.top_marg + 0.1;
    } else if (ct.y > PS.page_height - PS.bot_marg ) {
	/* lower than bottom margin - simply move one inch up from bottom margin */
	G_warning(_("Colorbar y location beyond page margins. Adjusting."));
	ct.y = PS.page_height - PS.bot_marg - 1 ; 
    }
    t = 72.0 * ( PS.page_height - ct.y); 

    if ( ct.x < PS.left_marg ) {
	G_warning(_("Colorbar x location beyond page margins. Adjusting."));
	ct.x = PS.left_marg + 0.1;
    } else if ( ct.x > PS.page_width - PS.right_marg ) {
	/* move 1 inch to the left from right marg */
	G_warning(_("Colorbar x location beyond page margins. Adjusting."));
	ct.x = PS.page_width - PS.right_marg - 1;
    }
    l = 72.0 * ct.x;

    G_debug(3, "corrected ct.x = %f ct.y = %f", ct.x, ct.y);

    r  = l + 72.0 * ct.width;
    col_width = ct.width / (double)ct.cols;
    
    /* Calc number of colors to print */
    width =  72.0 * ct.width;
    height =  72.0 * ct.height;
    cwidth = 0.1;
    ncols = (int) height / cwidth;
    step = (dmax - dmin) / (ncols - 1);
    lwidth = 0.02 * width;

    /* Print color band */
    y = t;
    x1 = l; 
    x2 = x1 + width;
    fprintf(PS.fp, "%.8f W\n", cwidth);
    for ( i = 0; i < ncols; i++ ) {
/*	val = dmin + i * step;   flip*/
        val = dmax - i * step;
	G_get_d_raster_color(&val, &R, &G, &B, &colors);

	if(do_color)
	    fprintf(PS.fp, "%.3f %.3f %.3f C\n", (double)R/255., (double)G/255., (double)B/255.);
	else {
	    grey_color_val = (.3 * (double)R + .59 * (double)G + .11 * (double)B)/255.;
	    fprintf(PS.fp, "%.3f setgray\n", grey_color_val);
	}

	fprintf(PS.fp, "NP\n");
        fprintf(PS.fp, "%f %f M\n", x1, y); 
        fprintf(PS.fp, "%f %f LN\n", x2, y); 
        fprintf(PS.fp, "D\n"); 
	y -= cwidth;
    }

    /* Frame around */
    fprintf(PS.fp, "NP\n");
    set_rgb_color ( ct.color ); 
    fprintf(PS.fp, "%.8f W\n", lwidth);
    fprintf(PS.fp, "%f %f %f %f B\n", x1, t-(ncols-1)*cwidth-(cwidth+lwidth)/2 , x2, t+(cwidth+lwidth)/2 );
    fprintf(PS.fp, "D\n"); 

    /* Print labels */
    /* maximum number of parts we can divide into */
    k = (ncols - 1) * cwidth / dy;
    /* step in values for labels */
    step = (dmax - dmin ) / k; 

    /* raw step - usually decimal number with many places, not nice */
    /* find nice step and first nice value for label: nice steps are 
     * 1, 2, 2.5 or 5 * 10^n,
     * we need nice step which is first >= raw step, we take each nice 
     * step and find 'n' and then compare differences */

    for ( i = 0; i < NNSTEP; i++ ) {
	/* smalest n for which nice step >= raw step */
        if ( nice_steps[i] <= step ) {
	    ex = 1;
	    while (  nice_steps[i] * ex < step ) ex *= 10;
	} else {
	    ex = 0.1;
	    while (  nice_steps[i] * ex > step ) ex *= 0.1;
	    ex *= 10;
	}
	if ( i == 0 || (nice_steps[i] * ex - step) < cur_d ) {
	    cur_step = i;
	    cur_d = nice_steps[i] * ex - step;
	    cur_ex = ex;
	}
    }
    step = nice_steps[cur_step] * cur_ex; 

    /* Nice first value: first multiple of step >= dmin */
    k = dmin / step ;
    val = k * step;
    if ( val < dmin ) val += step;
    
    x1 = l + width + 0.1; 
    if(ct.tickbar)    /* switch to draw tic all the way through bar */
	x2 = x1 - width;
    else
	x2 = x1 + 0.37 * width;

    /* do nice label: we need so many decimal places to hold all step decimal digits */	
    if ( step > 100 ) { /* nice steps do not have > 2 digits, important separate, otherwise */
	ddig = 0;       /* we can get something like 1000000.00000000765239 */
    } else { 
	sprintf (buf, "%.10f", step);
	k = strlen (buf) - 1;
	while ( buf[k] == '0' ) k--;
	k = k - (int) ( strchr( buf, '.') - (unsigned) buf );
	ddig = k;
    }

    fprintf(PS.fp, "%.8f W\n", lwidth);
    while ( val <= dmax ) {
/*      y = t - (val - dmin) * height / (dmax - dmin) ;  flip*/
        y = t - (dmax - val) * height / (dmax - dmin);
	fprintf(PS.fp, "NP\n");
        fprintf(PS.fp, "%f %f M\n", x1, y); 
        fprintf(PS.fp, "%f %f LN\n", x2, y); 
        fprintf(PS.fp, "D\n"); 
            
	sprintf (buf, "%f", val);
	ch = (char *) strchr (buf, '.');
	ch += ddig;
	if ( ddig > 0 ) ch++;
	*ch = '\0';

	if(ct.tickbar)    /* switch to draw tic all the way through bar */
	    fprintf(PS.fp, "(%s) %f %f MS\n", buf, x1 + 0.2 * fontsize , y - 0.35 * fontsize);
	else
	    fprintf(PS.fp, "(%s) %f %f MS\n", buf, x2 + 0.2 * fontsize , y - 0.35 * fontsize);

	val += step;
    }

    G_free_colors(&colors);
    
    if (verbose > 1) fprintf (stdout,"\n");

    return 0;
}

