	/****************************************/
	/* EDITEUR de PCB: Menus d'AUTOROUTAGE: */
	/****************************************/
// #define ROUTER

#include "fctsys.h"
#include "gr_basic.h"
#include "common.h"
#include "pcbnew.h"
#include "autorout.h"
#include "cell.h"
#include "trigo.h"

#include "protos.h"

#define ROUTER

#define PSCALE 1

/* routines internes */
static void Out_Pads(BOARD * Pcb, FILE * outfile);
static int GenEdges(BOARD * Pcb, FILE * outfile);
static void GenExistantTracks(BOARD * Pcb, FILE *outfile, int current_net_code, int type);
static void ReturnNbViasAndTracks(BOARD * Pcb, int netcode, int * nb_vias, int *nb_tracks);

/* variables locales */
static int min_layer, max_layer;



/******************************************/
void WinEDA_PcbFrame::GlobalRoute(wxDC * DC)
/******************************************/
{
#ifdef ROUTER
FILE * outfile;
wxString FullFileName, ExecFileName, msg;
int ii;
int net_number;

#ifdef __UNIX__
	ExecFileName = FindKicadFile(wxT("anneal"));
#else
	ExecFileName = FindKicadFile(wxT("anneal.exe"));
#endif
	/* test de la presence du fichier et execution si present */
	if( ! wxFileExists(ExecFileName) )
	{
		msg.Printf( wxT("File <%s> not found"), ExecFileName.GetData());
		DisplayError(this, msg, 20) ;
		return;
	}

	/* Calcule du nom du fichier intermediaire de communication */
	FullFileName = m_CurrentScreen->m_FileName;
	ChangeFileNameExt(FullFileName,wxT(".ipt"));

	if( (outfile = wxFopen(FullFileName, wxT("wt"))) == NULL )
	{
		msg = _("Unable to create temporary file ") + FullFileName;
		DisplayError(this, msg,20);
		return;
	}

	msg = _("Create temporary file ") + FullFileName;
	SetStatusText(msg);

	/* calcul ratsnest */
	m_Pcb->m_Status_Pcb = 0 ;
	Compile_Ratsnest(DC, TRUE);

	m_Pcb->ComputeBoundaryBox();

	// Sortie de la dimension hors tout du pcb (dimensions + marge + g_GridRoutingSize)
#define B_MARGE 1000       // en 1/10000 inch
	fprintf(outfile,"j %d %d %d %d",
		(-B_MARGE - g_GridRoutingSize + m_Pcb->m_BoundaryBox.GetX() )/PSCALE,
		(-B_MARGE - g_GridRoutingSize + m_Pcb->m_BoundaryBox.GetY() )/PSCALE,
		(B_MARGE + g_GridRoutingSize + m_Pcb->m_BoundaryBox.GetRight() )/PSCALE,
		(B_MARGE + g_GridRoutingSize + m_Pcb->m_BoundaryBox.GetBottom() )/PSCALE);

	/* calcul du nombre de couches cuivre */
	min_layer = 1;	/* -> couche soudure = min layer */
	max_layer = m_Pcb->m_BoardSettings->m_CopperLayerCount;

	fprintf(outfile," %d %d", min_layer, max_layer);

	net_number = m_Pcb->m_NbNets;

	fprintf(outfile," %d", net_number);

	fprintf(outfile," %d", g_GridRoutingSize / PSCALE);

	fprintf(outfile," %d %d %d",	/* isolation Pad, track, via */
			g_DesignSettings.m_TrackClearence/PSCALE,
			g_DesignSettings.m_TrackClearence/PSCALE,
			g_DesignSettings.m_TrackClearence/PSCALE );


	fprintf(outfile," 0");		/* via type */

	fprintf(outfile," %d", g_DesignSettings.m_CurrentViaSize/PSCALE);		/* via diam */

	fprintf(outfile," n");		/* via enterree non permise */

	fprintf(outfile," 0");		/* unused */

	fprintf(outfile," %d", g_DesignSettings.m_CurrentTrackWidth /PSCALE); /* default track width */

	fprintf(outfile," 0");		/* unused */

	fprintf(outfile," 0 0 0\n");	/* unused */

	fprintf(outfile,"k 0 0 0 0 0 0 0 0 0 0\n");	/* spare record */

	fprintf(outfile,"m 0 0 0 0 0 0 0 0 0 0\n");	/* cost record */

	for ( ii = min_layer; ii <= max_layer; ii++ )
		{
		int dir;
		dir = 3;	/* horizontal */
		if (ii & 1 ) dir = 1;	/* vertical */
		fprintf(outfile,"l %d %d\n", ii, dir);	/* layer direction record */
		}

	Out_Pads(m_Pcb, outfile);
	GenEdges(m_Pcb, outfile);

	fclose( outfile );

	ExecFileName += wxT(" ") + FullFileName;

	Affiche_Message(ExecFileName);

	wxExecute(ExecFileName);

#else
	wxMessageBox( wxT("TODO, currently not available"));
#endif
}


