#if !defined(lint) && !defined(DOS)
static char rcsid[] = "$Id: color.c 769 2007-10-24 00:15:40Z hubert@u.washington.edu $";
#endif

/*
 * ========================================================================
 * Copyright 2013-2020 Eduardo Chappa
 * Copyright 2006-2007 University of Washington
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * ========================================================================
 */

#include "../pith/headers.h"
#include "../pith/color.h"
#include "../pith/state.h"
#include "../pith/conf.h"
#include "../pith/filter.h"


char *
color_embed(char *fg, char *bg)
{
    static char buf[(2 * RGBLEN) + 5], *p;

    p = buf;
    if(fg){
	if(sizeof(buf)-(p-buf) > 1){
	  *p++ = TAG_EMBED;
	  *p++ = TAG_FGCOLOR;
	}

	sstrncpy(&p, color_to_asciirgb(fg), sizeof(buf)-(p-buf));
    }

    if(bg){
	if(sizeof(buf)-(p-buf) > 1){
	  *p++ = TAG_EMBED;
	  *p++ = TAG_BGCOLOR;
	}

	sstrncpy(&p, color_to_asciirgb(bg), sizeof(buf)-(p-buf));
    }

    buf[sizeof(buf)-1] = '\0';

    return(buf);
}


int
colorcmp(char *color1, char *color2)
{
    if(color1 && color2)
      return(strcmp(color_to_asciirgb(color1), color_to_asciirgb(color2)));

    /* if both NULL they're the same? */
    return(!(color1 || color2));
}



struct quote_colors {
    COLOR_PAIR          *color;
    struct quote_colors *next;
};


int
color_a_quote(long int linenum, char *line, LT_INS_S **ins, void *is_flowed_msg)
{
    int countem = 0;
    struct variable *vars = ps_global->vars;
    char *p;
    struct quote_colors *colors = NULL, *cp, *next;
    COLOR_PAIR *col = NULL;
    int is_flowed = is_flowed_msg ? *((int *)is_flowed_msg) : 0;

    p = line;
    if(!is_flowed)
      while(isspace((unsigned char)*p))
	p++;

    if(p[0] == '>'){
	struct quote_colors *c;

	/*
	 * We have a fixed number of quote level colors (3). If there are
	 * more levels of quoting than are defined, they repeat.
	 */
	if(VAR_QUOTE1_FORE_COLOR && VAR_QUOTE1_BACK_COLOR &&
	   (col = new_color_pair(VAR_QUOTE1_FORE_COLOR,
				 VAR_QUOTE1_BACK_COLOR)) &&
	   pico_is_good_colorpair(col)){
	    c = (struct quote_colors *)fs_get(sizeof(*c));
	    memset(c, 0, sizeof(*c));
	    c->color = col;
	    col = NULL;
	    colors = c;
	    cp = c;
	    countem++;
	    if(VAR_QUOTE2_FORE_COLOR && VAR_QUOTE2_BACK_COLOR &&
	       (col = new_color_pair(VAR_QUOTE2_FORE_COLOR,
				     VAR_QUOTE2_BACK_COLOR)) &&
	       pico_is_good_colorpair(col)){
		c = (struct quote_colors *)fs_get(sizeof(*c));
		memset(c, 0, sizeof(*c));
		c->color = col;
		col = NULL;
		cp->next = c;
		cp = c;
		countem++;
		if(VAR_QUOTE3_FORE_COLOR && VAR_QUOTE3_BACK_COLOR &&
		   (col = new_color_pair(VAR_QUOTE3_FORE_COLOR,
					 VAR_QUOTE3_BACK_COLOR)) &&
		   pico_is_good_colorpair(col)){
		    c = (struct quote_colors *)fs_get(sizeof(*cp));
		    memset(c, 0, sizeof(*c));
		    c->color = col;
		    col = NULL;
		    cp->next = c;
		    cp = c;
		    countem++;
		}
	    }
	}
    }

    if(col)
      free_color_pair(&col);

    cp = NULL;
    while(*p == '>'){
	cp = (cp && cp->next) ? cp->next : colors;

	if(countem > 0)
	  ins = gf_line_test_new_ins(ins, p,
				     color_embed(cp->color->fg, cp->color->bg),
				     (2 * RGBLEN) + 4);

	countem = (countem == 1) ? 0 : countem;

	p++;
	if(!is_flowed)
	  for(; isspace((unsigned char)*p); p++)
	    ;
    }

    if(colors){
	char fg[RGBLEN + 1], bg[RGBLEN + 1], rgbbuf[RGBLEN + 1];

	strncpy(fg, color_to_asciirgb(VAR_NORM_FORE_COLOR), sizeof(fg));
	strncpy(bg, color_to_asciirgb(VAR_NORM_BACK_COLOR), sizeof(bg));
	fg[sizeof(fg)-1] = '\0';
	bg[sizeof(bg)-1] = '\0';

	/*
	 * Loop watching colors, and override with most recent
	 * quote color whenever the normal foreground and background
	 * colors are in force.
	 */
	while(*p)
	  if(*p++ == TAG_EMBED){

	      switch(*p++){
		case TAG_HANDLE :
		  p += *p + 1;	/* skip handle key */
		  break;

		case TAG_FGCOLOR :
		  snprintf(rgbbuf, sizeof(rgbbuf), "%s", p);
		  p += RGBLEN;	/* advance past color value */
		  
		  if(!colorcmp(rgbbuf, VAR_NORM_FORE_COLOR)
		     && !colorcmp(bg, VAR_NORM_BACK_COLOR))
		    ins = gf_line_test_new_ins(ins, p,
					       color_embed(cp->color->fg,NULL),
					       RGBLEN + 2);
		  break;

		case TAG_BGCOLOR :
		  snprintf(rgbbuf, sizeof(rgbbuf), "%s", p);
		  p += RGBLEN;	/* advance past color value */
		  
		  if(!colorcmp(rgbbuf, VAR_NORM_BACK_COLOR)
		     && !colorcmp(fg, VAR_NORM_FORE_COLOR))
		    ins = gf_line_test_new_ins(ins, p,
					       color_embed(NULL,cp->color->bg),
					       RGBLEN + 2);

		  break;

		default :
		  break;
	      }
	  }

	ins = gf_line_test_new_ins(ins, line + strlen(line),
				   color_embed(VAR_NORM_FORE_COLOR,
					       VAR_NORM_BACK_COLOR),
				   (2 * RGBLEN) + 4);
	for(cp = colors; cp && cp->color; cp = next){
	    free_color_pair(&cp->color);
	    next = cp->next;
	    fs_give((void **)&cp);
	}
    }

    return(0);
}


void
free_spec_colors(SPEC_COLOR_S **colors)
{
    if(colors && *colors){
	free_spec_colors(&(*colors)->next);
	if((*colors)->spec)
	  fs_give((void **)&(*colors)->spec);
	if((*colors)->fg)
	  fs_give((void **)&(*colors)->fg);
	if((*colors)->bg)
	  fs_give((void **)&(*colors)->bg);
	if((*colors)->val)
	  free_pattern(&(*colors)->val);
	
	fs_give((void **)colors);
    }
}
