/**********************************************************/
/*	libclass.cpp										  */
/**********************************************************/

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

#include "common.h"
#include "program.h"
#include "libcmp.h"
#include "general.h"

#include "protos.h"


	/*******************************************************/
	/* Methodes relatives a la manipulation des librairies */
	/*******************************************************/

/***************************************************************************************/
LibraryStruct::LibraryStruct(int type, const wxString & name, const wxString & fullname)
/***************************************************************************************/
{
	m_Type = type;					/* type indicator */
	m_Name = name;					/* Name of library loaded. */
	m_FullFileName = fullname;		/* Full File Name (with path) of library loaded. */
	m_NumOfParts = 0;				/* Number of parts this library has. */
	m_Entries = NULL;				/* Parts themselves are saved here. */
	m_Pnext = NULL;					/* Point on next lib in chain. */
	m_Modified = FALSE;				/* flag indicateur d'edition */
	m_TimeStamp = 0;
	m_Flags = 0;
	m_IsLibCache = FALSE;

}

/*****************************************/
void FreeLibraryEntry(LibCmpEntry * Entry)
/*****************************************/
/* Used by PQFreeFunc() to delete all entries
*/
{
	delete Entry;
}

/******************************/
LibraryStruct::~LibraryStruct()
/******************************/
{
	if ( m_Entries ) PQFreeFunc(m_Entries, (void(*)(void *))FreeLibraryEntry);
}


/*******************************************/
bool LibraryStruct::WriteHeader(FILE * file)
/*******************************************/
/* Ecrit l'entete du fichier librairie
*/
{
char BufLine[1024];
bool succes = TRUE;

    DateAndTime(BufLine);
    if ( fprintf(file,"%s %d.%d  Date: %s\n", LIBFILE_IDENT,
						LIB_VERSION_MAJOR, LIB_VERSION_MINOR,
									BufLine) != 5 )
		succes = FALSE;
#if 0
	if ( fprintf(file,"$HEADER\n") != 1 ) succes = FALSE;
	if ( fprintf(file,"TimeStamp %8.8lX\n", m_TimeStamp) != 2 ) succes = FALSE;
	if ( fprintf(file,"Parts %d\n", m_NumOfParts) != 2 ) succes = FALSE;
	if ( fprintf(file,"$ENDHEADER\n") != 1 ) succes = FALSE;
#endif
	return (succes);
}

/***********************************************************/
bool LibraryStruct::ReadHeader(FILE * libfile, int * LineNum)
/***********************************************************/
/* Ecrit l'entete du fichier librairie
*/
{
char Line[1024], * text, * data;

	while (GetLine(libfile, Line, LineNum, sizeof(Line)) )
	{
		text = strtok(Line, " \t\r\n");
		data = strtok(NULL, " \t\r\n");
		if ( stricmp(text, "TimeStamp") == 0 )
			m_TimeStamp = atol(data);
		if ( stricmp(text,"$ENDHEADER") == 0 ) return TRUE;
	}
	return FALSE;
}


	/*********************/
	/* class LibCmpEntry */
	/*********************/
/* Basic class for librarty oomponent description
	Nor directly used
	Used to create the 2 derived classes :
		- EDA_LibCmpAliasStruct
		- EDA_LibComponentStruct
*/

/********************************************************************/
LibCmpEntry::LibCmpEntry(LibrEntryType CmpType, const wxChar * CmpName):
		EDA_BaseStruct(LIBCOMPONENT_STRUCT_TYPE)
/********************************************************************/
{
	Type = CmpType;
	m_Name.m_FieldId = VALUE;
	if ( CmpName ) m_Name.m_Text = CmpName;
}

/******************************/
LibCmpEntry::~LibCmpEntry(void)
/******************************/
{
}


	/*******************************/
	/* class EDA_LibCmpAliasStruct */
	/*******************************/

