/* Function: vect_legend
 **
 ** Author: Paul W. Carlson     April 1992
 ** Modified by: Radim Blazek Jan 2000 area, label added 
 ** Modified by: Morten Hulden Mar 2004, support for legend in columns added 
 */

#include "vector.h"
#include "local_proto.h"

int PS_vlegend(void)
{
    int h, i, j, k, l, lc, st, lcount, nopos;
    double x, y, fontsize, dx, dy, xo, yo, xs, ys, margin, width;
    double llx, lly, urx, ury, sc;
    char pat[50];
    int **vec, *nvec;

    G_debug(2, "vect_legend(): count = %d", vector.count);

    vec = (int **)G_malloc(vector.count * sizeof(int *));
    for (i = 0; i < vector.count; i++)
	vec[i] = (int *)G_malloc(vector.count * sizeof(int));
    nvec = (int *)G_malloc(vector.count * sizeof(int));

    /* vec[][] is array of vectors on each row of legend, first to be drawn is first in array,
     *         label is stored in last in row (last plotted, first in the script)
     * nvec[] is number of vector on each row 
     *        index for both start at 0, lpos in script starts from 1
     * If position is not used by any vector it is used for next not used vector without
     * lpos or lpos > vector.count */

    nopos = -1;			/* last used without position in script or position > count */

    for (l = 0; l < vector.count; l++) {
	nvec[l] = 0;
	for (i = vector.count - 1; i >= 0; i--) {	/* last in script plot first */
	    if (vector.layer[i].lpos == l + 1) {
		vec[l][nvec[l]] = i;
		nvec[l]++;
	    }
	}
	if (nvec[l] == 0) {	/* no vector with this lpos */
	    for (i = nopos + 1; i < vector.count; i++) {
		/* first in script (most important) in script plot first */
		if (vector.layer[i].lpos == -1 ||
		    vector.layer[i].lpos > vector.count) {
		    vec[l][0] = i;
		    nvec[l]++;
		    nopos = i;
		    break;
		}
	    }
	}
    }

    /* find last used row */
    lcount = 0;			/* number of used rows in legend */
    for (i = vector.count - 1; i >= 0; i--) {
	if (nvec[i] > 0) {
	    lcount = i + 1;
	    break;
	}
    }

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

    /* get text location */
    dy = 1.5 * fontsize;

    if (vector.x > 0.0)
	x = 72.0 * vector.x;
    else
	x = PS.map_left;

    if (vector.y > 0.0)
	y = 72.0 * (PS.page_height - vector.y);
    else if (vector.x <= 0.0)
	y = PS.min_y;
    else
	y = PS.map_bot;

    margin = 0.4 * fontsize;

    if (x < PS.left_marg*72 + margin)
	x = PS.left_marg*72 + margin;

    if (lcount < vector.cols)
	vector.cols = lcount;

    if(vector.span < 0)
	dx = (PS.map_right - x) / vector.cols;
	/* dx = ((PS.page_width-PS.right_marg)*72 - x) / vector.cols; */
    else
	dx = vector.span*72;

    xs = x;			/*save x and y */
    ys = y;
    lc = (int)lcount / vector.cols;	/* lines per column */

    if (lcount % vector.cols)
	lc++;

    for (h = 0; h < vector.cols; h++) {

	y = ys;
	if (h)
	    x += dx;
	st = ((h + 1) * lc < lcount) ? ((h + 1) * lc) : lcount;

	/* make PostScript array "a" of name-mapset strings */
	fprintf(PS.fp, "/a [\n");

	for (i = h * lc; i < st; i++) {
	    G_debug(4, "  row = %d", i);
	    if (nvec[i] > 0) {	/* used position */
		j = vec[i][nvec[i] - 1];	/* vector with label */
		if (vector.layer[j].label == NULL)
		    fprintf(PS.fp, "( %s (%s))\n", vector.layer[j].name,
			    vector.layer[j].mapset);
		else
		    fprintf(PS.fp, "( %s)\n", vector.layer[j].label);
	    }
	    else {		/* not used -> empty string */
		fprintf(PS.fp, "( )\n");
	    }
	}
	fprintf(PS.fp, "] def\n");

	width = 72.0 * vector.width;
	if (width <= 0.0)
	    width = 2.4 * fontsize;

	/* HB 2006: always figure width & draw so the border will always work. */
	/* if vector legend is on map... */
	/*      if (y > PS.map_bot && y <= PS.map_top && x < PS.map_right) {   */
	fprintf(PS.fp, "/mg %.1f def\n", margin);

	/* get width of widest string in PostScript variable "w" */
	fprintf(PS.fp, "/w 0 def 0 1 a length 1 sub { /i XD\n");
	fprintf(PS.fp, "a i get SW pop /t XD t w gt {/w t def} if } for\n");
	fprintf(PS.fp, "/w w %.1f add mg add %.1f add def\n", x, width);

	/* make white background for text */
	fprintf(PS.fp, "1 1 1 C ");
	fprintf(PS.fp, "%.1f %.1f w %.1f B fill \n",
		x - margin, y - lc * dy - margin, y);
	/*      } */

	/* draw the border, if set */
	if (! color_none(&vector.border)) {
	    set_ps_color(&vector.border);

	    fprintf(PS.fp, "%.1f %.1f w %.1f B\n",
		    x - margin, y - lc * dy - margin, y);
	    fprintf(PS.fp, "D\n");
	}

	/* make the legend */
	for (j = h * lc; j < st; j++) {	/* each row */
	    G_debug(4, "  row = %d", j);
	    y -= dy;		/* set position of next row */
	    for (k = 0; k < nvec[j]; k++) {
		i = vec[j][k];

		/* make a grey box if needed */
		/* TODO */
		/*
		   if ((vector.layer[i].hwidth > 0. && vector.layer[i].hcolor == WHITE) ||
		   (vector.layer[i].hwidth < 1. && vector.layer[i].colors[0]  == WHITE))
		   {
		   fprintf(PS.fp, "0.5 setgray ");
		   fprintf(PS.fp, "%.1f %.1f %.1f %.1f B fill \n", 
		   x, y, x + 72.0, y + fontsize);
		   }
		 */

		if (vector.layer[i].type == VAREAS) {	/* added for areas */
		    /* plot rectangle */
		    yo = y - 0.1 * fontsize;

		    if (vector.layer[i].pat != NULL ||
			!(color_none(&vector.layer[i].fcolor))) {

			if (vector.layer[i].pat != NULL) {	/* use pattern */
			    sc = 0.5 * vector.layer[i].scale;	/* half scale */

			    /* load pattern */
			    eps_bbox(vector.layer[i].pat, &llx, &lly, &urx,
				     &ury);
			    sprintf(pat, "APATTEPS%d", i);
			    pat_save(PS.fp, vector.layer[i].pat, pat);

			    fprintf(PS.fp,
				    "<<  /PatternType 1\n    /PaintType 1\n    /TilingType 1\n");
			    fprintf(PS.fp, "    /BBox [%f %f %f %f]\n",
				    llx * sc, lly * sc, urx * sc, ury * sc);
			    fprintf(PS.fp, "    /XStep %f\n    /YStep %f\n",
				    (urx - llx) * sc, (ury - lly) * sc);
			    fprintf(PS.fp, "    /PaintProc\n      { begin\n");
			    fprintf(PS.fp, "        %f %f scale\n", sc, sc);
			    set_ps_color(&(vector.layer[i].fcolor));
			    fprintf(PS.fp, "        %.8f W\n",
				    vector.layer[i].pwidth);
			    fprintf(PS.fp, "        %s\n", pat);
			    fprintf(PS.fp, "        end\n");
			    fprintf(PS.fp, "      } bind\n>>\n");
			    sprintf(pat, "APATT%d", i);
			    fprintf(PS.fp,
				    " matrix\n makepattern /%s exch def\n",
				    pat);
			    fprintf(PS.fp,
				    "/Pattern setcolorspace\n %s setcolor\n",
				    pat);
			}
			else	/* solid fill color */
			    set_ps_color(&(vector.layer[i].fcolor));

			fprintf(PS.fp, "%.1f %.1f %.1f %.1f rectfill\n",
				x + width / 5, yo, 3 * width / 5,
				0.8 * fontsize);
		    }
		    if (!color_none(&vector.layer[i].color) &&
			vector.layer[i].width > 0) {
			fprintf(PS.fp, "%.8f W\n", vector.layer[i].width);
			set_ps_color(&(vector.layer[i].color));
			fprintf(PS.fp, "[] 0 setdash\n");
			fprintf(PS.fp, "%.1f %.1f %.1f %.1f rectstroke\n",
				x + width / 5, yo, 3 * width / 5,
				0.8 * fontsize);
		    }
		}
		else if (vector.layer[i].type == VLINES) {
		    yo = y + 0.35 * fontsize - vector.layer[i].offset;
		    /* do highlight, if any */
		    if (vector.layer[i].hwidth) {
			set_ps_color(&(vector.layer[i].hcolor));
			fprintf(PS.fp, "%.8f W\n",
				vector.layer[i].width +
				2 * vector.layer[i].hwidth);
			fprintf(PS.fp, "[] 0 setdash\n");
			fprintf(PS.fp, "%.1f %.1f %.1f %.1f L\n", x + width,
				yo, x, yo);
		    }

		    /* plot the primary color line */
		    set_ps_color(&(vector.layer[i].color));
		    fprintf(PS.fp, "%.8f W\n", vector.layer[i].width);
		    fprintf(PS.fp, "%s setdash\n", vector.layer[i].setdash);
		    fprintf(PS.fp, "%.1f %.1f %.1f %.1f L\n", x + width, yo,
			    x, yo);
		}
		else if (vector.layer[i].type == VPOINTS) {
		    /* TODO */
		    yo = y + 0.5 * fontsize - vector.layer[i].offset;
		    xo = x + width / 2;
		    symbol_draw(vector.layer[i].symbol_ps, xo, yo,
				vector.layer[i].size, vector.layer[i].rotate,
				vector.layer[i].width);
		}

	    }

	    /* plot the text */
	    set_rgb_color(BLACK);
	    fprintf(PS.fp, "a %d get %.1f %.1f MS\n",
			j - h * lc, x + width, y);
	}
    }	/* h */

    x = xs;
    y = ys - lc * dy;

    fprintf(PS.fp, "[] 0 setdash\n");

    if (PS.min_y > y)
	PS.min_y = y;

    return 0;
}
