	/*******************************************************/
	/* Module de generation de la Netliste , selon Formats */
	/*******************************************************/

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

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

#include "protos.h"


/* Routines locales */
static void Write_GENERIC_NetList(WinEDA_SchematicFrame * frame, const wxString & FullFileName);
static void WriteNetListPCBNEW(WinEDA_SchematicFrame * frame, FILE *f,
					bool with_pcbnew);
static void WriteNetListCADSTAR(WinEDA_SchematicFrame * frame, FILE *f);
static void WriteListOfNetsCADSTAR( FILE * f, ObjetNetListStruct *ObjNet );
static void WriteNetListPspice(WinEDA_SchematicFrame * frame, FILE *f, bool use_netnames);

static void WriteGENERICListOfNets( FILE * f, ObjetNetListStruct *ObjNet );
static void AddPinToComponentPinList(EDA_SchComponentStruct *Component,
								LibDrawPin *PinEntry);
static void FindOthersUnits(EDA_SchComponentStruct *Component );
static int SortPinsByNum(ObjetNetListStruct **Pin1, ObjetNetListStruct **Pin2);
static void EraseDuplicatePins(ObjetNetListStruct **TabPin, int NbrPin);

static void ClearUsedFlags(WinEDA_SchematicFrame * frame);



/* Variable locales */
static int s_SortedPinCount;
static ObjetNetListStruct **s_SortedComponentPinList;




/******************************************************************************/
void WriteNetList(WinEDA_SchematicFrame * frame, const wxString & FileNameNL,
				bool use_netnames)
/*******************************************************************************/
/* Create the netlist file ( Format is given by g_NetFormat )
	bool use_netnames is used only for Spice netlist
*/
{
FILE *f = NULL;

	if ( g_NetFormat < NET_TYPE_CUSTOM1 )
	{
		if ((f = wxFopen(FileNameNL, wxT("wt"))) == NULL)
		{
			wxString msg =  _("Failed to create file ") + FileNameNL;
			DisplayError(frame, msg);
			return;
		}
	}

wxBusyCursor Busy;

	switch ( g_NetFormat )
	{
		case NET_TYPE_PCBNEW :
			WriteNetListPCBNEW(frame, f, TRUE);
			fclose(f);
			break;

		case NET_TYPE_ORCADPCB2 :
			WriteNetListPCBNEW(frame, f, FALSE);
			fclose(f);
			break;

		case NET_TYPE_CADSTAR :
			WriteNetListCADSTAR(frame, f);
			fclose(f);
			break;

		case NET_TYPE_SPICE :
			WriteNetListPspice(frame, f, use_netnames);
			fclose(f);
			break;

		case NET_TYPE_CUSTOM1 :
		case NET_TYPE_CUSTOM2 :
		case NET_TYPE_CUSTOM3 :
		case NET_TYPE_CUSTOM4 :
		case NET_TYPE_CUSTOM5 :
		case NET_TYPE_CUSTOM6 :
		case NET_TYPE_CUSTOM7 :
		case NET_TYPE_CUSTOM8 :
			Write_GENERIC_NetList(frame, FileNameNL);
			break;

		default:
			DisplayError(frame, wxT("WriteNetList() err: Unknown Netlist Format"));
			break;
	}
}


/****************************************************************************/
static EDA_SchComponentStruct * FindNextComponentAndCreatPinList(
		EDA_BaseStruct * DrawList)
/****************************************************************************/
/*	Find a "suitable" component from the DrawList
	build its pin list s_SortedComponentPinList.
	The list is sorted by pin num
	A suitable component is a "new" real component (power symbols are not considered)

	alloc memory for s_SortedComponentPinList if s_SortedComponentPinList == NULL
	Must be deallocated by the user
*/
{
EDA_SchComponentStruct * Component = NULL;
EDA_LibComponentStruct *Entry;
LibEDA_BaseStruct *DEntry;
	
	s_SortedPinCount = 0;

	for ( ; DrawList != NULL; DrawList = DrawList->Next() )
	{
		if ( DrawList->m_StructType != DRAW_LIB_ITEM_STRUCT_TYPE ) continue;
		Component = (EDA_SchComponentStruct *) DrawList;
	
		 /* already tested ? : */
		if( Component->m_FlagControlMulti == 1 ) continue; /* yes */
	
		Entry = FindLibPart(Component->m_ChipName.GetData(), wxEmptyString, FIND_ROOT);
		if( Entry  == NULL) continue;
			
		/* Power symbol and other component which have the reference starting by
		"#" are not included in netlist (pseudo components) */
		if( Component->m_Field[REFERENCE].m_Text[0] == '#' ) continue;
	
		/* Create the pin table for this component */
		int ii = sizeof(ObjetNetListStruct) * MAXPIN;
		if ( s_SortedComponentPinList == NULL )
			s_SortedComponentPinList = (ObjetNetListStruct **) MyMalloc(ii);
		memset(s_SortedComponentPinList, 0 , ii);
	
		DEntry = Entry->m_Drawings;
		for ( ;DEntry != NULL; DEntry = DEntry->Next())
		{
			if ( DEntry->m_StructType != COMPONENT_PIN_DRAW_TYPE) continue;
			if( DEntry->m_Unit &&
				(DEntry->m_Unit != Component->m_Multi) ) continue;
			if( DEntry->m_Convert &&
				(DEntry->m_Convert != Component->m_Convert)) continue;
			{
				AddPinToComponentPinList(Component, (LibDrawPin*)DEntry);
			}
		}
	
		Component->m_FlagControlMulti = 1;
	
		if (Entry->m_UnitCount > 1) FindOthersUnits(Component);
	
		/* Tri sur le numero de Pin de TabListePin */
		qsort(s_SortedComponentPinList, s_SortedPinCount, sizeof(ObjetNetListStruct*),
				  (int (*)(const void *, const void *)) SortPinsByNum);
	
		/* Elimination des Pins redondantes du s_SortedComponentPinList */
		EraseDuplicatePins(s_SortedComponentPinList, s_SortedPinCount);

		return Component;
	}
	
	return NULL;
}

