#include "krcd.h"
#include <libxml/HTMLtree.h>
#include <unistd.h>

static htmlDocPtr	krcdLibrary	= NULL;
static xmlNodePtr	krcdLibraryDl	= NULL;
static int krcdLibraryModified = false;

void krcdLibraryOutputStyles(FILE *svgout) {

    fprintf( svgout, " text { font-family: Helvetica, Ariel, sans-serif; fill: black; stroke: none; }\n" );
    fprintf( svgout, " .main { font-weight: bold; font-size: 42px; }\n" );
    fprintf( svgout, " .modifier { font-size: 30px; }\n" );
    fprintf( svgout, " .footer { font-size: 21px; }\n" );
    fprintf( svgout, " .circle-label { font-weight: bold; font-size: 30px; }\n" );
    fprintf( svgout, " .box-header { font-size: 25px; }\n" );
    fprintf( svgout, " .notes { font-size: 19px; }\n" );
    fprintf( svgout, " .dashed { stroke-dasharray: 9px 6px; stroke-width: 2px ; stroke: black; fill: none; }\n" );
    fprintf( svgout, " .dotted { stroke-dasharray: 4px 7px; stroke-width: 2px ; stroke: black; fill: none; }\n" );
    fprintf( svgout, " .line { stroke-width: 2px; stroke: black; fill: none; }\n" );
    fprintf( svgout, " .fat-line { stroke-width: 4px; stroke: black; fill: none; }\n" );
    fprintf( svgout, " .filled { fill: black; stroke; none }\n" );
    fprintf( svgout, " .hidden { fill: none; stroke; none }\n" );
}

static void krcdLibraryCreate() {
    xmlNodePtr html, head, body, temp;

    krcdLibrary = htmlNewDoc(NULL,NULL);
    html = xmlNewNode(NULL,(xmlChar *)"html");
    xmlDocSetRootElement(krcdLibrary,html);
    head = xmlNewNode(NULL,(xmlChar *)"head");
    xmlAddChild(html,head);
    temp = xmlNewNode(NULL,(xmlChar *)"meta");
    xmlNewProp(temp,(xmlChar *) "charset",(xmlChar *) "UTF-8");
    xmlAddChild(head,temp);
    temp = xmlNewNode(NULL,(xmlChar *)"link");
    xmlNewProp(temp,(xmlChar *) "rel",(xmlChar *) "stylesheet");
    xmlNewProp(temp,(xmlChar *) "href",(xmlChar *) "krcd.css");
    xmlNewProp(temp,(xmlChar *) "type",(xmlChar *) "text/css");
    xmlAddChild(head,temp);
    
    body = xmlNewNode(NULL,(xmlChar *)"body");
    xmlAddChild(html,body);
    krcdLibraryDl = xmlNewNode(NULL,(xmlChar *)"dl");
    xmlAddChild(body,krcdLibraryDl);
}

static void krcdLoadLibrary() {
    static int tried_to_load=false;

    if ( krcdLibrary!=NULL )
return;

    /* I need PARSE_RECOVER because otherwise the parse objects to <svg and its children */
    krcdLibrary = htmlReadFile("krcd-library.html", NULL, HTML_PARSE_NONET | HTML_PARSE_COMPACT | HTML_PARSE_RECOVER | HTML_PARSE_NOERROR );
    if ( krcdLibrary==NULL && !tried_to_load )
	krcdLibraryCreate();
    if ( access("krcd.css",F_OK)== -1 ) {
	FILE *styles = fopen( "krcd.css","w" );
	if ( styles!=NULL ) {
	    krcdLibraryOutputStyles(styles);
	    fclose(styles);
	}
    }

    if ( krcdLibrary==NULL && !tried_to_load )
	fprintf( stderr, "krcd-library.html: No library file found\n" );
    else {
	xmlNodePtr root = xmlDocGetRootElement(krcdLibrary);
	xmlNodePtr child, body=NULL, dl=NULL;
	if ( root!=NULL ) {
	    for ( child=root->children; child!=NULL; child=child->next ) {
		if ( child->type == XML_ELEMENT_NODE && xmlStrcmp(child->name,(xmlChar *) "body")==0 ) {
		    body = child;
	    break;
		}
	    }
	}
	if ( body!=NULL ) {
	    for ( child=body->children; child!=NULL; child=child->next ) {
		if ( child->type == XML_ELEMENT_NODE && xmlStrcmp(child->name,(xmlChar *) "dl")==0 ) {
		    dl = child;
	    break;
		}
	    }
	}
	if ( dl==NULL )
	    fprintf( stderr, "Expected to find a <dl> node inside the <body> node inside the <html> node of krcd-library.html\n" );
	else
	    krcdLibraryDl = dl;
    }
    
    tried_to_load= true;
}

