	/****************************/
	/*	EESchema - eesavlib.cpp	*/
	/****************************/

/* Write Routines to save schematic libraries and library components (::WriteDescr() members)
*/

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

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

#include "protos.h"

/* Routines locales */

/* Variables locales */


static bool WriteLibEntryDateAndTime(FILE * ExportFile,
			EDA_LibComponentStruct * LibEntry);


static int  fill_tab[3] = { 'N', 'F', 'f' };

/***********************************************/
bool LibDrawArc::WriteDescr( FILE * ExportFile )
/***********************************************/
/* format
A centre_posx centre_posy rayon start_angle end_angle unit convert fill('N', 'F' ou 'f') startx starty endx endy
*/
{	
int x1 = t1; if(x1 > 1800) x1 -= 3600;
int x2 = t2; if(x2 > 1800) x2 -= 3600;
 
	fprintf(ExportFile,"A %d %d %d %d %d %d %d %d %c %d %d %d %d\n",
			m_Pos.x, m_Pos.y,
			m_Rayon, x1, x2,
			m_Unit,m_Convert,
			m_Width, fill_tab[m_Fill],
			m_ArcStart.x, m_ArcStart.y, m_ArcEnd.x, m_ArcEnd.y);
    return FALSE;
}

/***************************************************/
bool LibDrawCircle::WriteDescr( FILE * ExportFile )
/***************************************************/
{                
	fprintf(ExportFile,"C %d %d %d %d %d %d %c\n",
                m_Pos.x, m_Pos.y,
				m_Rayon,
				m_Unit,m_Convert,
				m_Width, fill_tab[m_Fill]);
    return FALSE;
}

/************************************************/
bool LibDrawText::WriteDescr( FILE * ExportFile )
/************************************************/
{
wxString text = m_Text;
	
	text.Replace( wxT(" "), wxT("~") );	// Spaces are not allowed: changed to '~'
	
	fprintf(ExportFile,"T %d %d %d %d %d %d %d %s\n",
				m_Horiz,
				m_Pos.x, m_Pos.y,
				m_Size.x, m_Type,
				m_Unit,m_Convert,
				CONV_TO_UTF8(text) );
    return FALSE;
}

/***************************************************/
bool LibDrawSquare::WriteDescr( FILE * ExportFile )
/***************************************************/
{
	fprintf(ExportFile,"S %d %d %d %d %d %d %d %c\n",
                m_Pos.x, m_Pos.y, m_End.x, m_End.y,
				m_Unit,m_Convert,
				m_Width, fill_tab[m_Fill]);
    return FALSE;
}


/************************************************/
bool LibDrawPin::WriteDescr( FILE * ExportFile )
/************************************************/
{
int	Etype = 'I';
wxString StringPinNum;
    
	switch(m_PinType)
		{
		case PIN_INPUT: Etype = 'I'; break;
		case PIN_OUTPUT: Etype = 'O'; break;
		case PIN_BIDI: Etype = 'B'; break;
		case PIN_TRISTATE: Etype = 'T'; break;
		case PIN_PASSIVE: Etype = 'P'; break;
		case PIN_UNSPECIFIED: Etype = 'U'; break;
		case PIN_POWER_IN: Etype = 'W'; break;
		case PIN_POWER_OUT: Etype = 'w'; break;
		case PIN_OPENCOLLECTOR: Etype = 'C'; break;
		case PIN_OPENEMITTER:	Etype = 'E'; break;
		}
        
	ReturnPinStringNum(StringPinNum);
	if ( StringPinNum.IsEmpty() ) StringPinNum = wxT("~");
	
    if( ! m_PinName.IsEmpty() )
		fprintf(ExportFile,"X %s", CONV_TO_UTF8(m_PinName) );
	else fprintf(ExportFile,"X ~");

	fprintf(ExportFile," %s %d %d %d %c %d %d %d %d %c",
					CONV_TO_UTF8(StringPinNum),
					m_Pos.x, m_Pos.y,
					(int)m_PinLen, (int)m_Orient,
					m_PinNumSize, m_PinNameSize,
					m_Unit,m_Convert, Etype);

	if( (m_PinShape) || (m_Attributs & PINNOTDRAW) )
		fprintf(ExportFile," ");
	if (m_Attributs & PINNOTDRAW) fprintf(ExportFile,"N");
	if (m_PinShape & INVERT) fprintf(ExportFile,"I");
	if (m_PinShape & CLOCK) fprintf(ExportFile,"C");
	if (m_PinShape & LOWLEVEL_IN) fprintf(ExportFile,"L");
	if (m_PinShape & LOWLEVEL_OUT) fprintf(ExportFile,"V");

	fprintf(ExportFile,"\n");
    return FALSE;
}