/**************************************************************************************/
static wxString ReturnPinNetName(ObjetNetListStruct *Pin,
	const wxString& DefaultFormatNetname)
/**************************************************************************************/
/* Return the net name for the pin Pin.
	Net name is:
	"?" if pin not connected
	"netname" for global net (like gnd, vcc ..
	"netname_sheetnumber" for the usual nets
*/
{
int netcode = Pin->m_NetCode;
wxString NetName;
	
	if( (netcode == 0 ) || ( Pin->m_FlagOfConnection != CONNECT ) )
	{
		return NetName;
	}
	else
	{
		int jj;
		for (jj = 0; jj < g_NbrObjNet; jj++)
		{
			if( g_TabObjNet[jj].m_NetCode != netcode) continue;
			if( ( g_TabObjNet[jj].m_Type != NET_GLOBLABEL) &&
				( g_TabObjNet[jj].m_Type != NET_LABEL) &&
				( g_TabObjNet[jj].m_Type != NET_PINLABEL) ) continue;

			NetName = * g_TabObjNet[jj].m_Label;
			break;
		}
		
		if( ! NetName.IsEmpty() )
		{
			if( g_TabObjNet[jj].m_Type != NET_PINLABEL )
				NetName << wxT("_") << g_TabObjNet[jj].m_SheetNumber;
		}
		else
		{
			NetName.Printf(DefaultFormatNetname.GetData(), netcode);
		}
	}
	return NetName;
}

/***********************************************************************/
void Write_GENERIC_NetList(WinEDA_SchematicFrame * frame,
		const wxString & FullFileName)
/***********************************************************************/
/* Create a generic netlist, and call an external netlister
	to change the netlist syntax and create the file
*/
{
wxString Line, FootprintName;
BASE_SCREEN *CurrScreen;
EDA_BaseStruct *DrawList;
EDA_SchComponentStruct *Component;
wxString netname;
int ii;
FILE * tmpfile;
wxString TmpFullFileName = FullFileName;	
	
	ChangeFileNameExt(TmpFullFileName, wxT(".tmp"));

	if ((tmpfile = wxFopen(TmpFullFileName, wxT("wt"))) == NULL)
	{
		wxString msg =  _("Failed to create file ") + TmpFullFileName;
		DisplayError(frame, msg);
		return;
	}
	
	ClearUsedFlags(frame);	/* Reset the flags FlagControlMulti in all schematic files*/
	fprintf( tmpfile, "$BeginNetlist\n" );

	/* Create netlist module section */
	fprintf( tmpfile, "$BeginComponentList\n" );
	for(CurrScreen = ScreenSch; CurrScreen != NULL; CurrScreen = (BASE_SCREEN*)CurrScreen->Pnext )
	{
		for ( DrawList = CurrScreen->EEDrawList; DrawList != NULL; DrawList = DrawList->Pnext )
		{
			DrawList = Component = FindNextComponentAndCreatPinList(DrawList);
			if ( Component == NULL ) break;	// No component left

			FootprintName.Empty();
			if( ! Component->m_Field[FOOTPRINT].IsVoid() )
			{
				FootprintName = Component->m_Field[FOOTPRINT].m_Text;
				FootprintName.Replace(wxT(" "), wxT("_"));
			}

			fprintf( tmpfile, "\n$BeginComponent\n" );
			fprintf(tmpfile, "TimeStamp=%8.8lX\n", Component->m_TimeStamp);
			fprintf(tmpfile, "Footprint=%s\n", CONV_TO_UTF8(FootprintName));
			Line =  wxT("Reference=") + Component->m_Field[REFERENCE].m_Text + wxT("\n");
			Line.Replace(wxT(" "), wxT("_"));
			fprintf(tmpfile, CONV_TO_UTF8(Line));

			Line = Component->m_Field[VALUE].m_Text;
			Line.Replace( wxT(" "), wxT("_"));
			fprintf(tmpfile, "Value=%s\n", CONV_TO_UTF8(Line));

			Line = Component->m_ChipName;
			Line.Replace(wxT(" "), wxT("_"));
			fprintf(tmpfile, "Libref=%s\n", CONV_TO_UTF8(Line));

			// Write pin list:
			fprintf( tmpfile, "$BeginPinList\n" );
			for (ii = 0; ii < s_SortedPinCount; ii++)
			{
				ObjetNetListStruct *Pin = s_SortedComponentPinList[ii];
				if( ! Pin ) continue;
				netname = ReturnPinNetName(Pin, wxT("$-%.6d"));
				if ( netname.IsEmpty() ) netname = wxT("?");
				fprintf( tmpfile,"%.4s=%s\n",(char *)&Pin->m_PinNum,
					CONV_TO_UTF8(netname));
			}

			fprintf( tmpfile, "$EndPinList\n" );
			fprintf( tmpfile, "$EndComponent\n" );
		}
	}
	
	MyFree(s_SortedComponentPinList);
	s_SortedComponentPinList = NULL;
	
	fprintf( tmpfile, "$EndComponentList\n" );

	fprintf( tmpfile, "\n$BeginNets\n" );
	WriteGENERICListOfNets( tmpfile, g_TabObjNet );
	fprintf( tmpfile, "$EndNets\n" );
	fprintf( tmpfile, "\n$EndNetlist\n" );
	fclose(tmpfile);
	
	// Call the external module (plug in )
	
	if ( g_NetListerCommandLine.IsEmpty() ) return;

wxString CommandFile;
	if ( wxIsAbsolutePath(g_NetListerCommandLine) )
		CommandFile = g_NetListerCommandLine;
	else CommandFile = FindKicadFile(g_NetListerCommandLine);
	
	CommandFile += wxT(" ") + TmpFullFileName;
	CommandFile += wxT(" ") + FullFileName;

	wxExecute(CommandFile, wxEXEC_SYNC);
	
}


