/**********************************************************************
 
	Copyright (C) 2003 Hirohisa MORI <joshua@nichibun.ac.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	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.

**********************************************************************/

#include "avt.h" /* er_panic */
#include "utils.h" /* nl_copy_str */
#include "svgtypes.h"
#include "svgfuncs.h"
#include <stdlib.h>
#include <string.h>
#include	"memory_debug.h"

SVG_COLOR SVG_RGB(unsigned char r, unsigned char g, unsigned char b){
	SVG_COLOR cl;
	cl.r = r;
	cl.g = g;
	cl.b = b;
	cl.a = 255;
	return cl;
}

SVG_COLOR SVG_RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a){
	SVG_COLOR cl;
	cl.r = r;
	cl.g = g;
	cl.b = b;
	cl.a = a;
	return cl;
}

static L_CHAR *l_strchr(L_CHAR *string, L_CHAR ch)
{
	for(;*string;++string){
		if(*string == ch)
			return string;
	}
	return 0;
}

static SVG_FLOAT svg_read_float(char **pp){
	SVG_FLOAT f = (SVG_FLOAT)atof(*pp);
	*pp += 1;
	*pp += strspn(*pp, "0123456789.");
	if(**pp==' '||**pp==',')
		++(*pp);
	return f;
}


SVG_STYLE *svg_make_style(L_CHAR *name, L_CHAR *value)
{
SVG_STYLE *ret;
	ret = calloc(sizeof(SVG_STYLE),1);
	ret->name = (L_CHAR*)malloc((l_strlen(name)+1)*sizeof(L_CHAR));
	ret->value = (L_CHAR*)malloc((l_strlen(value)+1)*sizeof(L_CHAR));
	l_strcpy(ret->name, name);
	l_strcpy(ret->value, value);
	return ret;
}

void svg_free_style(SVG_STYLE *style)
{
	free(style->name);
	free(style->value);
	free(style);
}

SVG_TRANSFORM_INFO *svg_make_transform()
{
	SVG_TRANSFORM_INFO *t = calloc(sizeof(SVG_TRANSFORM_INFO),1);
	t->x_scale = 1;
	t->y_scale = 1;
	return t;
}

void svg_free_transform(SVG_TRANSFORM_INFO *trans)
{
	free(trans);
}

SVG_LAYER *svg_make_layer(L_CHAR *id){
SVG_LAYER *ret;

	ret = (SVG_LAYER *)calloc(sizeof(SVG_LAYER),1);
	ret->id = ll_copy_str(id,1234); 
	return ret;
}

void svg_free_layer(SVG_LAYER *layer){
SVG_STYLE *s;
SVG_TRANSFORM_INFO *t;
int i;
	for(i=0; i<layer->child_count; ++i){
		svg_free_layer(layer->children[i]);
	}
	for(s=layer->styles; s; ){
		SVG_STYLE *tmp;
		tmp= s->next;
		svg_free_style(s);
		s = tmp;
	}
	for(t=layer->transform; t; ){
		SVG_TRANSFORM_INFO *tmp;
		tmp = t->next;
		svg_free_transform(t);
		t = tmp;
	}
	
	free(layer->children);
	free(layer);
}

SVG_LAYER *svg_find_layer(SVG_LAYER *src, L_CHAR* id)
{
	int i;
	SVG_LAYER *ret=0;
	if(l_strcmp(src->id, id) == 0){
		return src;
	}
	for(i=0; i<src->child_count; ++i){
		ret=svg_find_layer(src->children[i], id);
		if(ret)
			break;
	}
	return 0;
}

void svg_add_child_layer(SVG_LAYER *parent, SVG_LAYER *child)
{
	if(parent->child_buff_size <=parent->child_count){
		int new_count = parent->child_count*2;
		if(new_count==0)
			new_count = 8;
		parent->children = realloc(parent->children, sizeof(SVG_LAYER*)*new_count);
		parent->child_buff_size = new_count;
	}
	parent->children[parent->child_count] = child;
	parent->child_count++;
	child->parent = parent;
}

SVG_STYLE *svg_str2style(L_CHAR *str)
{
SVG_STYLE *ret;
char *begin=n_string(std_cm, str);
char *end;
char *p;
L_CHAR *name;
L_CHAR *value;
SVG_STYLE *tmp;
char *pos;
	ret = NULL;
/* fill-rule:nonzero;clip-rule:nonzero;fill:#00FFFF;stroke:#D32020;stroke-miterlimit:4; */
	begin+=strspn(begin, " \t\r\n");
	p = begin;
	
	/* split by ';' */
	for(;*p;++p){
		if(*p == ';')
			*p='\0';
	}
	end = p;
	
	for(p=begin; p<end; p+=strlen(p)+1){
		pos = strchr(p, ':');
		if(pos){
			p[pos-p] = '\0';
			name = nl_copy_str(std_cm, p);
			p = pos + 1;
			value = nl_copy_str(std_cm, p);
		}
		else{
			name = nl_copy_str(std_cm, p);
		}
		tmp = svg_make_style(name, value);
		tmp->next = ret;
		ret = tmp;
	}
	
	return ret;
}

