#usage "<b>Eagle schematic exporting tool  version 1.2 </b>\n"
       "<p>"
       "This ULP can convert an Eagle CAD schematics into SVG files."
       "<p>"
       "Load any schematic and execute the ULP in the eagle."
       "<p>"
	   "For drill holes to show up correctly enable DRILLS layer, and set its color to white (light gray)"
       "<p>"
	   "For dimensions to show up correctly change its color to anything but white (light gray), and set its wire width to non-zero."
       "<p>"
       "<author>Author: xTitoris</author><br>"
       "based on eagle2svg by nils.springob@nicai-systems.de<br>"
       "<br>"
       "Known issues in board export:<ul>"
       "<li>elongated pads are not supported"
       "<li>non vector-text is not rotated correctly"
	   "<li>layers are not placed correctly"
       "</ul>"
       
real VERSION   = 1.2;

/*
 * CHANGELOG================================================
 *
 * 1.2 (29.11.2010): Fixed drill holes, optimized stylesheet generation
 * 1.1 (??.04.2008): SVG export for board files      
 * 1.0 (16.04.2008): Some bugfixes      
 * 0.2 (11.04.2008): Using CSS for layer-styles      
 * 0.1 (08.03.2008): Initial version    
 *
 */  

/* ==========================================================================
 * License: This file is released under the license of the GNU Public license
 *          Version 2.
 * ==========================================================================*/  


int g_monochrome = 0;
int g_only_visible = 1;
int g_used_layers[];


//------------------------------------------------------
// generate html color code  
//------------------------------------------------------
string htmlcolor(int col)
{
	string result;
	sprintf(result, "#%06x", col);
	return result;
}


//------------------------------------------------------
// replace xml reserved chars and build 2-byte utf-8 characters  
//------------------------------------------------------
string encodeText(string strText)
{
	string newText = "";
	int i=0;

	while (strText[i])
	{
		char c = strText[i++];
		switch(c)
		{
		case '<': newText += "&lt;"; break; 
		case '>': newText += "&gt;"; break;
		case '&': newText += "&amp;"; break;
		default:
			if (c>=0xc0)
			{
				newText += char(0xc3);
				newText += char(c-0x40);
			}
			else if (c>=0x80)
			{
				newText += char(0xc2);
				newText += char(c);
			}
			else
			{
				newText += c;
			}
		}
	}
	return newText;
}

//------------------------------------------------------
// SVG output functions
//------------------------------------------------------

string svgLineStyle(int width, int cap)
{
	string lineCap="round";

	switch (cap)
	{
	case CAP_FLAT: lineCap = "butt"; break;
	case CAP_ROUND: lineCap = "round"; break;
	default: lineCap = "round"; break;
	}

	string style;
	sprintf(style, "stroke-width:%f; stroke-linecap:%s",
	u2mm(width), lineCap);
	return style;    
}

string svgTransform(int x, int y, real angle)
{
	string trans, rot, res;
	sprintf(trans, "translate(%f,%f)", u2mm(x), u2mm(-y));
	sprintf(rot, "rotate(%f)", -angle);
	return "transform='"+trans+" "+rot+"'";
}

void svgWriteLine(int x1, int y1, int x2, int y2, int layer, string style)
{
	printf("<line class='l%d' x1='%f' y1='%f' x2='%f' y2='%f' style='%s'/>\n",
	layer,
	u2mm(x1), u2mm(-y1), 
	u2mm(x2), u2mm(-y2),
	style);
}

void svgWriteArc(int x1, int y1, int x2, int y2, int radius, char longpath, int layer, string style)
{
	printf("<path class='l%d' d='M %f,%f A %f %f 0 %c 0 %f,%f' style='%s'/>\n",
	layer,
	u2mm(x1), u2mm(-y1),
	u2mm(radius), u2mm(radius),
	longpath,
	u2mm(x2), u2mm(-y2),
	style);
}