/****************************************************/
bool LibDrawPolyline::WriteDescr( FILE * ExportFile )
/****************************************************/
{
int ii, *ptpoly;
    
	fprintf(ExportFile,"P %d %d %d %d", 
                        n,
						m_Unit,m_Convert,
						m_Width);
	ptpoly = PolyList;
	for( ii = n ; ii > 0; ii-- )
		{
		fprintf(ExportFile,"  %d %d", *ptpoly, *(ptpoly+1) );
		ptpoly += 2;
		}
	fprintf(ExportFile," %c\n", fill_tab[m_Fill]);
    return FALSE;
}


/**************************************************/
bool LibDrawField::WriteDescr( FILE * ExportFile )
/**************************************************/
{
int hjustify, vjustify;
wxString text = m_Text;
	
	hjustify = 'C';
	if ( m_HJustify == GR_TEXT_HJUSTIFY_LEFT ) hjustify = 'L';
	else if ( m_HJustify == GR_TEXT_HJUSTIFY_RIGHT ) hjustify = 'R';
	vjustify = 'C';
	if ( m_VJustify == GR_TEXT_VJUSTIFY_BOTTOM) vjustify = 'B';
	else if ( m_VJustify == GR_TEXT_VJUSTIFY_TOP) vjustify = 'T';
	if ( text.IsEmpty() ) text = wxT("~");
	fprintf(ExportFile,"F%d \"%s\" %d %d %d %c %c %c %c",
                m_FieldId, CONV_TO_UTF8(text),
				m_Pos.x, m_Pos.y,
				m_Size.x,
				m_Orient == 0 ? 'H' : 'V',
				(m_Attributs & TEXT_NO_VISIBLE )? 'I' : 'V',
				hjustify, vjustify );
	// Save field name, if necessary
	if ( m_FieldId >= FIELD1 && ! m_Name.IsEmpty() )
		fprintf(ExportFile," \"%s\"", CONV_TO_UTF8(m_Name) );

	fprintf(ExportFile,"\n");
    return FALSE;
}

/**********************************************************/
LibEDA_BaseStruct * CopyDrawEntryStruct( wxWindow * frame,
						 LibEDA_BaseStruct * DrawItem)
/**********************************************************/
/* Routine de Duplication d'une structure DrawLibItem d'une partlib
	Parametres d'entree:
		DrawEntry = pointeur sur la structure a dupliquer
	La structure nouvelle est creee, mais n'est pas inseree dans le
	chainage
	Retourne:
		Pointeur sur la structure creee
*/
{
LibEDA_BaseStruct * NewDrawItem = NULL;
wxString msg;

	switch(DrawItem->m_StructType)
		{
		case COMPONENT_ARC_DRAW_TYPE:
			NewDrawItem = ((LibDrawArc*)DrawItem)->GenCopy();
			break;

		case COMPONENT_CIRCLE_DRAW_TYPE:
			NewDrawItem = ((LibDrawCircle*)DrawItem)->GenCopy();
			break;

		case COMPONENT_RECT_DRAW_TYPE:
			NewDrawItem = ((LibDrawSquare*)DrawItem)->GenCopy();
			break;

		case COMPONENT_PIN_DRAW_TYPE:
			NewDrawItem = ((LibDrawPin*)DrawItem)->GenCopy();
			break;

		case COMPONENT_GRAPHIC_TEXT_DRAW_TYPE:
			NewDrawItem = ((LibDrawText*)DrawItem)->GenCopy();
			break;

		case COMPONENT_POLYLINE_DRAW_TYPE:
			NewDrawItem = ((LibDrawPolyline*)DrawItem)->GenCopy();
			break;

		default:
			msg.Printf( wxT("CopyDrawLibEntryStruct: unknown Draw Type %d"),
				DrawItem->m_StructType);
			DisplayError(frame, msg);
			break;
		}

	return(NewDrawItem);
}

