		/******************************************/
		/* Kicad: Common plot Postscript Routines */
		/******************************************/

#include "fctsys.h"
#include "gr_basic.h"
#include "trigo.h"
#include "wxstruct.h"
#include "base_struct.h"
#include "common.h"
#include "plot_common.h"
#include "macros.h"

#include "wx/defs.h"

// Variables partagees avec Common plot Postscript Routines
extern wxPoint LastPenPosition;
extern wxPoint PlotOffset;
extern FILE * PlotOutputFile;
extern double XScale, YScale;
extern int g_DefaultPenWidth, g_CurrentPenWidth;
extern int PlotOrientOptions, etat_plume;

// Locales
static Ki_PageDescr * SheetPS;


/*************************************************************************************/
void InitPlotParametresPS(wxPoint offset, Ki_PageDescr * sheet,
		double xscale, double yscale, int orient)
/*************************************************************************************/

/* Set the plot offset for the current plotting
 * xscale,yscale = coordinate scale (scale coefficient for coordinates)
 * device_xscale,device_yscale = device coordinate scale (i.e scale used by plot device)
 */
{
	PlotOrientOptions = orient;
	PlotOffset = offset;
	SheetPS = sheet;
	XScale = xscale;
	YScale = yscale;
	g_CurrentPenWidth = -1;
}


/*************************************************************************************/
void SetDefaultLineWidthPS(int width)
/*************************************************************************************/

/* Set the default line width (in 1/1000 inch) for the current plotting
 */
{
	g_DefaultPenWidth = width;		// epaisseur du trait standard en 1/1000 pouce
	g_CurrentPenWidth = -1;
}


/***************************************/
void SetCurrentLineWidthPS(int width)
/***************************************/

/* Set the Current line width (in 1/1000 inch) for the next plot
 */
{
int pen_width; 

	if( width > 0 )
		pen_width = width;
	else
		pen_width = g_DefaultPenWidth;

	if( pen_width != g_CurrentPenWidth )
		fprintf(PlotOutputFile, "%d setlinewidth\n", (int)(XScale * pen_width) );

	g_CurrentPenWidth = pen_width;
}


/******************************/
void SetColorMapPS(int color)
/******************************/

/* Print the postscript set color command:
 * r g b setrgbcolor,
 * r, g, b  = color values (= 0 .. 1.0 )
 *
 * color = color index in ColorRefs[]
 */
{
char Line[1024];

	sprintf( Line, "%.3f %.3f %.3f setrgbcolor\n",
			(float)ColorRefs[color].m_Red / 255,
			(float)ColorRefs[color].m_Green / 255,
			(float)ColorRefs[color].m_Blue / 255 );
	to_point(Line);
	fputs( Line, PlotOutputFile );
}


/***************************************************************/
void PlotFilledSegmentPS(wxPoint start, wxPoint end, int width)
/***************************************************************/

/* Plot 1 segment like a track segment
 */
{
	UserToDeviceCoordinate(start);
	UserToDeviceCoordinate(end);

	SetCurrentLineWidthPS(width);
	fprintf(PlotOutputFile,"%d %d %d %d line\n", start.x, start.y, end.x, end.y);
}


/******************************************************/
void PlotCircle_PS(wxPoint pos, int diametre, int width)
/******************************************************/
{
int rayon;
char Line[256];

	UserToDeviceCoordinate(pos);
	rayon = (int)(XScale * diametre / 2);

	if( rayon < 0 )
		rayon = 0;

	SetCurrentLineWidthPS(width);
	sprintf(Line, "newpath %d %d %d 0 360 arc stroke\n", pos.x, pos.y, rayon);
	fputs(Line, PlotOutputFile);
}


/**************************************************************************************/
void PlotArcPS(wxPoint centre, int StAngle, int EndAngle, int rayon, int width)
/**************************************************************************************/