void svgWriteRect(int x1, int y1, int x2, int y2, real angle, int layer)
{
	if (g_used_layers[layer]==0)
	{
		return;
	}
	string rotation="";

	if (angle!=0.0)
	{
		sprintf(rotation, " transform='rotate(%f,%f,%f)'",
		-angle, 
		u2mm(x1+x2)/2.0, u2mm(-y1-y2)/2.0);
	}   
	printf("<rect class='l%d' x='%f' y='%f' width='%f' height='%f'%s/>\n",
	layer,
	u2mm(x1), u2mm(-y2), 
	u2mm(x2-x1), u2mm(y2-y1),
	rotation);
}

void svgWriteRectCenter(int x, int y, int dx, int dy, real angle, int layer)
{
	if (g_used_layers[layer]==0)
	{
		return;
	}
	string rotation = svgTransform(x, y, angle);

	printf("<rect class='l%d' x='%f' y='%f' width='%f' height='%f' %s/>\n",
	layer,
	u2mm(-dx/2), u2mm(-dy/2), 
	u2mm(dx), u2mm(dy),
	rotation);
}

void svgWriteOctCenter(int x, int y, int dx, int dy, real angle, int layer)
{
	if (g_used_layers[layer]==0)
	{
		return;
	}
	string rotation = svgTransform(x, y, angle);

	real x1 = u2mm(dx)/2; 
	real y1 = u2mm(dy)/2; 
	real x2 = u2mm(dx)/(2*(1+1.414213562));
	real y2 = u2mm(dy)/(2*(1+1.414213562)); 

	printf("<polygon class='l%d' points='%f %f, %f %f, %f %f, %f %f, %f %f, %f %f, %f %f, %f %f' %s/>\n",
	layer,
	-x1, -y2, 
	-x2, -y1, 
	x2, -y1, 
	x1, -y2, 
	x1, y2, 
	x2, y1, 
	-x2, y1, 
	-x1, y2, 
	rotation);
}

void svgWriteRoundRectCenter(int x, int y, int w, int h, int roundness, real angle, int layer)
{
	if (g_used_layers[layer]==0)
	{
		return;
	}
	string rotation = svgTransform(x, y, angle);

	if (w<h){
		roundness = w*roundness/200;
	}
	else
	{
		roundness = h*roundness/200;
	}

	printf("<rect class='l%d' x='%f' y='%f' width='%f' height='%f' rx='%f' %s/>\n",
	layer,
	u2mm(-w/2), u2mm(-h/2), 
	u2mm(w), u2mm(h),
	u2mm(roundness),
	rotation);
}


void svgWriteCircle(int x, int y, int radius, int lwidth, int layer)
{
	if (g_used_layers[layer]==0) {
	  return;
	}
	printf("<circle class='l%d' cx='%f' cy='%f' r='%f' style='stroke-width:%f'/>\n", 
	layer,
	u2mm(x), u2mm(-y),
	u2mm(radius), 
	u2mm(lwidth));
}

void svgWriteDot(int x, int y, int diameter, int layer)
{
	if (g_used_layers[layer]==0)
	{
		return;
	}
	printf("<circle class='j%d' cx='%f' cy='%f' r='%f'/>\n", 
	layer,
	u2mm(x), u2mm(-y),
	u2mm(diameter)/2.0);
}


void svgWritePathStart(int layer, string style)
{
	printf( "<path class='l%d' style='%s' d='", layer, style);
}

void svgWritePathSegment(int x1, int y1, int x2, int y2)
{
	printf( " M %f,%f L %f,%f", u2mm(x1), u2mm(-y1), u2mm(x2), u2mm(-y2));    
}

void svgWritePathEnd()
{
	printf( "'/>\n");
}



void svgWriteText(int x, int y, real angle, char align, string text, int size, int layer)
{
	if (g_used_layers[layer]==0)
	{
		return;
	}
	string style;
	sprintf(style, "font-size:%fpt;", u2mm(size)*1.1);

	if (align=='e')
	{
		style += " text-anchor:end;";
	}

	if (angle==0.0)
	{
		printf( "<text class='l%d' x='%f' y='%f' style='%s'>%s</text>\n",
		layer,
		u2mm(x), u2mm(-y), 
		style, 
		text);

	}
	else
	{
		printf( "<text class='l%d' x='0' y='0' style='%s' transform='translate(%f, %f) rotate(%f)'>%s</text>\n",
		layer,
		style,
		u2mm(x), u2mm(-y), 
		angle,
		text);  
	}
}