/*************************************************************************************************/
EDA_LibComponentStruct * CopyLibEntryStruct ( wxWindow * frame, EDA_LibComponentStruct * OldEntry)
/*************************************************************************************************/
/* Routine de copie d'une partlib
	Parametres d'entree: pointeur sur la structure de depart
	Parametres de sortie: pointeur sur la structure creee
	Do not copy new items ( i.e. with m_Flag  & IS_NEW)
*/
{
EDA_LibComponentStruct * NewStruct;
LibEDA_BaseStruct * NewDrawings, * OldDrawings;
LibEDA_BaseStruct * LastItem;
LibDrawField * OldField, * NewField;

	if( OldEntry->Type != ROOT )
	{
		DisplayError(frame, wxT("CopyLibEntryStruct(): Type != ROOT"));
		return(NULL);
	}

	NewStruct = new EDA_LibComponentStruct(NULL);
	OldEntry->m_Prefix.Copy(&NewStruct->m_Prefix);
	OldEntry->m_Name.Copy(&NewStruct->m_Name);

	NewStruct->m_UnitCount = OldEntry->m_UnitCount;
	NewStruct->m_TextInside = OldEntry->m_TextInside;
	NewStruct->m_DrawPinNum = OldEntry->m_DrawPinNum;
	NewStruct->m_DrawPinName = OldEntry->m_DrawPinName;
	NewStruct->m_Options = OldEntry->m_Options;
	NewStruct->m_UnitSelectionLocked = OldEntry->m_UnitSelectionLocked;

	/* Copie des sous structures: */
	NewStruct->m_AliasList = OldEntry->m_AliasList;
	NewStruct->m_Doc  = OldEntry->m_Doc;
	NewStruct->m_KeyWord  = OldEntry->m_KeyWord;
	NewStruct->m_DocFile  = OldEntry->m_DocFile;

	/* Copie des champs */
	for(OldField = OldEntry->Fields; OldField != NULL;
						OldField = (LibDrawField*)OldField->Pnext)
	{
		NewField = OldField->GenCopy();
		NewField->Pnext = NewStruct->Fields;
		NewStruct->Fields = NewField;
	}

	/* Copie des elements type Drawing */
	LastItem = NULL;
	for(OldDrawings = OldEntry->m_Drawings; OldDrawings != NULL; OldDrawings = OldDrawings->Next())
	{
		if ( ( OldDrawings->m_Flags  & IS_NEW) != 0 ) continue;
		NewDrawings = CopyDrawEntryStruct(frame, OldDrawings);
		if ( NewDrawings )
		{
			if (LastItem == NULL ) NewStruct->m_Drawings = NewDrawings;
			else LastItem->Pnext = NewDrawings;
			LastItem = NewDrawings;
			NewDrawings->Pnext = NULL;
		}
		else	// Probleme rencontré: arret de copie
		{
			OldDrawings->m_StructType = TYPE_NOT_INIT;
			DisplayError(frame, wxT("CopyLibEntryStruct(): error: aborted"));
			break;
		}
	}

	/* Copy the footprint filter list */
	for ( unsigned ii = 0 ; ii < OldEntry->m_FootprintList.GetCount(); ii++ )
		NewStruct->m_FootprintList.Add(OldEntry->m_FootprintList[ii]);
	
	return(NewStruct);
}