/* Decrit un alias d'un composant standard en librairie
	Un alias est identique au composant standard
	Dans un alias on ne redefinit que le nom et la documentation associée.
	Le gain de place en memoire est important
*/

EDA_LibCmpAliasStruct:: EDA_LibCmpAliasStruct( const wxChar * CmpName,
				const wxChar * CmpRootName):
	LibCmpEntry(ALIAS, CmpName)
{
	if ( CmpRootName == NULL) m_RootName.Empty();
	else m_RootName = CmpRootName;
}

EDA_LibCmpAliasStruct::~EDA_LibCmpAliasStruct(void)
{
}


	/********************************/
	/* class EDA_LibComponentStruct */
	/********************************/

/* This is a standard component  (in library)
*/
EDA_LibComponentStruct:: EDA_LibComponentStruct( const wxChar * CmpName):
	LibCmpEntry(ROOT, CmpName)
{
	m_Drawings = NULL;
	m_LastDate = 0;
	m_UnitCount = 1;
	m_TextInside = 40;
	m_Options = ENTRY_NORMAL;
	m_UnitSelectionLocked = FALSE;
	m_DrawPinNum = m_DrawPinName = 1;

	Fields = NULL;
	m_Prefix.m_FieldId = REFERENCE;
}

/******************************************************/
EDA_LibComponentStruct::~EDA_LibComponentStruct( void )
/******************************************************/
{
LibEDA_BaseStruct * DrawItem, * NextDrawItem;
LibDrawField *TempField, *field;

	field = Fields; Fields = NULL;
	while (field)
	{
		TempField = field; field = (LibDrawField *) field->Pnext;
		delete TempField;
	}

	/* suppression des elements dependants */
	DrawItem = m_Drawings; m_Drawings = NULL;
	while(DrawItem)
	{
		NextDrawItem = DrawItem->Next();
		delete DrawItem;
		DrawItem = NextDrawItem;
	}
}