/********************************************************/
static void ClearUsedFlags(WinEDA_SchematicFrame * frame)
/********************************************************/
/* Clear flag FlagControlMulti, used in netlist generation */
{
SCH_SCREEN *screen;
EDA_BaseStruct *DrawList;
	
	EDA_ScreenList ScreenList(NULL);
	for ( screen = ScreenList.GetFirst(); screen != NULL; screen = ScreenList.GetNext() )
	{
		DrawList = screen->EEDrawList;
		while ( DrawList )
		{
			if( DrawList->m_StructType == DRAW_LIB_ITEM_STRUCT_TYPE)
			{
				EDA_SchComponentStruct * Component = (EDA_SchComponentStruct *) DrawList;
				Component->m_FlagControlMulti = 0;
			}
			DrawList = DrawList->Pnext;
		}
	}
}

/*************************************************************/
static void WriteNetListPspice(WinEDA_SchematicFrame * frame, FILE *f,
		 bool use_netnames)
/*************************************************************/
/* Routine de generation du fichier netliste ( Format PSPICE )
	si use_netnames = TRUE
		les nodes sont identifies par le netname
	sinon	les nodes sont identifies par le netnumber

	tous les textes graphiques commençant par [.-+]pspice ou  [.-+]gnucap
	sont considérés comme des commandes a placer dans la netliste
		[.-]pspice ou gnucap sont en debut
		+pspice et +gnucap sont en fin de netliste
*/
{
char Line[1024];
SCH_SCREEN *screen;
EDA_BaseStruct *DrawList;
EDA_SchComponentStruct *Component;
int ii, nbitems;
wxString text;
wxArrayString SpiceCommandAtBeginFile, SpiceCommandAtEndFile;
wxString msg;
#define BUFYPOS_LEN 4
wxChar bufnum[BUFYPOS_LEN+1];

	DateAndTime(Line);
	fprintf( f, "* %s (Spice format) creation date: %s\n\n", NETLIST_HEAD_STRING, Line );

	/* Create text list starting by [.-]pspice , or [.-]gnucap (simulator commands) */
	/* and create text list starting by [+]pspice , or [+]gnucap (simulator commands) */
	bufnum[BUFYPOS_LEN] = 0;
	EDA_ScreenList ScreenList(NULL);
	for ( screen = ScreenList.GetFirst(); screen != NULL; screen = ScreenList.GetNext() )
	{
		for ( DrawList = screen->EEDrawList; DrawList != NULL; DrawList = DrawList->Pnext )
		{
			wxChar ident;
			if ( DrawList->m_StructType != DRAW_TEXT_STRUCT_TYPE ) continue;
			#define DRAWTEXT ((DrawTextStruct *) DrawList)
			text = DRAWTEXT->m_Text; if ( text.IsEmpty() ) continue;
			ident = text.GetChar(0);
			if ( ident != '.' && ident != '-' && ident != '+' ) continue;
			text.Remove(0,1);	//Remove the first char.
			text.Remove(6);		//text contains 6 char.
			if( ( text == wxT("pspice") ) || ( text == wxT("gnucap") ) )
			{
				/* Put the Y position as an ascii string, for sort by vertical position,
				using usual sort string by alphabetic value */
				int ypos = DRAWTEXT->m_Pos.y;
				for ( ii = 0; ii < BUFYPOS_LEN; ii++ )
				{
					bufnum[BUFYPOS_LEN-1-ii] = (ypos & 63) + ' '; ypos >>= 6;
				}
				text = DRAWTEXT->m_Text.AfterFirst( ' ');
				msg.Printf( wxT("%s %s"),bufnum, text.GetData());	// First BUFYPOS_LEN char are the Y position
				if ( ident == '+' ) SpiceCommandAtEndFile.Add(msg);
				else SpiceCommandAtBeginFile.Add(msg);
			}
		}
	}

	/* Print texts starting by [.-]pspice , ou [.-]gnucap (of course, without the Y position string)*/
	nbitems = SpiceCommandAtBeginFile.GetCount();
	if ( nbitems )
	{
		SpiceCommandAtBeginFile.Sort();
		for(ii= 0; ii < nbitems; ii++ )
		{
			SpiceCommandAtBeginFile[ii].Remove(0, BUFYPOS_LEN);
			SpiceCommandAtBeginFile[ii].Trim(TRUE);
			SpiceCommandAtBeginFile[ii].Trim(FALSE);
			fprintf( f, "%s\n", CONV_TO_UTF8(SpiceCommandAtBeginFile[ii]) );
		}
	}
	fprintf( f, "\n" );


	/* Create component list */
	ClearUsedFlags(frame);	/* Reset the flags FlagControlMulti in all schematic files*/
	for ( screen = ScreenList.GetFirst(); screen != NULL; screen = ScreenList.GetNext() )
	{
		for( DrawList = screen->EEDrawList; DrawList != NULL; DrawList = DrawList->Pnext )
		{
			DrawList = Component = FindNextComponentAndCreatPinList(DrawList);
			if ( Component == NULL ) break;

			fprintf(f, "%s ", CONV_TO_UTF8(Component->m_Field[REFERENCE].m_Text));

			// Write pin list:
			for (ii = 0; ii < s_SortedPinCount; ii++)
			{
				ObjetNetListStruct *Pin = s_SortedComponentPinList[ii];
				if( ! Pin ) continue;
				wxString NetName = ReturnPinNetName(Pin, wxT("N-%.6d"));
				if ( NetName.IsEmpty() ) NetName = wxT("?");
				if( use_netnames) fprintf( f," %s", CONV_TO_UTF8(NetName));
				else	// Use number for net names (with net number = 0 for "GND"
				{
					// NetName = "0" is "GND" net for Spice
					if( NetName == wxT("0") || NetName == wxT("GND") )
						fprintf( f," 0");
					else fprintf( f," %d", Pin->m_NetCode);
				}
			}
			fprintf(f, " %s\n", CONV_TO_UTF8(Component->m_Field[VALUE].m_Text));
		}
	}

	MyFree(s_SortedComponentPinList);
	s_SortedComponentPinList = NULL;
	
	/* Print texts starting by [+]pspice , ou [+]gnucap */
	nbitems = SpiceCommandAtEndFile.GetCount();
	if ( nbitems )
	{
		fprintf( f, "\n" );
		SpiceCommandAtEndFile.Sort();
		for(ii= 0; ii < nbitems; ii++ )
		{
			SpiceCommandAtEndFile[ii].Remove(0,  + BUFYPOS_LEN);
			SpiceCommandAtEndFile[ii].Trim(TRUE);
			SpiceCommandAtEndFile[ii].Trim(FALSE);
			fprintf( f, "%s\n", CONV_TO_UTF8(SpiceCommandAtEndFile[ii]));
		}
	}

	fprintf( f, "\n.end\n" );
}