/********************************************************/
int WriteOneLibEntry(wxWindow * frame, FILE * ExportFile,
					EDA_LibComponentStruct * LibEntry)
/********************************************************/

/* Routine d'ecriture du composant pointe par LibEntry
	dans le fichier ExportFile( qui doit etre deja ouvert)
	return: 0 si Ok
			-1 si err write
			1 si composant non ecrit ( type ALIAS )
*/
#define UNUSED 0
{
LibEDA_BaseStruct *DrawEntry;
LibDrawField * Field;

	if( LibEntry->Type != ROOT ) return(1);

	/* Creation du commentaire donnant le nom du composant */
	fprintf(ExportFile,"#\n# %s\n#\n", CONV_TO_UTF8(LibEntry->m_Name.m_Text));

	/* Generation des lignes utiles */
	fprintf(ExportFile,"DEF");
	if( (LibEntry->m_Name.m_Attributs & TEXT_NO_VISIBLE) == 0)
		 fprintf(ExportFile," %s", CONV_TO_UTF8(LibEntry->m_Name.m_Text));
	else fprintf(ExportFile," ~%s", CONV_TO_UTF8(LibEntry->m_Name.m_Text));

	if( ! LibEntry->m_Prefix.m_Text.IsEmpty())
		fprintf(ExportFile," %s", CONV_TO_UTF8(LibEntry->m_Prefix.m_Text));
	else fprintf(ExportFile," ~");
	fprintf(ExportFile," %d %d %c %c %d %c %c\n",
		UNUSED, LibEntry->m_TextInside,
		LibEntry->m_DrawPinNum ? 'Y' : 'N',
		LibEntry->m_DrawPinName ? 'Y' : 'N',
		LibEntry->m_UnitCount, LibEntry->m_UnitSelectionLocked ? 'L' : 'F',
		LibEntry->m_Options == ENTRY_POWER ? 'P' : 'N');

	WriteLibEntryDateAndTime(ExportFile, LibEntry);

	/* Position / orientation / visibilite des champs */
    LibEntry->m_Prefix.WriteDescr( ExportFile );
    LibEntry->m_Name.WriteDescr( ExportFile );

	for ( Field = LibEntry->Fields; Field!= NULL;
						Field = (LibDrawField*)Field->Pnext )
	{
		if( Field->m_Text.IsEmpty() && Field->m_Name.IsEmpty() ) continue;
        Field->WriteDescr( ExportFile );
	}

	/* Sauvegarde de la ligne "ALIAS" */
	if( LibEntry->m_AliasList.GetCount() != 0)
	{
		fprintf(ExportFile,"ALIAS");
		unsigned ii;
		for ( ii = 0; ii < LibEntry->m_AliasList.GetCount(); ii++ )
			fprintf(ExportFile," %s", CONV_TO_UTF8(LibEntry->m_AliasList[ii]));
		fprintf(ExportFile,"\n");
	}

	/* Write the footprint filter list */
	if( LibEntry->m_FootprintList.GetCount() != 0)
	{
		fprintf(ExportFile,"$FPLIST\n");
		unsigned ii;
		for ( ii = 0; ii < LibEntry->m_FootprintList.GetCount(); ii++ )
			fprintf(ExportFile," %s\n", CONV_TO_UTF8(LibEntry->m_FootprintList[ii]));
		fprintf(ExportFile,"$ENDFPLIST\n");
	}

	/* Sauvegarde des elements de trace */
	DrawEntry = LibEntry->m_Drawings;
	if(LibEntry->m_Drawings)
	{
		/* we sort the draw items, in order to have an edition more easy,
		when a file editing "by hand" is made */
		LibEntry->SortDrawItems();
		
		fprintf(ExportFile,"DRAW\n");
		DrawEntry = LibEntry->m_Drawings;
		while( DrawEntry )
		{
			switch( DrawEntry->m_StructType)
			{
				case COMPONENT_ARC_DRAW_TYPE:
					#define DRAWSTRUCT ((LibDrawArc *) DrawEntry)
                    DRAWSTRUCT->WriteDescr( ExportFile );
					break;

				case COMPONENT_CIRCLE_DRAW_TYPE:
					#undef DRAWSTRUCT
					#define DRAWSTRUCT ((LibDrawCircle *) DrawEntry)
                    DRAWSTRUCT->WriteDescr( ExportFile );
					break;

				case COMPONENT_GRAPHIC_TEXT_DRAW_TYPE:
					#undef DRAWSTRUCT
					#define DRAWSTRUCT ((LibDrawText *) DrawEntry)
                    DRAWSTRUCT->WriteDescr( ExportFile );
					break;

				case COMPONENT_RECT_DRAW_TYPE:
					#undef DRAWSTRUCT
					#define DRAWSTRUCT ((LibDrawSquare *) DrawEntry)
                    DRAWSTRUCT->WriteDescr( ExportFile );
 					break;

				case COMPONENT_PIN_DRAW_TYPE:
					#undef DRAWSTRUCT
					#define DRAWSTRUCT ((LibDrawPin *) DrawEntry)
                    DRAWSTRUCT->WriteDescr( ExportFile );
					break;

				case COMPONENT_POLYLINE_DRAW_TYPE:
					#undef DRAWSTRUCT
					#define DRAWSTRUCT ((LibDrawPolyline *) DrawEntry)
                    DRAWSTRUCT->WriteDescr( ExportFile );
					break;

				default: DisplayError(frame, wxT("Save Lib: Unknown Draw Type"));
					break;
			}

			DrawEntry = DrawEntry->Next();
		}
		fprintf(ExportFile,"ENDDRAW\n");
	}

	fprintf(ExportFile,"ENDDEF\n");

	return(0);
}