/************************************************/
static void Out_Pads(BOARD * Pcb, FILE * outfile)
/************************************************/
{
D_PAD * pt_pad ;
//MODULE * Module;
int netcode, mod_num, nb_pads, plink;
LISTE_PAD * pt_liste_pad, * pt_start_liste,
		* pt_end_liste, * pt_liste_pad_limite;
int pin_min_layer, pin_max_layer;
int no_conn = Pcb->m_NbPads+1;	/* valeur incrementee pour indiquer
		que le pad n'est pas deja connecte a une piste*/

	pt_liste_pad = pt_start_liste = Pcb->m_Pads;
	pt_liste_pad_limite = pt_start_liste + Pcb->m_NbPads;

	if( pt_liste_pad == NULL ) return;

	netcode = (*pt_liste_pad)->m_NetCode;
	nb_pads = 1; plink = 0;
	for ( ; pt_liste_pad < pt_liste_pad_limite ; )
	{
		/* Recherche de la fin de la liste des pads du net courant */
		for( pt_end_liste = pt_liste_pad + 1 ; ; pt_end_liste++)
		{
			if (pt_end_liste >= pt_liste_pad_limite ) break ;
			if ((*pt_end_liste)->m_NetCode != netcode ) break ;
			nb_pads++;
		}

		/* fin de liste trouvee : */
		if( netcode > 0 )
		{
			int nb_vias, nb_tracks;
			ReturnNbViasAndTracks(Pcb, netcode, &nb_vias, &nb_tracks);
			if ( nb_pads < 2 )
			{
				wxString Line;
				EQUIPOT * equipot = GetEquipot(Pcb, netcode);
				Line.Printf( wxT("Warning: %d pad, net %s"),
            					nb_pads, equipot->m_Netname.GetData());
				DisplayError(NULL, Line,20);
			}
			fprintf(outfile,"r %d %d %d %d %d %d 1 1\n",
					netcode, nb_pads, nb_vias+nb_pads, nb_tracks, 0,
					g_DesignSettings.m_CurrentTrackWidth /PSCALE);
		}

		for( ;pt_liste_pad < pt_end_liste ; pt_liste_pad++)
		{
			pt_pad = *pt_liste_pad;
			netcode = pt_pad->m_NetCode;
			plink = pt_pad->m_physical_connexion;
			/* plink = numero unique si pad non deja connecte a une piste */
			if (plink <= 0 ) plink = no_conn++;

			if( netcode <= 0 )  /* pad non connecte */
				fprintf(outfile,"u 0");
			else
				fprintf(outfile,"p %d", netcode);
			/* position */
			fprintf(outfile," %d %d",
				pt_pad->m_Pos.x/PSCALE, pt_pad->m_Pos.y/PSCALE);

			/* layers */
			pin_min_layer = 0; pin_max_layer = max_layer;

			if( (pt_pad->m_Masque_Layer & ALL_CU_LAYERS) == CUIVRE_LAYER )
				pin_min_layer = pin_max_layer = min_layer;

			else if( (pt_pad->m_Masque_Layer & ALL_CU_LAYERS) == CMP_LAYER )
				pin_min_layer = pin_max_layer = max_layer;

			fprintf(outfile," %d %d", pin_min_layer, pin_min_layer);

			/* link */
			fprintf(outfile," %d", plink);

			/* type of device (1 = IC, 2 = edge conn, 3 = discret, 4 = other */
			switch (pt_pad->m_Attribut)
				{
				case STANDARD:
				case SMD:
					fprintf(outfile," %d", 1);
					break;
				case CONN:  fprintf(outfile," %d", 2);
					break;
				case P_HOLE:
				case MECA:
					fprintf(outfile," %d", 4);
					break;
				}

			/* pin number */
			fprintf(outfile," %ld", (long)(pt_pad->m_Padname));

			/* layer size number (tj = 1) */
			fprintf(outfile," %d", 1);

			/* device number */
			mod_num = 1;	/* A CHANGER */
			fprintf(outfile," %d", mod_num);

			/* orientations pins 1 et 2 */
			fprintf(outfile," x");

			/* spare */
			fprintf(outfile," 0 0\n");

			/* output layer size record */
			fprintf(outfile,"q");
			switch (pt_pad->m_PadShape)  /* out type, dims */
				{
				case CIRCLE:
					fprintf(outfile," c 0 %d 0",
							pt_pad->m_Size.x/PSCALE );
					break;

				case OVALE:
				case RECT:
				case TRAPEZE:
					int lmax = pt_pad->m_Size.x;
					int lmin = pt_pad->m_Size.y;
					int angle = pt_pad->m_Orient/10;
					while (angle < 0 ) angle += 180;
					while (angle > 180 ) angle -= 180;
					while (angle > 135 )
						{
						angle -= 90;
						EXCHG(lmax,lmin);
						}
					fprintf(outfile," r %d %d %d",
							angle,
							lmax /PSCALE, lmin/PSCALE );
					break;
				}
			/* layers */
			fprintf(outfile," %d %d\n", pin_min_layer, pin_max_layer);

		}	/* fin generation liste pads pour 1 net */

		if(netcode)
		{
			GenExistantTracks(Pcb, outfile, netcode, TYPEVIA);
			GenExistantTracks(Pcb, outfile, netcode, TYPETRACK);
		}

		nb_pads = 1;
		pt_liste_pad = pt_start_liste = pt_end_liste;
		if(pt_start_liste < pt_liste_pad_limite)
				netcode = (*pt_start_liste)->m_NetCode ;
	}
}