//------------------------------------------------------
// write UL piece
//------------------------------------------------------
void write_piece(UL_WIRE W)
{
	if (g_used_layers[W.layer]==0)
	{
		return;
	}

	string style = svgLineStyle(W.width, W.cap);
	
	if (W.arc)
	{
		char longpath;
		if( abs(W.arc.angle2-W.arc.angle1) < 180.0 )
		{
			longpath='0';
		}
		else
		{
			longpath='1';
		}
		svgWriteArc(W.arc.x1, W.arc.y1, W.arc.x2, W.arc.y2, W.arc.radius, longpath, W.layer, style);
	}
	else
	{
		svgWriteLine(W.x1, W.y1, W.x2, W.y2, W.layer, style);
	}
}


//------------------------------------------------------
// write UL wire
//------------------------------------------------------
void write_wire(UL_WIRE W)
{
	if (g_used_layers[W.layer]==0)
	{
		return;
	}

	if ( W.style == WIRE_STYLE_LONGDASH || W.style == WIRE_STYLE_SHORTDASH || W.style == WIRE_STYLE_DASHDOT )
	{
		W.pieces(P)
		{
			write_piece(P);           
		}      
	}
	else if (W.arc)
	{
		string style = svgLineStyle(W.arc.width, W.cap);
		char longpath;
		if( abs(W.arc.angle2-W.arc.angle1) < 180.0 )
		{
			longpath='0';
		}
		else
		{
			longpath='1';
		}
		svgWriteArc(W.arc.x1, W.arc.y1, W.arc.x2, W.arc.y2, W.arc.radius, longpath, W.layer, style);   
	}
	else
	{
		string style = svgLineStyle(W.width, W.cap);
		svgWriteLine(W.x1, W.y1, W.x2, W.y2, W.layer, style);
	}
}


//------------------------------------------------------
// write UL rectangle
//------------------------------------------------------
void write_rectangle(UL_RECTANGLE R)
{
	if (g_used_layers[R.layer]==0)
	{
		return;
	}
	svgWriteRect(R.x1, R.y1, R.x2, R.y2, R.angle, R.layer);
}


//------------------------------------------------------
// write UL vector text
//------------------------------------------------------
void write_vector_text(UL_TEXT T)
{
	if (g_used_layers[T.layer]==0)
	{
		return;
	}
	int cnt=0;
	T.wires(W)
	{
		string lineCap;
		if (cnt==0)
		{
			string style = svgLineStyle(W.width, W.cap);
			svgWritePathStart(W.layer, style);
		}
		svgWritePathSegment(W.x1, W.y1, W.x2, W.y2);
		cnt++;
	}
	if (cnt>0)
	{
		svgWritePathEnd();
	}
}

//------------------------------------------------------
// write UL proportional text
//------------------------------------------------------
void write_prop_text(UL_TEXT T)
{
	if (g_used_layers[T.layer]==0)
	{
		return;
	}

	string newText = encodeText(T.value);

	int posX = T.x;
	int posY = T.y;   
	int textAngle = T.angle;
	int textSize = T.size;

	char hmode, vmode, rmode;

	if( T.mirror > 0 )
	{
		switch( textAngle )
		{
		case 0:   vmode='e'; hmode='b'; rmode='0'; break;
		case 90:  vmode='b'; hmode='t'; rmode='9'; break;
		case 180: vmode='b'; hmode='t'; rmode='0'; break;
		case 270: vmode='e'; hmode='b'; rmode='9'; break;
		} 
	}
	else
	{
		switch( textAngle )
		{
		case 0:   vmode='b'; hmode='b'; rmode='0'; break;
		case 90:  vmode='b'; hmode='b'; rmode='9'; break;
		case 180: vmode='e'; hmode='t'; rmode='0'; break;
		case 270: vmode='e'; hmode='t'; rmode='9'; break;
		} 
	}

	if (rmode=='0')
	{
		if (hmode=='t')
		{
			posY -= textSize;
		}
		svgWriteText(posX, posY, 0.0, vmode, newText, textSize, T.layer);
	}
	else
	{
		if (hmode=='t')
		{
			posX += textSize;
		}
		svgWriteText(posX, posY, -90.0, vmode, newText, textSize, T.layer);
	}
}