/*****************************************************************************************/
static void WriteNetListPCBNEW(WinEDA_SchematicFrame * frame, FILE *f, bool with_pcbnew)
/*****************************************************************************************/
/* Routine de generation du fichier netliste ( Format ORCAD PCB 2 ameliore )
	si with_pcbnew = FALSE
		format PCBNEW (OrcadPcb2 + commentaires et liste des nets)
	si with_pcbnew = FALSE
		Format ORCADPCB2 strict
*/
{
wxString Line, FootprintName;
char Buf[256];
SCH_SCREEN *CurrScreen;
EDA_BaseStruct *DrawList;
EDA_SchComponentStruct *Component;
int ii;
EDA_SchComponentStruct ** CmpList = NULL;
int CmpListCount = 0, CmpListSize = 1000;
	
	DateAndTime(Buf);
	if ( with_pcbnew )
		fprintf( f, "# %s created  %s\n(\n", NETLIST_HEAD_STRING, Buf);
	else fprintf( f, "( { %s created  %s }\n", NETLIST_HEAD_STRING, Buf );


	/* Create netlist module section */
	ClearUsedFlags(frame);	/* Reset the flags FlagControlMulti in all schematic files*/

	EDA_ScreenList ScreenList(NULL);
	for ( CurrScreen = ScreenList.GetFirst(); CurrScreen != NULL; CurrScreen = ScreenList.GetNext() )
	{
		for ( DrawList = CurrScreen->EEDrawList; DrawList != NULL; DrawList = DrawList->Pnext )
		{
			DrawList = Component = FindNextComponentAndCreatPinList(DrawList);
			if ( Component == NULL ) break;

			/* Get the Component FootprintFilter and put the component in CmpList if filter is not void */
			EDA_LibComponentStruct *Entry;
			if( (Entry = FindLibPart(Component->m_ChipName.GetData(),wxEmptyString,FIND_ROOT)) != NULL)
			{
				if ( Entry->m_FootprintList.GetCount() != 0 )	/* Put in list */
				{
					if ( CmpList == NULL )
						CmpList = (EDA_SchComponentStruct **) MyZMalloc(sizeof(EDA_SchComponentStruct *) * CmpListSize);
					if ( CmpListCount >= CmpListSize )
					{
						CmpListSize += 1000;
						CmpList = (EDA_SchComponentStruct **) realloc(CmpList, sizeof(EDA_SchComponentStruct *) * CmpListSize);
					}
					CmpList[CmpListCount] = Component;
					CmpListCount++;
				}
			}
			
			if( ! Component->m_Field[FOOTPRINT].IsVoid() )
			{
				FootprintName = Component->m_Field[FOOTPRINT].m_Text;
				FootprintName.Replace( wxT(" "), wxT("_") );
			}
			else FootprintName = wxT("$noname");

			Line = Component->m_Field[REFERENCE].m_Text;
			Line.Replace( wxT(" "), wxT("_") );
			fprintf(f, " ( %8.8lX %s",
						Component->m_TimeStamp,
						CONV_TO_UTF8(FootprintName));
			fprintf(f, "  %s", CONV_TO_UTF8(Line));

			Line = Component->m_Field[VALUE].m_Text;
			Line.Replace( wxT(" "), wxT("_") );
			fprintf(f, " %s", CONV_TO_UTF8(Line));

			if ( with_pcbnew )	// Add the lib name for this component
			{
				Line = Component->m_ChipName;
				Line.Replace( wxT(" "), wxT("_") );
				fprintf(f, " {Lib=%s}", CONV_TO_UTF8(Line));
			}
			fprintf(f, "\n");

			// Write pin list:
			for (ii = 0; ii < s_SortedPinCount; ii++)
			{
				ObjetNetListStruct *Pin = s_SortedComponentPinList[ii];
				if( ! Pin ) continue;
				wxString netname = ReturnPinNetName(Pin, wxT("N-%.6d"));
				if ( netname.IsEmpty() ) netname = wxT(" ?");
				fprintf( f,"  ( %4.4s %s )\n",(char *)&Pin->m_PinNum,
						CONV_TO_UTF8(netname));
			}

			fprintf(f, " )\n");
		}
	}
	fprintf( f, ")\n*\n");

	MyFree(s_SortedComponentPinList);
	s_SortedComponentPinList = NULL;

	/* Write the allowed footprint list for each component */
	if ( with_pcbnew && CmpList)
	{
		fprintf( f, "{ Allowed footprints by component:\n" );
		EDA_LibComponentStruct *Entry;
		for ( ii = 0; ii < CmpListCount; ii ++ )
		{
			Component = CmpList[ii];
			Entry = FindLibPart(Component->m_ChipName.GetData(),wxEmptyString,FIND_ROOT);
			Line = Component->m_Field[REFERENCE].m_Text;
			Line.Replace( wxT(" "), wxT("_") );
			fprintf(f, "$component %s\n", CONV_TO_UTF8(Line));
			/* Write the footprint list */
			for ( unsigned int jj = 0; jj < Entry->m_FootprintList.GetCount(); jj ++ )
			{
				fprintf(f, " %s\n", CONV_TO_UTF8(Entry->m_FootprintList[jj]));
			}
		fprintf(f, "$endlist\n");
		}
		fprintf(f, "$endfootprintlist\n}\n");
	}
	if ( CmpList ) free(CmpList);

	if ( with_pcbnew )
	{
		fprintf( f, "{ Pin List by Nets\n" );
		WriteGENERICListOfNets( f, g_TabObjNet );
		fprintf( f, "}\n" );
		fprintf( f, "#End\n" );
	}
}