/**************************************************************************/
static void ReturnNbViasAndTracks(BOARD * Pcb, int netcode, int * nb_vias,
	int *nb_tracks)
/**************************************************************************/
/* calcule le nombre de vias et segments de pistes pour le net netcode
*/
{
TRACK * track;

	*nb_vias = 0;
	*nb_tracks = 0;

	track = Pcb->m_Track;
	if( track == NULL ) return;

	for ( ; track != NULL ; track = (TRACK*) track->Pnext )
		{
		if( track->m_NetCode > netcode ) return;
		if( track->m_NetCode != netcode ) continue;
		if(track->m_StructType == TYPEVIA ) (*nb_vias)++;
		if(track->m_StructType == TYPETRACK ) (*nb_tracks)++;
		}
}

/*************************************************************/
static void	GenExistantTracks(BOARD * Pcb, FILE *outfile,
	int current_net_code, int type)
/*************************************************************/
/* generation des pistes existantes */
{
int netcode, plink;
int via_min_layer, via_max_layer;
TRACK * track;


	track = Pcb->m_Track;
	if( track == NULL ) return;


	for ( ; track != NULL ; track = (TRACK*) track->Pnext )
		{
		netcode = track->m_NetCode;
		if( netcode > current_net_code ) return;
		if( netcode != current_net_code ) continue;
		plink = track->m_Sous_Netcode;
		via_min_layer = track->m_Layer;

		if(track->m_StructType != type ) continue;

		if(track->m_StructType == TYPEVIA )
			{
			via_min_layer &= 15;
			via_max_layer = (track->m_Layer >> 4) & 15;

			if (via_min_layer == via_max_layer)
				{
				track->m_Layer = 0xF;
				via_min_layer = 0; via_max_layer = 15;
				}

			if( via_max_layer < via_min_layer )
				EXCHG(via_max_layer,via_min_layer);

			if(via_max_layer == CMP_N) via_max_layer = max_layer;
			else via_max_layer++;

			if(via_min_layer == CUIVRE_N) via_min_layer = min_layer;
			else via_min_layer++;

			fprintf(outfile,"v 0 ");
			fprintf(outfile," %d %d", track->m_Start.x/PSCALE, track->m_Start.y/PSCALE);
			fprintf(outfile," %d %d", via_min_layer, via_max_layer);
			fprintf(outfile," %d", plink);
			fprintf(outfile," %d\n", 1);
			/* layer size record */
			fprintf(outfile,"q c 0 %d 0 0 0\n", track->m_Width/PSCALE );
			}

		if(track->m_StructType == TYPETRACK )
			{
			fprintf(outfile,"t 0 %d", track->m_Width/PSCALE);
			fprintf(outfile," %d %d", track->m_Start.x/PSCALE, track->m_Start.y/PSCALE);
			fprintf(outfile," %d %d", track->m_End.x/PSCALE, track->m_End.y/PSCALE);

			if(via_min_layer == CMP_N) via_min_layer = max_layer;
			else via_min_layer++;
			fprintf(outfile," %d", via_min_layer);

			fprintf(outfile," %d\n", 1);	/*Number of corners */

			/* output corner */
			fprintf(outfile,"c");
			fprintf(outfile," %d %d\n", track->m_End.x/PSCALE, track->m_End.y/PSCALE);
			}
		}
}