/*************************************************************************/
int WriteOneDocLibEntry(FILE * ExportFile, EDA_LibComponentStruct * LibEntry)
/*************************************************************************/

/* Routine d'ecriture de la doc du composant pointe par LibEntry
	dans le fichier ExportFile( qui doit etre deja ouvert)
	return: 0 si Ok
			1 si err write
	Cependant, si i tous les Pointeurs sur textes sont nulls ( pas de Doc )
		rien ne sera ecrit.
*/
{

	if( (LibEntry->m_Doc.IsEmpty() ) &&
		(LibEntry->m_KeyWord.IsEmpty() ) &&
		(LibEntry->m_DocFile.IsEmpty() ) )
		return(0);

	/* Generation des lignes utiles */
	fprintf(ExportFile,"#\n$CMP %s\n", CONV_TO_UTF8(LibEntry->m_Name.m_Text));

	if( ! LibEntry->m_Doc.IsEmpty())
		fprintf(ExportFile,"D %s\n", CONV_TO_UTF8(LibEntry->m_Doc));

	if( ! LibEntry->m_KeyWord.IsEmpty())
		fprintf(ExportFile,"K %s\n", CONV_TO_UTF8(LibEntry->m_KeyWord));

	if( ! LibEntry->m_DocFile.IsEmpty())
		fprintf(ExportFile,"F %s\n", CONV_TO_UTF8(LibEntry->m_DocFile));

	fprintf(ExportFile,"$ENDCMP\n");
	return(0);
}