/**********************************************************************/
EDA_Rect EDA_LibComponentStruct::GetBoundaryBox( int Unit, int Convert)
/**********************************************************************/
/* Return the componenty boundary box ( in user coordinates )
	The unit Unit, and the shape Convert are considered.
	If Unit == 0, Unit is not used
	if Convert == 0 Convert is non used
**/
{
int xmin, xmax, ymin, ymax, x1, y1;
int * pt, ii;
LibEDA_BaseStruct * DrawEntry;
EDA_Rect BoundaryBox;

	DrawEntry = m_Drawings;
	if ( DrawEntry )
	{
		xmin = ymin = 0x7FFFFFFF; xmax = ymax = 0x80000000;
	}
	else
	{
		xmin = ymin = -50; xmax = ymax = 50;	// Min size in 1/1000 inch
	}

	for ( ;DrawEntry != NULL; DrawEntry = DrawEntry->Next() )
	{
		if ( DrawEntry->m_Unit > 0 ) // The item is non common to units
			if ( (m_UnitCount > 1 ) && (Unit > 0) && (Unit != DrawEntry->m_Unit) )
				continue;
		if ( DrawEntry->m_Convert > 0 )	//The item is not common to alls convert
			if ( (Convert > 0) && (Convert != DrawEntry->m_Convert) )
				continue;
				
		switch ( DrawEntry->m_StructType)
		{
			case COMPONENT_ARC_DRAW_TYPE:
			{
				// Arc is reduced to a line from m_Start to m_End.
				// TO DO better.
				LibDrawArc * Arc = (LibDrawArc *) DrawEntry;
				x1 = Arc->m_Start.x;
				y1 = Arc->m_Start.y;
				xmin = MIN(xmin, x1);
				ymin = MIN(ymin, y1);
				xmax = MAX(xmax, x1);
				ymax = MAX(ymax, y1);
				x1 = Arc->m_End.x;
				y1 = Arc->m_End.y;
				xmin = MIN(xmin, x1);
				ymin = MIN(ymin, y1);
				xmax = MAX(xmax, x1);
				ymax = MAX(ymax, y1);
			}
				break;

			case COMPONENT_CIRCLE_DRAW_TYPE:
			{
				LibDrawCircle * Circle = (LibDrawCircle *) DrawEntry;
				x1 = Circle->m_Pos.x - Circle->m_Rayon;
				y1 = Circle->m_Pos.y - Circle->m_Rayon;
				xmin = MIN(xmin, x1);
				ymin = MIN(ymin, y1);
				x1 = Circle->m_Pos.x + Circle->m_Rayon;
				y1 = Circle->m_Pos.y + Circle->m_Rayon;
				xmax = MAX(xmax, x1);
				ymax = MAX(ymax, y1);
			}
				break;

			case COMPONENT_RECT_DRAW_TYPE:
			{
				LibDrawSquare * Square = (LibDrawSquare *) DrawEntry;
				xmin = MIN(xmin, Square->m_Start.x);
				xmin = MIN(xmin, Square->m_End.x);
				xmax = MAX(xmax, Square->m_Start.x);
				xmax = MAX(xmax, Square->m_End.x);
				ymin = MIN(ymin, Square->m_Start.y);
				ymin = MIN(ymin, Square->m_End.y);
				ymax = MAX(ymax, Square->m_Start.y);
				ymax = MAX(ymax, Square->m_End.y);
			}
				break;

			case COMPONENT_PIN_DRAW_TYPE:
			{
				LibDrawPin * Pin = (LibDrawPin *) DrawEntry;
				x1 = Pin->m_Pos.x;
				y1 = Pin->m_Pos.y;
				xmin = MIN(xmin, x1);
				xmax = MAX(xmax, x1);
				ymin = MIN(ymin, y1);
				ymax = MAX(ymax, y1);
#if 0	// 0 pour englober le point origine de la pin, 1 pour englober toute la pin
				switch ( Pin->Orient )
				{
					case PIN_UP: y1 += Pin->Len; break;
					case PIN_DOWN: y1 -= Pin->Len; break;
					case PIN_LEFT: x1 -= Pin->Len; break;
					case PIN_RIGHT: x1 += Pin->Len; break;
				}
				xmin = MIN(xmin, x1);
				xmax = MAX(xmax, x1);
				ymin = MIN(ymin, y1);
				ymax = MAX(ymax, y1);
#endif
			}
				break;

			case COMPONENT_GRAPHIC_TEXT_DRAW_TYPE:
				break;

			case COMPONENT_POLYLINE_DRAW_TYPE:
			{
				LibDrawPolyline * polyline = (LibDrawPolyline *) DrawEntry;
				pt = polyline->PolyList;
				for( ii = 0; ii < polyline->n; ii++ )
				{
					if( xmin > *pt ) xmin = *pt;
					if( xmax < *pt ) xmax = *pt;
					pt++;
					if( ymin > *pt ) ymin = *pt;
					if( ymax < *pt ) ymax = *pt;
					pt++;
				}
			}
				break;
		}
	}

	// Update the BoundaryBox. Remenber the fact the screen Y axis is the reverse */
	ymax = - ymax; ymin = -ymin;	// Y is is screen axis sense
	// Ensure w and H > 0 (wxRect assume it)
	if ( xmax < xmin ) EXCHG( xmax, xmin );
	if ( ymax < ymin ) EXCHG( ymax, ymin );
	BoundaryBox.SetX(xmin); BoundaryBox.SetWidth(xmax-xmin);
	BoundaryBox.SetY(ymin); BoundaryBox.SetHeight(ymax-ymin);

	return BoundaryBox;
}


	/***************************/
	/* class LibraryFieldEntry */
	/***************************/