/***********************************************/
static int GenEdges(BOARD * Pcb, FILE * outfile)
/***********************************************/
/* Generation des contours (edges).
	Il sont générés comme des segments de piste placés sur chaque couche routable.
*/
{
#define NB_CORNERS 4

EDA_BaseStruct * PtStruct;
DRAWSEGMENT * PtDrawSegment;
int ii;
int dx, dy, width, angle;
int ox, oy, fx, fy;
wxPoint lim[4];
int NbItems = 0;

	/* impression des contours  */
	for ( PtStruct = Pcb->m_Drawings; PtStruct != NULL; PtStruct = PtStruct->Pnext)
	  {
		if( PtStruct->m_StructType != TYPEDRAWSEGMENT ) continue;

		PtDrawSegment = (DRAWSEGMENT *) PtStruct;
		if( PtDrawSegment->m_Layer != EDGE_N) continue;

		fx = PtDrawSegment->m_End.x;ox = PtDrawSegment->m_Start.x;
		fy = PtDrawSegment->m_End.y; oy = PtDrawSegment->m_Start.y;
		dx = fx - ox; dy = fy - oy;
		if( (dx == 0) && (dy == 0) ) continue;

		/* elimination des segments non horizontaux, verticaux ou 45 degres,
			non gérés par l'autorouteur */
		if( (dx != 0) && (dy != 0) && (abs(dx) != abs(dy)) )
			continue;

		NbItems++;
		if( outfile == NULL ) continue;		/* car simple decompte des items */


		/* generation de la zone interdite */
		if( dx < 0 )
		  {
			EXCHG(ox,fx); EXCHG(oy,fy); dx = -dx; dy = -dy;
		  }
		if( (dx == 0) && (dy < 0 ) )
		  {
			  EXCHG(oy,fy);dy = -dy;
		  }

		width = PtDrawSegment->m_Width;
		width += g_GridRoutingSize;

		angle = - ArcTangente(dy, dx);
		if (angle % 450)/* not H, V or X */
		  {
			wxBell();
			continue;
		  }

		/* 1er point */
		dx = -width; dy = - width;
		RotatePoint(&dx, &dy, angle);
		lim[0].x = ox + dx;
		lim[0].y = oy + dy;

		/* 2eme point */
		RotatePoint(&dx, &dy, -900);
		lim[1].x = fx + dx;
		lim[1].y = fy + dy;

		/* 3eme point */
		RotatePoint(&dx, &dy, -900);
		lim[2].x = fx + dx;
		lim[2].y = fy + dy;

		/* 4eme point */
		RotatePoint(&dx, &dy, -900);
		lim[3].x = ox + dx;
		lim[3].y = oy + dy;

		if ( angle % 900 )
		  {
		  }
		/* mise a l'echelle */
		for( ii = 0; ii < 4; ii++ )
		  {
			lim[ii].x = (int)( ( (double)lim[ii].x + 0.5) / PSCALE);
			lim[ii].y = (int)( ( (double)lim[ii].y + 0.5) / PSCALE);
		  }

		/* sortie du 1er point */
		fprintf(outfile,"n %d %d %ld %ld %d\n",
				0,  /* layer number, 0 = all layers */
				0,  /* -1 (no via), 0 (no via no track), 1 (no track) */
				(long)lim[0].x, (long)lim[0].y,
				NB_CORNERS);

		/* sortie des autres points */
		for( ii = 1; ii < 4; ii++ )
		  {
			fprintf(outfile,"c %ld %ld\n",
					(long)lim[ii].x, (long)lim[ii].y);
		  }
	  }

	return NbItems;
}