/*************************************************************************************/
static void AddPinToComponentPinList( EDA_SchComponentStruct *Component, LibDrawPin *Pin)
/*************************************************************************************/
/* Add a new pin description in the pin list s_SortedComponentPinList
	a pin description is a pointer to the corresponding structure
	created by BuildNetList() in the table g_TabObjNet
*/
{
int ii;

	/* Search the PIN description for Pin in g_TabObjNet*/
	for (ii = 0; ii < g_NbrObjNet; ii++)
	{
		if ( g_TabObjNet[ii].m_Type != NET_PIN) continue;
		if ( g_TabObjNet[ii].m_Link != Component) continue;
		if ( g_TabObjNet[ii].m_PinNum != Pin->m_PinNum) continue;
		{
			s_SortedComponentPinList[s_SortedPinCount] = & g_TabObjNet[ii];
			s_SortedPinCount++;
			if (s_SortedPinCount >= MAXPIN)
			{
				/* Log message for Internal error */
				DisplayError(NULL, wxT("AddPinToComponentPinList err: MAXPIN reached")); return;
			}
		}
	}
}


/**********************************************************************/
static void EraseDuplicatePins(ObjetNetListStruct **TabPin, int NbrPin)
/**********************************************************************/
/*
	Routine qui elimine les Pins de meme Numero de la liste des objets
	(Liste des Pins d'un boitier) passee en entree
	Ces pins redondantes proviennent des pins (alims... ) communes a plusieurs
	elements d'un boitier a multiple parts.
*/
{
int ii, jj;

	for (ii = 0; ii < NbrPin-1; ii++)
	{
		if( TabPin[ii] == NULL) continue;	/* Deja supprime */
		if( TabPin[ii]->m_PinNum != TabPin[ii+1]->m_PinNum) continue;
		/* 2 Pins doublees */
		for( jj = ii+1; jj < NbrPin ; jj++ )
		{
			if( TabPin[ii]->m_PinNum != TabPin[jj]->m_PinNum) break;
			TabPin[jj] = NULL;
		}
	}
}