//------------------------------------------------------
// write UL general text
//------------------------------------------------------
void write_text(UL_TEXT T)
{
	if (g_used_layers[T.layer]==0)
	{
		return;
	}
	if (T.font==FONT_VECTOR)
	{
		write_vector_text(T);
	}
	else
	{
		write_prop_text(T);
	}
}



//------------------------------------------------------
// write UL circle
//------------------------------------------------------
void write_circle(UL_CIRCLE C)
{
	if (g_used_layers[C.layer]==0)
	{
	 return;
	}
	svgWriteCircle(C.x, C.y, C.radius, C.width, C.layer);
}


//------------------------------------------------------
// write drillsymbol
//------------------------------------------------------
void write_drill(int x, int y, int drill, int layer)
{
	if (g_used_layers[layer]==0)
	{
	  return;
	}
	svgWriteDot(x, y, drill, layer);
}

//------------------------------------------------------
// write restring
//------------------------------------------------------
void write_restring(int x, int y, int diameter, int shape, int long, real angle, int layer)
{
	if (g_used_layers[layer]==0)
	{
		return;
	}

	switch(shape)
	{
	case PAD_SHAPE_SQUARE:
		svgWriteRectCenter(x, y, diameter, diameter, angle, layer);
		break;
	case PAD_SHAPE_OCTAGON: 
		svgWriteOctCenter(x, y, diameter, diameter, angle, layer);
		break;
	case PAD_SHAPE_LONG:
		svgWriteRoundRectCenter(x, y, (diameter*long)/100, diameter, 100, angle, layer);
		break;
	case PAD_SHAPE_OFFSET:
	case PAD_SHAPE_ANNULUS:
	case PAD_SHAPE_THERMAL:
	case PAD_SHAPE_ROUND:
	default:
		svgWriteDot(x, y, diameter, layer);
	}
}


//------------------------------------------------------
// write UL pad
//------------------------------------------------------
void write_pad(UL_PAD P)
{
	int layer;
	if (P.flags&PAD_FLAG_STOP)
	{
		write_restring(P.x, P.y, P.diameter[LAYER_TSTOP], P.shape[LAYER_TSTOP], 100+P.elongation, P.angle, LAYER_TSTOP);
		write_restring(P.x, P.y, P.diameter[LAYER_BSTOP], P.shape[LAYER_BSTOP], 100+P.elongation, P.angle, LAYER_BSTOP);
	}
	for (layer=LAYER_TOP; layer<=LAYER_BOTTOM; ++layer)
	{
		if (g_used_layers[layer])
		{
			write_restring(P.x, P.y, P.diameter[layer], P.shape[layer], 100+P.elongation, P.angle, layer);
		}
	}
	write_drill(P.x, P.y, P.drill, LAYER_DRILLS);
}