/* a Field is a string linked to a component.
	Unlike a pure graphic text, fields can be used in netlist generation
	and other things.

	4 fields have a special meaning:
		REFERENCE
		VALUE
		FOOTPRINT NAME
		SCHEMATIC LINK (reserved but not used in kicad)
*/
LibDrawField::LibDrawField(int idfield) : LibEDA_BaseStruct(COMPONENT_FIELD_DRAW_TYPE)
{
	m_FieldId = idfield;				/* 0 a 11, 0 = REFERENCE, 1 = VALUE*/
	if ( m_FieldId < 0 ) m_FieldId = 0;
	if ( m_FieldId >= NUMBER_OF_FIELDS ) m_FieldId = NUMBER_OF_FIELDS - 1;
	m_Size.x = m_Size.y = DEFAULT_SIZE_TEXT;
	m_Orient = 0;					/* Orientation */
	m_Attributs = 0;				/* Attributs = Non visible ... */
	m_HJustify = GR_TEXT_HJUSTIFY_CENTER;
	m_VJustify = GR_TEXT_VJUSTIFY_CENTER;	/* Justifications Horiz et Vert du texte */
}

LibDrawField::~LibDrawField(void)		// Destructor
{
}

	// Creation et Duplication d'un field
LibDrawField * LibDrawField::GenCopy(void)
{
	LibDrawField * newfield = new LibDrawField(m_FieldId);
	Copy(newfield);

	return newfield;
}

	// copie du field dans le field Target
void LibDrawField::Copy(LibDrawField * Target)
{
	Target->m_Pos = m_Pos;
	Target->m_Size = m_Size;
	Target->m_Orient = m_Orient;
	Target->m_Attributs = m_Attributs;
	Target->m_Text = m_Text;
	Target->m_Name = m_Name;
	Target->m_HJustify = m_HJustify;
	Target->m_VJustify = m_VJustify;
}

/* Elements Graphiques */
LibEDA_BaseStruct::LibEDA_BaseStruct(int struct_type):
	EDA_BaseStruct(struct_type)
{
	m_Unit = 0;		/* Unit identification (for multi part per package)
					0 if the item is common to all units */
	m_Convert = 0;	/* Shape identification (for parts which have a convert shape)
					0 if the item is common to all shapes */
}

/***************************************************************/
LibDrawPin::LibDrawPin(void) : LibEDA_BaseStruct(COMPONENT_PIN_DRAW_TYPE)
/***************************************************************/
{
	m_PinLen = 300;				/* default Pin len */
	m_Orient = PIN_RIGHT;		/* Pin oprient: Up, Down, Left, Right */
	m_PinShape = NONE;			/* Bit a bit: Pin shape (voir enum prec) */
	m_PinType = PIN_UNSPECIFIED;	/* electrical type of pin */
	m_Attributs = 0;			 /* bit 0 != 0: pin invisible */
	m_PinNum = 0;				/*pin number ( i.e. 4 codes Ascii ) */
	m_SizeNum = 50;
	m_SizeName = 50;			/* Default size for pin name and num */
}


/******************************************/
wxPoint LibDrawPin::ReturnPinEndPoint(void)
/******************************************/
/* return the pin end position, for a component in normal orient
*/
{
wxPoint pos = m_Pos;
	switch ( m_Orient )
	{
		case PIN_UP: pos.y += m_PinLen; break;
		case PIN_DOWN: pos.y -= m_PinLen; break;
		case PIN_LEFT: pos.x -= m_PinLen; break;
		case PIN_RIGHT: pos.x += m_PinLen; break;
	}

	return pos;
}

/********************************************************/
int LibDrawPin::ReturnPinDrawOrient(int TransMat[2][2])
/********************************************************/
/* Return the pin real orientation (PIN_UP, PIN_DOWN, PIN_RIGHT, PIN_LEFT),
	according to its orientation,
	AND the matrix transform (rot, mirror) TransMat
*/
{
int orient;
int x1 = 0, y1 = 0;
int t1, t2;
	
	switch ( m_Orient )
	{
		case PIN_UP: y1 = 1; break;
		case PIN_DOWN: y1 = -1; break;
		case PIN_LEFT: x1 = -1; break;
		case PIN_RIGHT: x1 = 1; break;
	}
	t1 = TransMat[0][0] * x1 + TransMat[0][1] * y1;
	t2 = TransMat[1][0] * x1 + TransMat[1][1] * y1;
	orient = PIN_UP;
	if( t1 == 0 )
	{
		if ( t2 > 0 ) orient = PIN_DOWN;
	}
	else
	{
		orient = PIN_RIGHT;
		if ( t1 < 0 ) orient = PIN_LEFT;
	}

	return orient;
}