/* Plot an arc:
 * StAngle, EndAngle = start and end arc in 0.1 degree
 */
{
char Line[256];

	if( rayon <= 0 )
		return;

	SetCurrentLineWidthPS(width);
	// Calcul des coord du point de depart :
	UserToDeviceCoordinate(centre);

	if( PlotOrientOptions == PLOT_MIROIR )
		sprintf( Line, "newpath %d %d %d %f %f arc stroke\n", centre.x, centre.y,
				(int)(rayon * XScale), (float)StAngle / 10, (float)EndAngle / 10 );
	else
		sprintf( Line, "newpath %d %d %d %f %f arc stroke\n", centre.x, centre.y,
				(int)(rayon * XScale), -(float)EndAngle / 10, -(float)StAngle / 10 );
	// Undo internationalization printf (float x.y printed x,y)
	to_point(Line);
	fputs(Line, PlotOutputFile);
}


/*****************************************************************/
void PlotPolyPS(int nb_segm, int * coord, int fill, int width)
/*****************************************************************/

/* Trace un polygone ( ferme si rempli ) en format POSTSCRIPT
 * coord = tableau des coord des sommets
 * nb_segm = nombre de coord ( 1 coord = 2 elements: X et Y du tableau )
 * fill : si != 0 polygone rempli
 */
{
int ii;
wxPoint pos;

	if( nb_segm <= 1 )
		return;

	SetCurrentLineWidthPS(width);

	pos.x = coord[0];
	pos.y = coord[1];
	UserToDeviceCoordinate(pos);
	fprintf(PlotOutputFile, "newpath %d %d moveto\n", pos.x, pos.y);

	for( ii = 1; ii < nb_segm; ii ++ )
	{
		pos.x = coord[2 * ii];
		pos.y = coord[2 * ii + 1];
		UserToDeviceCoordinate(pos);
		fprintf(PlotOutputFile, "%d %d lineto\n", pos.x, pos.y);
	}

	// Fermeture du polygone
	if( fill )
		fprintf(PlotOutputFile, "closepath ");
	if( fill == 1 )
		fprintf(PlotOutputFile, "fill ");
	fprintf(PlotOutputFile, "stroke\n");
}


/*************************************/
void LineTo_PS(wxPoint pos, int plume)
/*************************************/

/* Routine to draw to a new position
 */
{
	if( plume == 'Z' )
		return;

	UserToDeviceCoordinate(pos);
	if( plume == 'D' )
	{
		char Line[256];
		sprintf(Line, "%d %d %d %d line\n",
				LastPenPosition.x, LastPenPosition.y, pos.x, pos.y);
		fputs(Line, PlotOutputFile);
	}
	LastPenPosition = pos;
}


/***********************************************************/
void PrintHeaderPS(FILE * file, const wxString & Creator,
				const wxString & FileName, int PageCount,
				int BBox[4], int PaperOrientation)
/***********************************************************/