/**********************************************************************/
static void FindOthersUnits(EDA_SchComponentStruct *Component )
/**********************************************************************/

/* Recherche les autres parts du boitier auquel appartient la part Component,
	pour les boitiers a parts multiples.
	Appelle AddPinToComponentPinList() pour classer les pins des parts trouvees
*/
{
EDA_BaseStruct *DrawList;
EDA_SchComponentStruct *Component2;
EDA_LibComponentStruct *Entry;
LibEDA_BaseStruct *DEntry;
SCH_SCREEN * screen;

	EDA_ScreenList ScreenList(NULL);
	for ( screen = ScreenList.GetFirst(); screen != NULL; screen = ScreenList.GetNext() )
	{
		DrawList = screen->EEDrawList;
		while ( DrawList )
		{
			switch( DrawList->m_StructType )
			{
				case DRAW_LIB_ITEM_STRUCT_TYPE :
					Component2 = (EDA_SchComponentStruct *) DrawList;

					if ( Component2->m_FlagControlMulti == 1 )  break;

					if ( Component2->m_Field[REFERENCE].m_Text.CmpNoCase(
							  Component->m_Field[REFERENCE].m_Text) != 0 )
						break;

					Entry = FindLibPart(Component2->m_ChipName.GetData(), wxEmptyString, FIND_ROOT);
 					if( Entry  == NULL) break;
					if( Component2->m_Field[REFERENCE].m_Text[0] == '#' ) break;

					if (Entry->m_Drawings != NULL)
					{
						DEntry = Entry->m_Drawings;
						for ( ;DEntry != NULL; DEntry = DEntry->Next())
						{
							if ( DEntry->m_StructType != COMPONENT_PIN_DRAW_TYPE) continue;
							if( DEntry->m_Unit &&
								(DEntry->m_Unit != Component2->m_Multi) ) continue;
							if( DEntry->m_Convert &&
								(DEntry->m_Convert != Component2->m_Convert)) continue;
							{
								AddPinToComponentPinList(Component2, (LibDrawPin*)DEntry);
							}
						}
					}
					Component2->m_FlagControlMulti = 1;
					break;

				default: break;
			}
			DrawList = DrawList->Pnext;
		}
	}
}


/**************************************************************************/
static int SortPinsByNum(ObjetNetListStruct **Pin1, ObjetNetListStruct **Pin2)
/**************************************************************************/
/* Routine de comparaison pour le tri des pins par numero croissant
	du tableau des pins s_SortedComponentPinList par qsort()
*/
{
ObjetNetListStruct * Obj1, * Obj2;
int Num1, Num2;
char Line[5];

	Obj1 = *Pin1; Obj2 = *Pin2;
	Num1 = Obj1->m_PinNum; Num2 = Obj2->m_PinNum;
	Line[4] = 0; memcpy(Line, &Num1, 4 ); Num1 = atoi(Line);
	memcpy(Line, &Num2, 4 ); Num2 = atoi(Line);
	return (Num1 - Num2);
}