/****************************************************/
void LibDrawPin::ReturnPinStringNum(wxString & buffer)
/****************************************************/
/* fill the buffer with pin num as a wxString
	Pin num is coded as a long
	Used to print/draw the pin num
*/
{
char ascii_buf[5];
	
	strncpy(ascii_buf, (char*)&m_PinNum,4);
	ascii_buf[4]=0;

	buffer = CONV_FROM_UTF8(ascii_buf);
}
/****************************************************/
void LibDrawPin::SetPinNumFromString(wxString & buffer)
/****************************************************/
/* fill the buffer with pin num as a wxString
	Pin num is coded as a long
	Used to print/draw the pin num
*/
{
char ascii_buf[4];
unsigned ii, len = buffer.Len();
	
	ascii_buf[0] = ascii_buf[1] = ascii_buf[2] = ascii_buf[3] = 0;
	if ( len > 4 ) len = 4;
	for ( ii = 0; ii < len; ii ++ )
	{
		ascii_buf[ii] = buffer.GetChar(ii) & 0xFF;
	}
	strncpy((char*)&m_PinNum, ascii_buf, 4);
}

/*************************************/
LibDrawPin * LibDrawPin::GenCopy(void)
/*************************************/
{
LibDrawPin * newpin = new LibDrawPin();

	newpin->m_Pos = m_Pos;
	newpin->m_PinLen = m_PinLen;
	newpin->m_Orient = m_Orient;
	newpin->m_PinShape = m_PinShape;
	newpin->m_PinType = m_PinType;
	newpin->m_Attributs = m_Attributs;
	newpin->m_PinNum = m_PinNum;
	newpin->m_SizeNum = m_SizeNum;
	newpin->m_SizeName = m_SizeName;
	newpin->m_Unit = m_Unit;
	newpin->m_Convert = m_Convert;
	newpin->m_Flags = m_Flags;

	newpin->m_PinName = m_PinName;

	return newpin;
}

/**************************************************************/
LibDrawArc::LibDrawArc(void) : LibEDA_BaseStruct(COMPONENT_ARC_DRAW_TYPE)
/**************************************************************/
{
	m_Rayon = 0;
	t1 = t2 = 0;
	m_Width = 0;
	m_Fill = NO_FILL;
}


/************************************/
LibDrawArc * LibDrawArc::GenCopy(void)
/************************************/
{
LibDrawArc * newitem = new LibDrawArc();

	newitem->m_Pos = m_Pos;
	newitem->m_Start = m_Start;
	newitem->m_End = m_End;
	newitem->m_Rayon = m_Rayon;
	newitem->t1 = t1;
	newitem->t2 = t2;
	newitem->m_Width = m_Width;
	newitem->m_Unit = m_Unit;
	newitem->m_Convert = m_Convert;
	newitem->m_Flags = m_Flags;
	newitem->m_Fill = m_Fill;
	return newitem;
}


/**********************************************************************/
LibDrawCircle::LibDrawCircle(void) : LibEDA_BaseStruct(COMPONENT_CIRCLE_DRAW_TYPE)
/**********************************************************************/
{
	m_Rayon = 0;
	m_Width = 0;
	m_Fill = NO_FILL;
}