//------------------------------------------------------
// write UL smd
//------------------------------------------------------
void write_smd(UL_SMD S)
{
	if (S.layer==LAYER_TOP)
	{
		if (S.flags & SMD_FLAG_STOP)
		{
			svgWriteRoundRectCenter(S.x, S.y, S.dx[LAYER_TSTOP], S.dy[LAYER_TSTOP], S.roundness, S.angle, LAYER_TSTOP);
		}
		if (S.flags & SMD_FLAG_CREAM)
		{
			svgWriteRoundRectCenter(S.x, S.y, S.dx[LAYER_TCREAM], S.dy[LAYER_TCREAM], S.roundness, S.angle, LAYER_TCREAM);
		}  
		svgWriteRoundRectCenter(S.x, S.y, S.dx[LAYER_TOP], S.dy[LAYER_TOP], S.roundness, S.angle, LAYER_TOP);
	}
	else if (S.layer==LAYER_BOTTOM)
	{
		if (S.flags & SMD_FLAG_STOP)
		{
			svgWriteRoundRectCenter(S.x, S.y, S.dx[LAYER_BSTOP], S.dy[LAYER_BSTOP], S.roundness, S.angle, LAYER_BSTOP);
		}
		if (S.flags & SMD_FLAG_CREAM)
		{
			svgWriteRoundRectCenter(S.x, S.y, S.dx[LAYER_BCREAM], S.dy[LAYER_BCREAM], S.roundness, S.angle, LAYER_BCREAM);
		}    
		svgWriteRoundRectCenter(S.x, S.y, S.dx[LAYER_BOTTOM], S.dy[LAYER_BOTTOM], S.roundness, S.angle, LAYER_BOTTOM);
	}
}


//------------------------------------------------------
// write UL via
//------------------------------------------------------
void write_via(UL_VIA V)
{
	int layer;
	if (V.flags&VIA_FLAG_STOP)
	{
		write_restring(V.x, V.y, V.diameter[LAYER_TSTOP], V.shape[LAYER_TSTOP], 100, 0.0, LAYER_TSTOP);
		write_restring(V.x, V.y, V.diameter[LAYER_BSTOP], V.shape[LAYER_BSTOP], 100, 0.0, LAYER_BSTOP);
	}
	for (layer=V.start; layer<=V.end; ++layer)
	{
		if (g_used_layers[layer])
		{
			write_restring(V.x, V.y, V.diameter[layer], V.shape[layer], 100, 0.0, layer);
		}
	}
	write_drill(V.x, V.y, V.drill, LAYER_DRILLS);
}


//------------------------------------------------------
// write UL hole
//------------------------------------------------------
void write_hole(UL_HOLE H)
{ 
	svgWriteCircle(H.x, H.y, H.drill/2, 1, LAYER_DIMENSION);
	write_drill(H.x, H.y, H.drill, LAYER_HOLES);
}


//------------------------------------------------------
// write UL segment
//------------------------------------------------------
void write_segment(UL_SEGMENT SEG)
{
	int layer = 0;      
	SEG.wires(W)
	{
		layer = W.layer;      
		write_wire(W);
	}

	SEG.junctions(J)
	{  
		svgWriteDot(J.x, J.y, J.diameter, layer);
	}

	SEG.texts(T)
	{
		write_text(T);
	}
}


//------------------------------------------------------
// write UL polygon
//------------------------------------------------------
void write_polygon(UL_POLYGON P)
{
	if (g_used_layers[P.layer]==0)
	{
		return;
	}
	int count = 0;
	printf( "<polygon class='l%d' points='", P.layer);

	P.wires(W)
	{
		if (count == 0)
		{
			printf( "%f %f", u2mm(W.x1), u2mm(-W.y1)); 
		}
		else
		{
			printf( ", %f %f", u2mm(W.x1), u2mm(-W.y1));
		}
		++count;
	}

	printf( "'/>\n" );

}


//------------------------------------------------------
// write filled UL polygon
//------------------------------------------------------
void write_filled_polygon(UL_POLYGON P)
{
	if (g_used_layers[P.layer]==0)
	{
		return;
	}
	string style;
	int first=1;

	P.contours(W)
	{
		if (first)
		{
			string style = svgLineStyle(W.width, W.cap);
			svgWritePathStart(P.layer, style);
			first=0;
		}
		svgWritePathSegment(W.x1, W.y1, W.x2, W.y2);
	}
	P.fillings(W)
	{
		svgWritePathSegment(W.x1, W.y1, W.x2, W.y2);
	}
	svgWritePathEnd();
}


//------------------------------------------------------
// write UL bus
//------------------------------------------------------
void write_bus(UL_BUS B)
{
	printf("<g><title>BUS %s</title>\n", encodeText(B.name));
	B.segments(SEG)
	{
		write_segment(SEG);
	}
	printf("</g>\n");
}