/*************************************************************************/
static void WriteGENERICListOfNets( FILE * f, ObjetNetListStruct *ObjNet )
/*************************************************************************/
/* Ecrit dans le fichier f la liste des nets ( classee par NetCodes ), et des
elements qui y sont connectes
*/
{
int ii, jj;
int NetCode, LastNetCode = -1;
int SameNetcodeCount = 0;
EDA_SchComponentStruct * Cmp;
wxString NetName, CmpRef;
wxString NetcodeName;
char FirstItemInNet[1024];
	
	for (ii = 0; ii < g_NbrObjNet; ii++)
	{
		if( (NetCode = ObjNet[ii].m_NetCode) != LastNetCode )	// New net found, write net id;
		{
			SameNetcodeCount = 0;		// Items count for this net
			NetName.Empty();
			for (jj = 0; jj < g_NbrObjNet; jj++)	// Find a label (if exists) for this net
			{
				if( ObjNet[jj].m_NetCode != NetCode) continue;
				if( ( ObjNet[jj].m_Type != NET_GLOBLABEL) &&
					( ObjNet[jj].m_Type != NET_LABEL) &&
					( ObjNet[jj].m_Type != NET_PINLABEL) ) continue;

				NetName = * g_TabObjNet[jj].m_Label; break;
			}

			NetcodeName.Printf( wxT("Net %d "), NetCode);
			NetcodeName += wxT("\"");
			if( ! NetName.IsEmpty() )
			{
				NetcodeName += NetName;
				if( g_TabObjNet[jj].m_Type != NET_PINLABEL)	// usual net name, add it the sheet number
					NetcodeName << wxT("_") << g_TabObjNet[jj].m_SheetNumber;
			}
			NetcodeName += wxT("\"");
			LastNetCode = NetCode;
		}

		if ( ObjNet[ii].m_Type != NET_PIN ) continue;

		Cmp = (EDA_SchComponentStruct*) ObjNet[ii].m_Link;
		CmpRef = Cmp->m_Field[REFERENCE].m_Text;
		if ( CmpRef.StartsWith( wxT("#") ) ) continue;	// Pseudo component (Like Power symbol)

		// Print the pin list for this net, if  2 or more items are connected:
		SameNetcodeCount++;
		if ( SameNetcodeCount == 1 )	/* first item for this net found,
				Print this connection, when a second item will be found */
		{
			sprintf(FirstItemInNet, " %s %.4s\n", CONV_TO_UTF8(CmpRef),
					(const char*) & ObjNet[ii].m_PinNum);
		}
		if ( SameNetcodeCount == 2 )	// Second item for this net found, Print the Net name, and the first item
		{
			fprintf( f, "%s\n", CONV_TO_UTF8(NetcodeName));
			fputs( FirstItemInNet, f);
		}
		
		if ( SameNetcodeCount >= 2 )
			fprintf( f, " %s %.4s\n", CONV_TO_UTF8(CmpRef),
					(const char*) & ObjNet[ii].m_PinNum);
	}
}



/* Generation des netlistes au format CadStar */
wxString StartLine( wxT("."));

/*********************************************************/
static void WriteNetListCADSTAR(WinEDA_SchematicFrame * frame, FILE *f)
/*********************************************************/
/* Routine de generation du fichier netliste ( Format CADSTAR )
Entete:
..HEA
..TIM 2004 07 29 16 22 17
..APP "Cadstar RINF Output - Version 6.0.2.3"
..UNI INCH 1000.0 in
..TYP FULL

liste des composants:
..ADD_COM    X1         "CNT D41612 (48PTS MC CONTOUR)"
..ADD_COM    U2         "74HCT245D" "74HCT245D"

Connexions:
..ADD_TER    RR2        6          "$42"
..TER        U1         100
            CA         6

..ADD_TER    U2         6          "$59"
..TER        U7         39
            U6         17
            U1         122

..ADD_TER    P2         1          "$9"
..TER        T3         1
            U1         14
*/
{
wxString StartCmpDesc = StartLine + wxT("ADD_COM");
wxString msg;
wxString FootprintName;
char Line[1024];
BASE_SCREEN *CurrScreen;
EDA_BaseStruct *DrawList;
EDA_SchComponentStruct *Component;
	wxString Title = g_Main_Title + wxT(" ") + GetBuildVersion();

	fprintf( f, "%sHEA\n", CONV_TO_UTF8(StartLine));
	DateAndTime(Line);
	fprintf( f, "%sTIM %s\n", CONV_TO_UTF8(StartLine), Line );
	fprintf( f, "%sAPP ", CONV_TO_UTF8(StartLine) );
	fprintf( f, "\"%s\"\n", CONV_TO_UTF8(Title) );
	fprintf( f, "\n");

	/* Create netlist module section */
	ClearUsedFlags(frame);	/* Reset the flags FlagControlMulti in all schematic files*/
	EDA_ScreenList ScreenList(NULL);
	for ( CurrScreen = ScreenList.GetFirst(); CurrScreen != NULL; CurrScreen = ScreenList.GetNext() )
	{
		for ( DrawList = CurrScreen->EEDrawList; DrawList != NULL; DrawList = DrawList->Pnext )
		{
			DrawList = Component = FindNextComponentAndCreatPinList(DrawList);
			if ( Component == NULL ) break;

			if( ! Component->m_Field[FOOTPRINT].IsVoid() )
			{
				FootprintName = Component->m_Field[FOOTPRINT].m_Text;
				FootprintName.Replace(wxT(" "), wxT("_"));
			}
			else FootprintName = wxT("$noname");

			msg = Component->m_Field[REFERENCE].m_Text;
			msg.Replace( wxT(" "), wxT("_"));
			fprintf(f, "%s     ", CONV_TO_UTF8(StartCmpDesc));
			fprintf(f, "%s", CONV_TO_UTF8(msg));

			msg = Component->m_Field[VALUE].m_Text;
			msg.Replace(wxT(" "), wxT("_"));
			fprintf(f, "     \"%s\"", CONV_TO_UTF8(msg));
			fprintf(f, "\n");

			}
		}
	fprintf( f, "\n");

	MyFree(s_SortedComponentPinList);
	s_SortedComponentPinList = NULL;

	WriteListOfNetsCADSTAR( f, g_TabObjNet );

	fprintf( f, "\n%sEND\n", CONV_TO_UTF8(StartLine) );
}

