/********************************************/
	/* AUTOROUTAGE PCB : routines d'autoroutage */
	/********************************************/

	/* fichier WORK.CC */

#include "fctsys.h"
#include "gr_basic.h"

#include "common.h"
#include "pcbnew.h"
#include "autorout.h"
#include "cell.h"

#include "protos.h"
/**/

struct CWORK /* a unit of work is a hole-pair to connect */
	{
	struct CWORK *Next;
	int FromRow;		/* source row		*/
	int FromCol;		/* source column	*/
	int net_code;		/* net_code			*/
	int ToRow;			/* target row		*/
	int ToCol;			/* target column	*/
	CHEVELU *pt_rats;	/* chevelu correspondant*/
	int ApxDist;		/* approximate distance	*/
	int Cost;			/* cost for sort by length */
	int Priority;       /* routage priority */
	};

/* pointers to the first and last item of work to do */
static CWORK *Head = NULL;
static CWORK *Tail = NULL;
static CWORK *Current = NULL;

/* Routines definies ici : */

void InitWork();
void ReInitWork();
int SetWork( int, int, int, int, int, CHEVELU *, int );
void GetWork( int *, int *, int *, int *, int *, CHEVELU ** );
void SortWork();


	/************************/
	/* void InitWork () */
	/************************/

 /* initialize the work list */
void InitWork()
{
CWORK *ptr;

	while( (ptr = Head) != NULL )
		{
		Head = ptr->Next; MyFree( ptr );
		}
	Tail = Current = NULL;
}


	/*************************/
	/* void ReInitWork() */
	/*************************/

 /* initialize the work list */
void ReInitWork()
	{
	Current = Head;
	}

/*****************************************************************************/
/*int SetWork(int r1,int c1,int* n_c,int r2,int c2,CHEVELU * pt_ch,int pri )*/
/*****************************************************************************/

/* add a unit of work to the work list
	Return:
		1 si OK
		0 si defaut d'allocation memoire
*/
static int GetCost(int r1,int c1,int r2,int c2);

int SetWork(int r1,int c1,int n_c,int r2,int c2,CHEVELU * pt_ch,int pri )
{
CWORK *p;

	if( (p = (CWORK *)MyMalloc( sizeof(CWORK) )) != NULL )
		{
		p->FromRow = r1;
		p->FromCol = c1;
		p->net_code = n_c;
		p->ToRow = r2;
		p->ToCol = c2;
		p->pt_rats = pt_ch;
		p->ApxDist = GetApxDist( r1, c1, r2, c2 );
		p->Cost = GetCost( r1, c1, r2, c2 );
		p->Priority = pri;
		p->Next = NULL;
		if (Head) /* attach at end */
			Tail->Next = p;
		else /* first in list */
			Head = Current = p;
		Tail = p;
		return(1);
		}
	else /* can't get any more memory */
		return(0);
}


	/************************************************************************/
	/* void GetWork (int *r1,int *c1,int *r2,int *c2, char **n1,char **n2 ) */
	/************************************************************************/

void GetWork (int *r1,int *c1,int *n_c,int *r2,int *c2,CHEVELU** pt_ch )
	/* fetch a unit of work from the work list */
{
	if (Current)
		{
		*r1 = Current->FromRow;
		*c1 = Current->FromCol;
		*n_c = Current->net_code;
		*r2 = Current->ToRow;
		*c2 = Current->ToCol;
		*pt_ch = Current->pt_rats;
		Current = Current->Next;
		}

	else { /* none left */
		*r1 = *c1 = *r2 = *c2 = ILLEGAL;
		*n_c = 0;
		*pt_ch = NULL;
		}
}


	/***********************/
	/* void SortWork() */
	/***********************/

/* order the work items; shortest (low cost) first */
void SortWork()
{
CWORK *p;
CWORK *q0; /* put PRIORITY PAD_CONNECTs in q0 */
CWORK *q1; /* sort other PAD_CONNECTs in q1 */
CWORK *r;

	q0 = q1 = NULL;
	while( (p = Head) != NULL )
		{ /* prioritize each work item */
		Head = Head->Next;
		if (p->Priority)
			{ /* put at end of priority list */
			p->Next = NULL;
			if ((r = q0) == NULL) /* empty list? */
				q0 = p;
			else
				{ /* attach at end */
				while (r->Next) /* search for end */
					r = r->Next;
				r->Next = p; /* attach */
				}
			}
		else if ( ((r = q1) == NULL) || (p->Cost < q1->Cost) )
			{
			p->Next = q1; q1 = p;
			}
		else { /* find proper position in list */
			while (r->Next && p->Cost >= r->Next->Cost) r = r->Next;
			p->Next = r->Next; r->Next = p;
			}
		}

	if( (p = q0) != NULL)
		{ /* any priority PAD_CONNECTs? */
		while (q0->Next) q0 = q0->Next;
		q0->Next = q1;
		}
	else p = q1;

	/* reposition Head and Tail */
	for(Head = Current = Tail = p; Tail && Tail->Next; Tail = Tail->Next) ;
}


/* routine de calcul du cout d'un chevelu:
cout = (|dx| + |dy|) * handicap
handicap = 1 si dx ou dy = 0, max si |dx| # |dy|
*/
static int GetCost(int r1,int c1,int r2,int c2)
{
int dx, dy, mx, my;
float incl;

	dx = abs(c2 - c1);
	dy = abs(r2 - r1);
	incl = 1.0;
	mx = dx; my = dy;
	if ( mx < my ) { mx = dy; my = dx;}
    if ( mx ) incl += (2*(float)my/mx);

	return (int)((dx+dy) * incl) ;
}