//------------------------------------------------------
// write UL net
//------------------------------------------------------
void write_net(UL_NET N)
{
	printf("<g><title>NET %s</title>\n", encodeText(N.name));
	N.segments(SEG)
	{
		write_segment(SEG);
	}
	printf("</g>\n");
}


//------------------------------------------------------
//write UL signal
//------------------------------------------------------
void write_signal(UL_SIGNAL S)
{
	S.polygons(P) {write_filled_polygon(P);}    
	S.wires(W)    {write_wire(W);}
	S.vias(V)     {write_via(V);}    
}


//------------------------------------------------------
//write UL pin
//------------------------------------------------------
void write_pin(UL_PIN P)
{
	P.wires(W)   {write_wire(W);}
	P.circles(C) {write_circle(C);}
	P.texts(T)   {write_text(T);}
}


//------------------------------------------------------
//write UL symbol
//------------------------------------------------------
void write_symbol(UL_SYMBOL S)
{
	S.polygons(P)   {write_polygon(P);}
	S.circles(C)    {write_circle(C);}
	S.rectangles(R) {write_rectangle(R);}
	S.pins(P)       {write_pin(P);}
	S.wires(W)      {write_wire(W);}
	S.texts(T)      {write_text(T);}
}


//------------------------------------------------------
//write UL gate
//------------------------------------------------------
void write_gate(UL_GATE G)
{
	write_symbol(G.symbol);
}


//------------------------------------------------------
//write UL instance
//------------------------------------------------------
void write_instance(UL_INSTANCE I)
{
	printf("<g><title>PART %s</title>\n", encodeText(I.name));
	write_gate(I.gate);
	I.texts(T) {write_text(T);}
	printf("</g>\n");
}


//------------------------------------------------------
//write UL part
//------------------------------------------------------
void write_part(UL_PART P)
{
	P.instances(I)
	{
		write_instance(I);
	}
}


//------------------------------------------------------
//write UL contact
//------------------------------------------------------
void write_contact(UL_CONTACT C)
{
	if (C.pad)
		write_pad(C.pad);
	else if (C.smd)
		write_smd(C.smd);
}


//------------------------------------------------------
//write UL package
//------------------------------------------------------
void write_package(UL_PACKAGE PKG)
{
	PKG.polygons(P)   {write_polygon(P);}
	PKG.rectangles(R) {write_rectangle(R);}
	PKG.wires(W)      {write_wire(W);}
	PKG.circles(C)    {write_circle(C);}
	PKG.texts(T)      {write_text(T);}
	PKG.contacts(C)   {write_contact(C);}
	PKG.holes(H)      {write_hole(H);}
}


//------------------------------------------------------
//write UL element
//------------------------------------------------------
void write_element(UL_ELEMENT E)
{
	printf("<g><title>PART %s</title>\n", encodeText(E.name));  
	E.texts(T) {write_text(T);}
	write_package(E.package);
	printf("</g>\n");      
}


//------------------------------------------------------
//write layer stylesheet to svg file 
//------------------------------------------------------
void write_svg_layerStyle (UL_LAYER L)
{
	string color;
	if (g_monochrome && L.color!=15) //White should stay white
		color = htmlcolor(0);
	else
		color = htmlcolor(palette(L.color)&0x00ffffff);
	
	printf ("path.l%d {stroke:%s; fill:none; }\n", L.number, color);
	printf ("line.l%d {stroke:%s; fill:none; }\n", L.number, color);
	printf ("circle.l%d {stroke:%s; fill:none; }\n", L.number, color);
	printf ("circle.j%d {fill:%s; }\n", L.number, color);
	printf ("rect.l%d {fill:%s; }\n", L.number, color);
	printf ("text.l%d {font-family:sans-serif; fill:%s; }\n", L.number, color);
	printf ("polygon.l%d {fill:%s; }\n", L.number, color);
}