static int textContentMatches(xmlNodePtr node,char *text ) {
    xmlChar *str = xmlNodeListGetString(krcdLibrary,node->children, 1);
    xmlChar *pt, *ept;
    int ret;

    for ( pt=str; isspace(*pt); ++pt )
	;
    for ( ept=str+xmlStrlen(str)-1; isspace(*ept); --ept )
	;
    ept[1]='\0';

    ret = xmlStrcmp(pt,(xmlChar *)text)==0;
    free(str);
return( ret );
}

xmlNodePtr krcdLibraryFindFigure(char *label) {
    xmlNodePtr child, dt=NULL, dd;

    krcdLoadLibrary();

    if ( krcdLibraryDl==NULL )
return( NULL );

    for ( child=krcdLibraryDl->children; child!=NULL; child=child->next ) {
	if ( child->type == XML_ELEMENT_NODE &&
		xmlStrcmp(child->name,(xmlChar *) "dt")==0 &&
		textContentMatches(child,label) ) {
	    dt = child;
    break;
	}
    }
    if ( dt!=NULL ) {
	/* Look for the dd which follows this dt */
	for ( child=dt->next; child!=NULL; child=child->next ) {
	    if ( child->type == XML_ELEMENT_NODE &&
		    xmlStrcmp(child->name,(xmlChar *) "dt")==0 ) {
		/* Hmm. two <dt>s in a row? that shouldn't happen */
		fprintf( stderr, "Bad format, two <dt>s in a row in krcd-library.html.\n" );
return( NULL );
	    } else if ( child->type == XML_ELEMENT_NODE &&
		    xmlStrcmp(child->name,(xmlChar *) "dd")==0 ) {
		dd = child;
		for ( child=dd->children; child!=NULL; child=child->next ) {
		    if ( child->type == XML_ELEMENT_NODE &&
			      xmlStrcmp(child->name,(xmlChar *) "svg")==0 ) {
return( xmlCopyNodeList( child->children ));
		    }
		}
		fprintf( stderr, "Bad format, no <svg> or <g> element in <dd> in krcd-library.html.\n" );
return( NULL );
	    }
	}
    }
return( NULL );
}
    
void krcdLibraryAddFigure(char *label, xmlNodePtr value) {
    xmlNodePtr dt, dd, text;
    char buffer[300];
    struct krcd_bb bb;

    if ( krcdLibraryFindFigure(label)!=NULL )
return;

    dt = xmlNewNode(NULL,(xmlChar *) "dt");
    text = xmlNewText((xmlChar *) label);
    xmlAddChild(dt,text);
    dd = xmlNewNode(NULL,(xmlChar *)"dd");
    /* value = xmlCopyNode(value,1);		/* AddChildList does this */
    if ( value->type != XML_ELEMENT_NODE ||
	      xmlStrcmp(value->name,(xmlChar *) "svg")!=0 ) {
	xmlNodePtr temp = xmlNewNode(NULL,(xmlChar *)"svg");
	xmlNewProp(temp,(xmlChar *) "xmlns",(xmlChar *) "http://www.w3.org/2000/svg");
	krcdSvgListBB(krcdLibrary,value,&bb);
	sprintf( buffer, "%.0f %.0f %.0f %.0f", bb.minx-2, bb.miny-2, bb.maxx-bb.minx+4, bb.maxy-bb.miny+10 );
	xmlNewProp(temp,(xmlChar *) "viewBox", (xmlChar *) buffer );
	sprintf( buffer, "width: %.0fpx; height: %.0fpx;", bb.maxx-bb.minx+4, bb.maxy-bb.miny+10 );
	xmlNewProp(temp,(xmlChar *) "style", (xmlChar *) buffer );
	
	xmlAddChildList(temp,value);
	value = temp;
    }
    xmlAddChildList(dd,value);

    xmlAddChild(krcdLibraryDl,dt);
    xmlAddChild(krcdLibraryDl,dd);
    xmlAddChild(krcdLibraryDl,xmlNewText((xmlChar *) "\n"));
    krcdLibraryModified = true;
}

void krcdLibrarySaveOnExit() {
    if ( krcdLibraryModified )
	xmlSaveFormatFile("krcd-library.html",krcdLibrary,1);
    krcdLibraryModified = false;
}

#if 0
int main(int argc, char **argv) {
    xmlNodePtr test;
    
    test = xmlNewNode(NULL,(xmlChar *)"g");

    krcdLibraryAddFigure("test", test);
    krcdLibraryAddFigure("test2", test);
    krcdLibraryAddFigure("test3", test);
    krcdLibraryAddFigure("test", test);
    krcdLibrarySaveOnExit();
return( 0 );
}
#endif