/* The code within this function (and the CloseFilePS function)
 * creates postscript files whose contents comply with Adobe's
 * Document Structuring Convention, as documented by assorted
 * details described within the following URLs:
 * 
 * http://en.wikipedia.org/wiki/Document_Structuring_Conventions
 * http://partners.adobe.com/public/developer/en/ps/5001.DSC_Spec.pdf
 * 
 * 
 * The PageCount and PaperOrientation parameters have been provided to
 * respectively cater for the production of multiple-page postscript
 * files, and postscript files having either a portrait orientation
 * or a landscape orientation.
 * 
 * BBox is the boundary box (position and size of the "client rectangle"
 * for drawings (page - margins) in mils (0.001 inch)
 */
{
wxString msg;
char Line[1024];
const char *PSMacro[] = {
"/line {\n",
"    newpath\n",
"    moveto\n",
"    lineto\n",
"    stroke\n",
"} def\n",
"gsave\n",
"72 72 scale\t\t\t% Talk inches\n",
"1 setlinecap\n",
"1 setlinejoin\n",
"1 setlinewidth\n",
	NULL
};
const double MIL_TO_INCH = 0.001;
int ii;
time_t time1970 = time(NULL);

	PlotOutputFile = file;

	fputs("%!PS-Adobe-3.0\n", PlotOutputFile);	// Print header

	sprintf( Line, "%%%%Creator: %s\n", CONV_TO_UTF8(Creator) );
	fputs(Line, PlotOutputFile);

	// A "newline" character ("\n") is not included in the following string,
	// because it is provided by the ctime() function.
	sprintf( Line, "%%%%CreationDate: %s", ctime(&time1970) );
	fputs(Line, PlotOutputFile);

	sprintf( Line, "%%%%Title: %s\n", CONV_TO_UTF8(FileName) );
	fputs(Line, PlotOutputFile);

	sprintf( Line, "%%%%Pages: %d\n", PageCount );
	fputs(Line, PlotOutputFile);

	sprintf( Line, "%%%%PageOrder: Ascend\n" );
	fputs(Line, PlotOutputFile);

	// Print boundary box en 1/72 pouce, box is in mils
	const double CONV_SCALE = MIL_TO_INCH * 72;
	// The coordinates of the lower left corner of the boundary
	// box need to be "rounded down", but the coordinates of its
	// upper right corner need to be "rounded up" instead.
	sprintf( Line, "%%%%BoundingBox: %d %d %d %d\n",
			(int)floor((BBox[1] * CONV_SCALE)), (int)floor((BBox[0] * CONV_SCALE)),
			(int)ceil((BBox[3] * CONV_SCALE)), (int)ceil((BBox[2] * CONV_SCALE)) );
	fputs(Line, PlotOutputFile);

	// Specify the size of the sheet and the name associated with that size.
	// (If the "User size" option has been selected for the sheet size,
	// identify the sheet size as "Custom" (rather than as "User"), but
	// otherwise use the name assigned by KiCad for each sheet size.)
	//
	// (The Document Structuring Convention also supports sheet weight,
	// sheet colour, and sheet type properties being specified within a
	// %%DocumentMedia comment, but they are not being specified here;
	// a zero and two null strings are subsequently provided instead.)
	//
	// (NOTE: m_Size.y is *supposed* to be listed before m_Size.x;
	// the order in which they are specified is not wrong!)
	if( SheetPS->m_Name.Cmp( wxT("User") ) == 0 )
		sprintf( Line, "%%%%DocumentMedia: Custom %d %d 0 () ()\n",
				(int)round( SheetPS->m_Size.y * CONV_SCALE ),
				(int)round( SheetPS->m_Size.x * CONV_SCALE ) );
	else // ( if SheetPS->m_Name does not equal "User" )
		sprintf( Line, "%%%%DocumentMedia: %s %d %d 0 () ()\n",
				CONV_TO_UTF8( SheetPS->m_Name ),
				(int)round( SheetPS->m_Size.y * CONV_SCALE ),
				(int)round( SheetPS->m_Size.x * CONV_SCALE ) );
	fputs(Line, PlotOutputFile);

	if( PaperOrientation == wxPORTRAIT )
		sprintf( Line, "%%%%Orientation: Portrait\n" );
	else
		sprintf( Line, "%%%%Orientation: Landscape\n" );
	fputs(Line, PlotOutputFile);

	sprintf( Line, "%%%%EndComments\n" );
	fputs(Line, PlotOutputFile);

	// Now specify various other details.

	// The following string has been specified here (rather than within
	// PSMacro[]) to highlight that it has been provided to ensure that the
	// contents of the postscript file comply with the details specified
	// within the Document Structuring Convention.
	sprintf( Line, "%%%%Page: 1 1\n" );
	fputs(Line, PlotOutputFile);

	for ( ii = 0; PSMacro[ii] != NULL; ii++ )
	{
		fputs(PSMacro[ii], PlotOutputFile);
	}

	if( PaperOrientation == wxLANDSCAPE )
		sprintf(Line, "%f %f translate 90 rotate\n",
				(float)BBox[3] * MIL_TO_INCH, (float)BBox[0] * MIL_TO_INCH);
	// (If support for creating postscript files with a portrait orientation
	// is ever provided, determine whether it would be necessary to provide
	// an "else" command and then an appropriate "sprintf" command here.)

	// compensation internationalisation printf (float x.y généré x,y)
	to_point(Line);

	fputs(Line, PlotOutputFile);

	sprintf(Line, "%f %f scale\t\t%% Move to User coordinates\n",
			XScale, YScale);
	to_point(Line);
	fputs(Line, PlotOutputFile);

	// Set default line width ( g_DefaultPenWidth is in user units )
	fprintf(PlotOutputFile, "%d setlinewidth\n", g_DefaultPenWidth);
}


/******************************************/
bool CloseFilePS(FILE * plot_file)
/******************************************/
{
	fputs("showpage\n", plot_file);
	fputs("grestore\n", plot_file);
	fputs("%%EOF\n", plot_file);

	fclose(plot_file);

	return TRUE;
}