void write_sheet_styles()
{
	printf ("<defs>\n");
	printf ("<style type='text/css'>\n");
	printf ("<![CDATA[\n");
	schematic(SCH)
	{
		SCH.layers(L)
		{
			if (g_used_layers[L.number])
				write_svg_layerStyle(L);
		}
	}
	printf ("]]>\n");
	printf ("</style>\n");
	printf ("</defs>\n");
}


void update_used_sheet_layers(UL_SCHEMATIC SCH)
{
	SCH.layers(L)
	{
		int used = L.used;
		if (g_only_visible)
		{
			used &= L.visible;
		}
		g_used_layers[L.number]=used;    
	}
}


//------------------------------------------------------
//write svg header
//------------------------------------------------------
void write_sheet_header(UL_SHEET SH)
{
	int t = time();
	int pageCount = 0;
	string header =  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
	header += "<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' version='1.1' ";
	header += "width='%fmm' height='%fmm' viewBox='%f %f %f %f'>\n";

	int dimX    = SH.area.x2-SH.area.x1;
	int dimY    = SH.area.y2-SH.area.y1;
	printf(header, u2mm(dimX), u2mm(dimY), u2mm(SH.area.x1), u2mm(-SH.area.y2), u2mm(dimX), u2mm(dimY));

	schematic(SCH)
	{
		printf("<title>%s - sheet %d</title>\n", encodeText(SCH.name), SH.number);
		printf("<desc>generated by eagle2svg %.1f, developed by http://www.nicai-systems.de</desc>\n", VERSION);
	}

	write_sheet_styles();
	printf ("<g id='surface0'>\n");
}


//------------------------------------------------------
//write svg footer
//------------------------------------------------------
void write_sheet_footer(UL_SHEET SH)
{
	string footer =  "</g>\n";
	footer += "</svg>\n";
	printf(footer);
}


//------------------------------------------------------
//write whole sheet 
//------------------------------------------------------
void write_svg_sheet(string fileName)
{
	output(fileName, "Fwt")
	{
		if(sheet)
		{
			sheet(SH)
			{
				schematic(SCH)
				{
					update_used_sheet_layers(SCH);
				}
				
				write_sheet_header(SH);
				
				SH.texts(T)      {write_text(T);}
				SH.wires(W)      {write_wire(W);}        
				SH.nets(N)       {write_net(N);}
				SH.busses(B)     {write_bus(B);}
				SH.rectangles(R) {write_rectangle(R);}
				SH.polygons(P)   {write_polygon(P);}
				SH.circles(C)    {write_circle(C);}
				SH.parts(P)      {write_part(P);}

				write_sheet_footer(SH);
			}
		}  
	}   
}


void update_used_board_layers(UL_BOARD B)
{
	B.layers(L)
	{
		int used = L.used;
		if (g_only_visible)
		{
			used &= L.visible;
		}
		g_used_layers[L.number]=used;    
	}
}

//------------------------------------------------------
//write svg board styles
//------------------------------------------------------
void write_board_styles()
{
	printf ("<defs>\n");
	printf ("<style type='text/css'>\n");
	printf ("<![CDATA[\n");
	board(B)
	{
		B.layers(L)
		{
			if (g_used_layers[L.number])
				write_svg_layerStyle(L);
		}
	}
	printf ("]]>\n");
	printf ("</style>\n");
	printf ("</defs>\n");
}


//------------------------------------------------------
//write svg board header
//------------------------------------------------------
void write_board_header(UL_BOARD B)
{
	int t = time();
	int pageCount = 0;
	string header =  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
	header += "<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' version='1.1' ";
	header += "width='%fmm' height='%fmm' viewBox='%f %f %f %f'>\n";

	int dimX    = B.area.x2-B.area.x1;
	int dimY    = B.area.y2-B.area.y1;
	printf(header, u2mm(dimX), u2mm(dimY), u2mm(B.area.x1), u2mm(-B.area.y2), u2mm(dimX), u2mm(dimY));

	printf("<title>%s</title>\n", encodeText(B.name));
	printf("<desc>generated by eagle2svg %.1f, developed by http://www.nicai-systems.de</desc>\n", VERSION);

	write_board_styles();
	printf ("<g id='surface0'>\n");
}


