#ifndef _KRCD_H
#define _KRCD_H
/* Keith Ross Crib Diagrams:
  width: 1127 height: 264 border: 2
   header: internal height: 73 cap-height: 30  (Helvetica Bold, 42 pixel for point size)
   body: internal height: 185 cap-height: 30 modifier-cap-height: 21 (Helvetica, 29)
   body-header: cap-height: 22 (Helvetica 30)
   body-footer: cap-height: 16
   figure-label: cap-height: 14 (Helvetica: 19)
  footer: height: 36 cap-height: 15 (Helvetica, 21)
*/

/* helvetica cap-height: 1469/2048 digit-height: 1426/2048  x-height: 1071/2048 */
/* Needs kerning: FPTY */

#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <libxml2/libxml/parser.h>
#include <libxml2/libxml/HTMLparser.h>

#ifndef true
# define true		1
# define false		0
# define forever	for (;;)
#endif

typedef struct krcd {
    char *header_left;	/* dance name */
    char *header_right;	/* dance type: 8x40 R */
    char *footer_left;	/* devisor, date, publication(s) */
    char *footer_right;	/* dance style: 3C/4C longwise set */
    struct krcd_box *boxes;

    xmlDocPtr doc;	/* We need a doc pointer to handle entities when looking at text nodes. Not sure why this isn't done at read in */
			/*  We don't want to keep around the original doc for */
			/*  the file, so we create a dummy one */

    int total_bars;
    int actual_line_cnt;

    /* metadata */
    time_t last_mod_time;
    time_t creation_time;
} KRCD;

struct krcd_bb {
    float minx,miny;
    float maxx,maxy;
};

typedef struct krcd_box {
    char *header;	/* Usually just numbers, sometimes with combining circles or squares (U+20DD, U+20DE) (0xE2, 0x83, 0x9D| 0xE2, 0x83, 0x9E), or crossed over mark (modifier x, U+2E3: 0xCB 0xA3 */
    		/* If multiple headers, separate by "|" */
		/* If one header, center it */
		/* If two, move first to left edge, second to right */
		/* If three, first: left, second: center, third: right */
		/* If n, first left, second: (total-width-header width)/(n-1) - header(1) width/2, ... */
    char *topnotes, *bottomnotes, *bottomnotes2;
    struct krcd_box *next;
    struct krcd_box *boxes;
    unsigned int line_break_after: 1;	/* User may force a line break with this */
    unsigned int drawDivider: 1;
    unsigned int fullDivider: 1;
    unsigned int dashedDivider: 1;
    unsigned int dottedDivider: 1;
    unsigned int endOfLine4:1;		/* line ends on a 4 bar boundary, not an 8 so we need to draw a dashed line */
    unsigned int startOfLine4:1;	/* line begins ... */

    unsigned int meanwhile: 1;
    unsigned int sequence: 1;

    /* If no children */
    int bars;
    char *text[4];
    char *modifier[4];
    char half[4];
    char *label;		/* Standard action, use this to look it up in dictionary */
    xmlNodePtr svg_description;	/* custom action, or what we got out of dictionary */
    struct krcd_bb bb;		/* Size of centered action (either svg, or text/modifiers or meanwhile subcomponents) */	
    int header_width;		/* Minimum header width */
    int header_gaps;		/* number of gaps between sub-headers */
    int topnotes_width;
    int topnotes_gaps;
    int bottomnotes_width;
    int bottomnotes_gaps;
    int meanwhile_subboxes;

    int min_width;
    int actual_width;
    int actual_x;		/* Upper left corner of box */
    int actual_y;
} KRCD_BOX;

enum style {
    st_main,
    st_modifier,
    st_footer,
    st_circle_label,
    st_box_header,
    st_box_notes,
    st_inactive,
    st_inactive_stroke,
    st_dashed,
    st_dotted,
    st_line,
    st_fat_line,

    st_filled,
    st_hidden,

    st_last,
    st_unknown = -1
};

#define BOX_MARGIN_MIN			10
#define MEANWHILE_MARGIN_MIN		7
#define HEADER_MARGIN_MIN		4
/*#define BOX_MARGIN_DESIRED		20*/
#define BETWEEN_TEXT_SPACING		10
#define BETWEEN_HEADER_SPACING_MIN	8

#define MAIN_WIDTH			1130
#define MAIN_HEADER_HEIGHT		65
#define MAIN_FOOTER_HEIGHT		35
#define MAIN_BOX_HEIGHT			200


 /* krcdLibrary */
extern void krcdLibraryOutputStyles(FILE *svgout);
extern xmlNodePtr krcdLibraryFindFigure(char *label);
extern void krcdLibraryAddFigure(char *label, xmlNodePtr value);
extern void krcdLibrarySaveOnExit(void);

 /* krcdSvg */
extern char *styleNames[];
/* Bug: svg interprets multiple spaces as one, but layouts don't */
extern xmlNodePtr krcdMassageString(xmlChar *str, enum style, int inactive,
	float x, float y, int lineno);
extern xmlNodePtr krcdMassageText(xmlDocPtr doc, xmlNodePtr text);
extern int krcdTextNeedsMassaging(xmlDocPtr doc, xmlNodePtr text);
extern void krcdSvgBB(xmlDocPtr doc, xmlNodePtr svg,struct krcd_bb *bb);
extern void krcdSvgListBB(xmlDocPtr doc, xmlNodePtr svg,struct krcd_bb *bb);
extern int krcdTextWidth(char *str, int len, enum style style, xmlDocPtr doc);
extern int krcdTextMainModKern(char *str);
extern int krcdTextMainModWidth(char *main, char *mod);
extern int krcdTextCapHeight(enum style style);

 /* krcdIO */
extern KRCD *krcdParseKrcd(xmlDocPtr doc, xmlNodePtr krcdNode, char *filename);
extern KRCD *krcdLoadFile(char *filename);
extern void krcdOutputIndent(FILE *output,int indent);
extern void krcdOutputNode(FILE *output,int indent, xmlDocPtr doc, xmlNodePtr node, int doMassage);
extern void krcdOutputKrcd(FILE *output, int indent, KRCD *krcd);
extern void krcdOutputFile(char *filename, KRCD *krcd);
extern void krcdFree(KRCD *krcd);

 /* krcdLayout */
extern void krcdLayout(KRCD *krcd);
extern void krcd2Svg(KRCD *krcd, FILE *svgout, char *svgfilename, int indent, int inline_styles );
#endif