/*******************************************/
LibDrawCircle * LibDrawCircle::GenCopy(void)
/*******************************************/
{
LibDrawCircle * newitem = new LibDrawCircle();

	newitem->m_Pos = m_Pos;
	newitem->m_Rayon = m_Rayon;
	newitem->m_Width = m_Width;
	newitem->m_Unit = m_Unit;
	newitem->m_Convert = m_Convert;
	newitem->m_Flags = m_Flags;
	newitem->m_Fill = m_Fill;
	return newitem;
}


/*****************************************************************/
LibDrawText::LibDrawText(void) : LibEDA_BaseStruct(COMPONENT_GRAPHIC_TEXT_DRAW_TYPE)
/*****************************************************************/
{
	m_Horiz = TEXT_ORIENT_HORIZ;
	m_Size = wxSize(50,50);
	m_Type = 0;
}

/***************************************/
LibDrawText * LibDrawText::GenCopy(void)
/***************************************/
{
LibDrawText * newitem = new LibDrawText();

	newitem->m_Pos = m_Pos;
	newitem->m_Horiz = m_Horiz;
	newitem->m_Size = m_Size;
	newitem->m_Type = m_Type;
	newitem->m_Unit = m_Unit;
	newitem->m_Convert = m_Convert;
	newitem->m_Flags = m_Flags;
	newitem->m_Text = m_Text;
	return newitem;
}



LibDrawSquare::LibDrawSquare(void) : LibEDA_BaseStruct(COMPONENT_RECT_DRAW_TYPE)
{
	m_Width = 0;
	m_Fill = NO_FILL;
}

LibDrawSquare * LibDrawSquare::GenCopy(void)
{
LibDrawSquare * newitem = new LibDrawSquare();

	newitem->m_Start = m_Start;
	newitem->m_End = m_End;
	newitem->m_Width = m_Width;
	newitem->m_Unit = m_Unit;
	newitem->m_Convert = m_Convert;
	newitem->m_Flags = m_Flags;
	newitem->m_Fill = m_Fill;
	return newitem;
}

LibDrawSegment::LibDrawSegment(void) : LibEDA_BaseStruct(COMPONENT_LINE_DRAW_TYPE)
{
	m_Width = 0;
}

LibDrawSegment * LibDrawSegment::GenCopy(void)
{
LibDrawSegment * newitem = new LibDrawSegment();

	newitem->m_Start = m_Start;
	newitem->m_End = m_End;
	newitem->m_Width = m_Width;
	newitem->m_Unit = m_Unit;
	newitem->m_Convert = m_Convert;
	newitem->m_Flags = m_Flags;
	return newitem;
}


LibDrawPolyline::LibDrawPolyline(void) : LibEDA_BaseStruct(COMPONENT_POLYLINE_DRAW_TYPE)
{
	n = 0;
	PolyList = NULL;
	m_Fill = NO_FILL;
	m_Width = 0;
}

/************************************************/
LibDrawPolyline * LibDrawPolyline::GenCopy(void)
/************************************************/
{
LibDrawPolyline * newitem = new LibDrawPolyline();
int size;

	newitem->n = n;
	size = sizeof(int) * 2 * n;
	if( size )
	{
		newitem->PolyList = (int*)MyMalloc(size);
		memcpy(newitem->PolyList, PolyList, size);
	}
	newitem->m_Width = m_Width;
	newitem->m_Unit = m_Unit;
	newitem->m_Convert = m_Convert;
	newitem->m_Flags = m_Flags;
	newitem->m_Fill = m_Fill;
	return newitem;
}

/***************************************************/
void LibDrawPolyline::AddPoint(const wxPoint & point)
/***************************************************/
/* add a point to the polyline coordinate list, and realloc the memory
*/
{
int allocsize;

	n++;
	allocsize =  2 * sizeof(int) * n;
	if (PolyList == NULL)
		PolyList = (int*)MyMalloc( allocsize );
	else
		PolyList = (int*)realloc(PolyList, allocsize );

	PolyList[(n*2) - 2] = point.x;
	PolyList[(n*2) - 1] = - point.y;
}