SVG_TRANSFORM_INFO *svg_str2transform(L_CHAR *str)
{
SVG_TRANSFORM_INFO *ret=NULL;
SVG_TRANSFORM_INFO *trans=NULL;
static const char *tbl[] = {"translate", "scale", "rotate", "skewX", "skewY", "matrix"};
int i;
char *b,*e;
int src_len;
char *src;
	src = copy_str(n_string(std_cm, str));
	src_len = strlen(src);
	
	b = src;
	while(b < src+src_len){
		for(i=0;i<sizeof(tbl)/sizeof(char*);++i){
			if(strncmp(b, tbl[i], strlen(tbl[i]))){
				if(i == sizeof(tbl)/sizeof(char*)-1){
					/* no mutch */
er_panic("stop");
					goto exit;
				}
				continue;
			}

			b = strchr(b+strlen(tbl[i]), '(');
			if(!b)
				goto exit;
			++b;
			e = strchr(b, ')');
			if(!e)
				goto exit;
			trans = svg_make_transform();
			trans->next = ret;
			ret = trans;
			switch(i){
			case 0: /* translate */
				trans->x_translate = svg_read_float(&b);
				trans->y_translate = (b==e) ? trans->x_translate : svg_read_float(&b);
				break;
			case 1: /* scale */
				trans->x_scale = svg_read_float(&b);
				trans->y_scale = (b==e) ? trans->x_scale : svg_read_float(&b);
				break;
			case 2: /* rotate */
				trans->rotate_angle = svg_read_float(&b);
				trans->rotate_cx = (b==e) ? 0 : svg_read_float(&b);
				trans->rotate_cy = (b==e) ? 0 : svg_read_float(&b);
				break;
			case 3: /* "skewX" */
				trans->x_skew = svg_read_float(&b);
				break;
			case 4: /* "skewY" */
				trans->y_skew = svg_read_float(&b);
				break;
			case 5: /* matrix */
				trans->x_scale = svg_read_float(&b);
				trans->y_skew = svg_read_float(&b);
				trans->x_skew = svg_read_float(&b);
				trans->y_scale = svg_read_float(&b);
				trans->x_translate = svg_read_float(&b);
				trans->y_translate = svg_read_float(&b);
			}
			b = e+1+strspn(e+1, " \t");
			break;
		}
	}
exit:
	d_f_ree(src);
	return ret;
}

/* translate string to SVG_COLOR */
typedef struct svg_color_name_trans_table{
	const char *str;
	unsigned char r;
	unsigned char g;
	unsigned char b;
	unsigned char a;
}SVG_COLOR_NAME_TRANS_TABLE;
SVG_COLOR str2svg_color(const char *str){
	const char *p = str;
	SVG_BYTE r,g,b;
	
	if(*p == '#'){
		char cl[3];
		memset(cl,0,sizeof(cl));
		strncpy(cl, ++p, 2);
		r = (SVG_BYTE)strtol(cl,NULL,16);
		p+=2;
		strncpy(cl, p, 2);
		g = (SVG_BYTE)strtol(cl,NULL,16);
		p+=2;
		strncpy(cl, p, 2);
		b = (SVG_BYTE)strtol(cl,NULL,16);
		return SVG_RGB(r,g,b);
	}
	/* named color */
	else{
		static const int defined_color_count=4;
		static const SVG_COLOR_NAME_TRANS_TABLE tbl[] = 
		{
			{"none",    0,   0,   0, 0},
			{"red",   255,   0,   0, 255},
			{"green",    0, 255,   0, 255},
			{"blue",    0,   0, 255, 255}
		};
		int i=0;
		for(i=0;i<defined_color_count;++i){
			if(!strcmp(tbl[i].str, p)){
				return SVG_RGBA(tbl[i].r, tbl[i].g, tbl[i].b, tbl[i].a);
			}
		}
		return SVG_DEFAULT_FILL;
	}
}

L_CHAR *svg_find_style(SVG_STYLE *style, L_CHAR *key)
{
	for(; style; style=style->next){
		if(l_strcmp(style->name, key) == 0){
			return style->value;
		}
	}
	return NULL;
}

L_CHAR *svg_find_style_from_layer(SVG_LAYER *layer, L_CHAR *key)
{
L_CHAR *ret=NULL;
	for(; layer&&!ret; layer = layer->parent){
		ret = svg_find_style(layer->styles, key);
	}
	return ret;
}