/*********************************************************************************/
int SaveOneLibrary(wxWindow * frame, const wxString & FullFileName, LibraryStruct * Library)
/*********************************************************************************/
/* Sauvegarde en fichier la librairie pointee par Library, sous le nom
	FullFileName.
	2 fichiers sont crees
	 - La librarie
	 - le fichier de documentation

	une sauvegarde .bak de l'ancien fichier librairie est cree
	une sauvegarde .bck de l'ancien fichier documentation est cree

	return:
		0 si OK
		1 si erreur
*/
{
FILE * SaveFile, * SaveDocFile;
EDA_LibComponentStruct *LibEntry;
char Line[1024];
int err = 1;
wxString Name,DocName,BakName, msg;

	if(Library == NULL) return(err);

	Name = FullFileName;

	/* L'ancien fichier lib est renomme en .bak */
	if( wxFileExists(Name) )
	{
		BakName = Name; ChangeFileNameExt(BakName, wxT(".bak"));
		wxRemoveFile(BakName);
		if( ! wxRenameFile(Name, BakName) )
		{
			msg = wxT("Failed to rename old lib file ") + BakName;
			DisplayError(frame, msg, 20);
		}
	}
 

	DocName = Name; ChangeFileNameExt(DocName,DOC_EXT);
	/* L'ancien fichier doc lib est renomme en .bck */
	if( wxFileExists(DocName) )
	{
		BakName = DocName; ChangeFileNameExt(BakName, wxT(".bck") );
		wxRemoveFile(BakName);
		if( ! wxRenameFile(DocName, BakName) )
		{
			msg = wxT("Failed to save old doc lib file ") + BakName;
			DisplayError(frame, msg, 20);
		}
	}
		

	SaveFile = wxFopen(Name, wxT("wt") );
	if (SaveFile == NULL)
	{
		msg = wxT("Failed to create Lib File ") + Name;
		DisplayError(frame, msg, 20);
		return(err);
	}

	SaveDocFile = wxFopen(DocName, wxT("wt") );
	if (SaveDocFile == NULL)
	{
		msg = wxT("Failed to create DocLib File ") + DocName;
		DisplayError(frame, msg, 20);
		return(err);
	}

	Library->m_Modified = 0;

	/* Creation de l'entete de la librairie */
	Library->m_TimeStamp = GetTimeStamp();
	Library->WriteHeader(SaveFile);
	fprintf(SaveDocFile,"%s  Date: %s\n", DOCFILE_IDENT,
            DateAndTime(Line) );

 
	/* Sauvegarde des composant: */
	PQCompFunc((PQCompFuncType) LibraryEntryCompare);
	LibEntry = (EDA_LibComponentStruct *) PQFirst(&Library->m_Entries, FALSE);

	while( LibEntry )
	{
		err = WriteOneLibEntry(frame, SaveFile, LibEntry);
		err = WriteOneDocLibEntry(SaveDocFile, LibEntry);

		LibEntry = (EDA_LibComponentStruct *)
					PQNext(Library->m_Entries, LibEntry, NULL);
	}

	fprintf(SaveFile,"#\n#End Library\n");
	fprintf(SaveDocFile,"#\n#End Doc Library\n");
	fclose(SaveFile);
	fclose(SaveDocFile);
	return(err);
}


/*************************************************************************************/
static bool WriteLibEntryDateAndTime(FILE * ExportFile, EDA_LibComponentStruct * LibEntry)
/*************************************************************************************/
/* lit date et time de modif composant sous le format:
	"Ti yy/mm/jj hh:mm:ss"
*/
{
int year,mon,day,hour,min,sec;

	if ( LibEntry->m_LastDate == 0 ) return TRUE;

	sec = LibEntry->m_LastDate & 63;
	min = (LibEntry->m_LastDate >> 6) & 63 ;
	hour = (LibEntry->m_LastDate >> 12) & 31;
	day = (LibEntry->m_LastDate >> 17) & 31;
	mon = (LibEntry->m_LastDate >> 22) & 15;
	year  = (LibEntry->m_LastDate >> 26) + 1990;

	fprintf(ExportFile,"Ti %d/%d/%d %d:%d:%d\n",year,mon,day,hour,min,sec);

	return TRUE;
}