/*************************************************************************/
static void WriteListOfNetsCADSTAR( FILE * f, ObjetNetListStruct *ObjNet )
/*************************************************************************/
/* Ecrit dans le fichier f la liste des nets ( classee par NetCodes ), et des
pins qui y sont connectes
format:
.ADD_TER    RR2        6          "$42"
.TER        U1         100
            CA         6
*/
{
wxString InitNetDesc = StartLine + wxT("ADD_TER");
wxString StartNetDesc = StartLine + wxT("TER");
wxString NetcodeName, InitNetDescLine;
int ii, jj, print_ter = 0;
int NetCode, LastNetCode = -1;
EDA_SchComponentStruct * Cmp;
wxString NetName;

	for (ii = 0; ii < g_NbrObjNet; ii++) ObjNet[ii].m_Flag = 0;

	for (ii = 0; ii < g_NbrObjNet; ii++)
	{
		// Get the NetName of the current net :
		if( (NetCode = ObjNet[ii].m_NetCode) != LastNetCode )
		{
			NetName.Empty();
			for (jj = 0; jj < g_NbrObjNet; jj++)
			{
				if( ObjNet[jj].m_NetCode != NetCode) continue;
				if( ( ObjNet[jj].m_Type != NET_GLOBLABEL) &&
					( ObjNet[jj].m_Type != NET_LABEL) &&
					( ObjNet[jj].m_Type != NET_PINLABEL) ) continue;

				NetName = * ObjNet[jj].m_Label; break;
			}
			NetcodeName = wxT("\"");
			if( ! NetName.IsEmpty() )
			{
				NetcodeName += NetName;
				if( g_TabObjNet[jj].m_Type != NET_PINLABEL)
					NetcodeName << wxT("_") << g_TabObjNet[jj].m_SheetNumber;
			}
			else	// this net has no name: create a default name $<net number>
				NetcodeName <<  wxT("$") << NetCode;
			NetcodeName += wxT("\"");
			LastNetCode = NetCode;
			print_ter = 0;
		}


		if ( ObjNet[ii].m_Type != NET_PIN ) continue;

		if ( ObjNet[ii].m_Flag != 0 ) continue;

		Cmp = (EDA_SchComponentStruct*) ObjNet[ii].m_Link;

		if ( Cmp->m_Field[REFERENCE].m_Text[0] == '#' )
			continue;	// Pseudo composant (symboles d'alims)

		switch ( print_ter )
		{
			case 0:
				{
				char buf[5];
				wxString str_pinnum;
				strncpy(buf, (char*) & ObjNet[ii].m_PinNum,4); buf[4] = 0;
				str_pinnum = CONV_FROM_UTF8(buf);
				InitNetDescLine.Printf( wxT("\n%s   %s   %.4s     %s"),
						InitNetDesc.GetData(),
						Cmp->m_Field[REFERENCE].m_Text.GetData(),
						str_pinnum.GetData(), NetcodeName.GetData());
				}
				print_ter++;
				break;

			case 1:
				fprintf( f, "%s\n", CONV_TO_UTF8(InitNetDescLine));
				fprintf( f, "%s       %s   %.4s\n",
						CONV_TO_UTF8(StartNetDesc),
						CONV_TO_UTF8(Cmp->m_Field[REFERENCE].m_Text),
						(char*) & ObjNet[ii].m_PinNum );
				print_ter++;
				break;

			default:
				fprintf( f, "            %s   %.4s\n",
					CONV_TO_UTF8(Cmp->m_Field[REFERENCE].m_Text),
					(char*) & ObjNet[ii].m_PinNum );
				break;
		}

		ObjNet[ii].m_Flag = 1;
		// Recherche des pins redondantes et mise a 1 de m_Flag,
		//	pour ne pas generer plusieurs fois la connexion
		for (jj = ii + 1; jj < g_NbrObjNet; jj++)
		{
			if( ObjNet[jj].m_NetCode != NetCode) break;
			if( ObjNet[jj].m_Type != NET_PIN ) continue;
			EDA_SchComponentStruct * tstcmp = 
				(EDA_SchComponentStruct *) ObjNet[jj].m_Link;
			if( Cmp->m_Field[REFERENCE].m_Text != tstcmp->m_Field[REFERENCE].m_Text ) continue;

			if ( ObjNet[jj].m_PinNum == ObjNet[ii].m_PinNum ) ObjNet[jj].m_Flag = 1;
		}
	}
}