//------------------------------------------------------
//write svg board footer
//------------------------------------------------------
void write_board_footer(UL_BOARD B)
{
	string footer =  "</g>\n";
	footer += "</svg>\n";
	printf(footer);
}


//------------------------------------------------------
//write whole board 
//------------------------------------------------------
void write_svg_board(string fileName)
{
	output(fileName, "Fwt")
	{
		if(board)
		{
			board(B)
			{
				update_used_board_layers(B);
				write_board_header(B);
				      
				B.texts(T)      {write_text(T);}
				B.circles(C)    {write_circle(C);}
				B.rectangles(R) {write_rectangle(R);}
				B.polygons(P)   {write_filled_polygon(P);}
				B.signals(S)    {write_signal(S);} 
				B.wires(W)      {write_wire(W);}
				B.elements(E)   {write_element(E);}
				B.holes(H)      {write_hole(H);}

				write_board_footer(B);
			}
		}  
	}   
}


//------------------------------------------------------
// Global mod_ and lib_name
//------------------------------------------------------
string sch_name ;   


//------------------------------------------------------
// Select the path where the schematic will be saved 
//------------------------------------------------------
void openSchematicPath(string startPath)
{
	string dirName = "";
	string stringArray[];
	dirName = dlgDirectory("Select a directory", startPath);

	if( dirName != "" )
	{
		schematic(S)
		{
			int n = 0;
			string tmpName = S.name; 
			int nr = strsplit(stringArray, tmpName, '/');
			sch_name = dirName + "/" + stringArray[nr-1];
			sch_name = strsub(sch_name , 0, strlen(sch_name) - 4) + ".ps";
		}
	}
}

int displayDialog(string titleStr)
{
	int space = 10;
	int result = dlgDialog(titleStr)
	{
		dlgVBoxLayout
		{
			dlgVBoxLayout
			{

				dlgHBoxLayout dlgSpacing(500);
				dlgStretch(0);
				dlgSpacing(space);
				dlgLabel("Export to file:");
				dlgStretch(0);
				dlgHBoxLayout
				{
					dlgSpacing(space);
					dlgStringEdit(sch_name);
					dlgSpacing(space);
					dlgPushButton("...") openSchematicPath("C:\\");
					dlgSpacing(space);
				}
				dlgHBoxLayout
				{
					dlgVBoxLayout
					{ 
						dlgCheckBox("Monochrome", g_monochrome);
						dlgCheckBox("Only visible", g_only_visible);					
					}
					dlgVBoxLayout
					{
						//dlgLabel("READ USAGE INFO!");
					}
				}
				dlgStretch(10);
				dlgLabel("developed by xTitoris, based on eagle2svg by nils.springob@nicai-systems.de");
			}
			dlgStretch(0);
			dlgHBoxLayout
			{
				dlgStretch(1);
				dlgPushButton("+OK") dlgAccept();
				dlgSpacing(space);
				dlgPushButton("-Cancel") dlgReject();
				dlgStretch(0);
				dlgSpacing(space);
			}
			dlgStretch(10);
		}
	};
	return result;
}


//------------------------------------------------------
// main program 
//------------------------------------------------------
string ref;
string titleStr;

sprintf(titleStr, "Export Eagle sheet to SVG, Version: %.1f", VERSION);

if (schematic)
{
	schematic(S)
	{
		sheet(SH)
		{
			sprintf(sch_name, "%s_p%d.svg", strsub(S.name, 0, strlen(S.name) - 4), SH.number);
		}
	}
	if(displayDialog(titleStr))
	{
		write_svg_sheet(sch_name);
	}
	exit(EXIT_SUCCESS);

}
else if (board)
{
	board(B)
	{
		sprintf(sch_name, "%s_brd.svg", strsub(B.name, 0, strlen(B.name) - 4));    
	}
	if(displayDialog(titleStr))
	{
		write_svg_board(sch_name);
	}
	exit(EXIT_SUCCESS);

}
else
{
	dlgMessageBox("Please run from schematic or board editor." ); 
	exit(EXIT_FAILURE);
}