/****************************************************/
void WinEDA_PcbFrame::ReadAutoroutedTracks(wxDC * DC)
/****************************************************/
{
char Line[1024];
wxString FullFileName, msg;
int LineNum = 0, NbTrack = 0, NetCode = 0;
FILE * File;
TRACK * NewTrack;
SEGVIA * NewVia;
int track_count, track_layer, image, track_width;
int via_layer1, via_layer2, via_size;
wxPoint track_start, track_end;
int max_layer = m_Pcb->m_BoardSettings->m_CopperLayerCount;

	/* Calcule du nom du fichier intermediaire de communication */
	FullFileName = m_CurrentScreen->m_FileName;
	ChangeFileNameExt(FullFileName, wxT(".trc"));

	if( (File = wxFopen(FullFileName, wxT("rt"))) == NULL )
		{
		msg = _("Unable to find data file ") + FullFileName;
		DisplayError(this, msg, 20);
		return;
		}
	else
		{
		 msg = _("Reading autorouter data file ") + FullFileName;
		 Affiche_Message(msg);
		}

	setlocale(LC_NUMERIC, "C");

	track_width = g_DesignSettings.m_CurrentTrackWidth;
	via_size = g_DesignSettings.m_CurrentViaSize;
	while( GetLine(File, Line, &LineNum ) != NULL )
	{
	char ident = Line[0];
		switch ( ident )
		{
		case 'j':	// Header, not used
			break;

		case 'R':	// Net record
			sscanf(Line+2, "%d", & NetCode);
			break;
		
		case 'V':	// via record: fmt = V symbol pos_x pos_y layer1 layer2
			sscanf(Line+2, "%d %d %d %d %d", & image,
				& track_start.x, & track_start.y, & via_layer1, &via_layer2);
			via_layer1--; via_layer2--;
			if ( via_layer1 == max_layer-1 ) via_layer1 = CMP_N;
			if ( via_layer2 == max_layer-1 ) via_layer2 = CMP_N;
			NewVia = new SEGVIA(m_Pcb);
			NewVia->m_Start = NewVia->m_End = track_start;
			NewVia->m_Width = via_size;
			NewVia->m_Layer = via_layer1 + (via_layer2<<4);
			if ( NewVia->m_Layer == 0x0F || NewVia->m_Layer == 0xF0)
				NewVia->m_Shape = VIA_NORMALE;
			else NewVia->m_Shape = VIA_ENTERREE;
			NewVia->Insert(m_Pcb, NULL);
			NbTrack++;
			break;
		
		case 'T':	// Track list start: fmt = T image layer t_count
			sscanf(Line+2, "%d %d %d", & image, & track_layer, & track_count);
			track_layer--;
			if ( track_layer == max_layer-1 ) track_layer = CMP_N;
			// Read corners: fmt = C x_pos y_pos
			for ( int ii = 0; ii < track_count; ii++ )
			{
				if( GetLine(File, Line, &LineNum ) != NULL )
				{
					if ( Line[0] != 'C' ) break;
					if ( ii == 0 )
						sscanf(Line+2, "%d %d", & track_start.x, & track_start.y);
					else
					{
						sscanf(Line+2, "%d %d", & track_end.x, & track_end.y);
						NewTrack = new TRACK(m_Pcb);
						NewTrack->m_Width = track_width;
						NewTrack->m_Layer = track_layer;
						NewTrack->m_Start = track_start;
						NewTrack->m_End = track_end;
						track_start = track_end;
						NewTrack->Insert(m_Pcb, NULL);
						NbTrack++;
					}
				}
				else break;
			}
			break;
		
		default:
			break;
		}
	}

	fclose(File);

	setlocale(LC_NUMERIC, "");

	if( NbTrack == 0 ) DisplayError(this, wxT("Warning: No tracks"), 10);
	else
	{
		m_Pcb->m_Status_Pcb = 0;
		m_CurrentScreen->SetModify();
	}

	Compile_Ratsnest(DC, TRUE);
	if( NbTrack ) m_CurrentScreen->SetRefreshReq();
}

