	/***********************************/
	/* Module de calcul de la Netliste */
	/***********************************/

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

#include "netlist.h"	/* Definitions generales liees au calcul de netliste */
#include "protos.h"



/* Routines locales */
static void PropageNetCode( int OldNetCode, int NewNetCode, int IsBus );
static void SheetLabelConnection(ObjetNetListStruct *SheetLabel);
static int ListeObjetConnection(WinEDA_SchematicFrame * frame, SCH_SCREEN *screen, ObjetNetListStruct *ObjNet);
static int ConvertBusToMembers(ObjetNetListStruct *ObjNet);
static void PointToPointConnect(ObjetNetListStruct *RefObj, int IsBus,
								int start);
static void SegmentToPointConnect(ObjetNetListStruct *Jonction, int IsBus,
								int start);
static void LabelConnection(ObjetNetListStruct *Label);
static int TriNetCode(ObjetNetListStruct *Objet1, ObjetNetListStruct *Objet2);
static void ConnectBusLabels( ObjetNetListStruct *Label, int NbItems );
static void SetUnconnectedFlag( ObjetNetListStruct *ObjNet, int NbItems );
static int TriBySheet(ObjetNetListStruct *Objet1, ObjetNetListStruct *Objet2);

/* Variable locales */
static int FirstNumWireBus, LastNumWireBus, RootBusNameLength;
static int LastNetCode, LastBusNetCode;
static int s_PassNumber;



/***********************************************************************/
void FreeTabNetList(ObjetNetListStruct * TabNetItems, int NbrNetItems)
/***********************************************************************/
/*
	Routine de liberation memoire des tableaux utilises pour le calcul
	de la netliste
	TabNetItems = pointeur sur le tableau principal (liste des items )
	NbrNetItems = nombre d'elements
*/
{
int i;

	/* Liberation memoire des strings du champ Label reserve par ConvertBusToMembers */
	for (i = 0; i < NbrNetItems; i++)
	{
		switch( TabNetItems[i].m_Type )
		{
			case NET_PIN:
			case NET_SHEETLABEL:
			case NET_SEGMENT:
			case NET_JONCTION:
			case NET_BUS:
			case NET_LABEL:
			case NET_GLOBLABEL:
			case NET_PINLABEL:
			case NET_NOCONNECT:
				break;
			case NET_GLOBBUSLABELMEMBER:
			case NET_SHEETBUSLABELMEMBER:
			case NET_BUSLABELMEMBER:
				delete TabNetItems[i].m_Label;
				break;
		}
	}

	MyFree(TabNetItems);
}

/*****************************************************/
void * WinEDA_SchematicFrame::BuildNetListBase(void)
/*****************************************************/
/* Routine qui construit le tableau des elements connectes du projet
	met a jour:
		g_TabObjNet
		g_NbrObjNet
*/
{
int NetNumber, SheetNumber;
int i, istart, NetCode;
SCH_SCREEN * screen;
ObjetNetListStruct * BaseTabObjNet;
wxString msg;
wxBusyCursor Busy;

	NetNumber = 1;
	s_PassNumber = 0;
	MsgPanel->EraseMsgBox();
	Affiche_1_Parametre(this, 1,_("List"), wxEmptyString, LIGHTRED);

	/* Build the screen list */
	EDA_ScreenList ScreenList(NULL);

	/* 1ere passe : Comptage du nombre d'objet de Net */
	g_NbrObjNet = 0;
	g_TabObjNet = NULL; /* Init pour le 1er passage dans ListeObjetConnection */

	/* Update the sheet number, sheet count and date and count nelist items */
	ScreenSch->SetModify();
	int kk = 1;
	for ( screen = ScreenList.GetFirst(); screen != NULL; screen = ScreenList.GetNext() )
	{
		screen->m_SheetNumber = kk++;
		screen->m_NumberOfSheet = ScreenList.GetCount();
		screen->m_Date = GenDate();
		g_NbrObjNet += ListeObjetConnection(this, screen, NULL);
	}

	if( g_NbrObjNet == 0 )
	{
		DisplayError(this, _("No component"), 20);
		return(NULL);
	}

	i = sizeof(ObjetNetListStruct) * g_NbrObjNet;
	BaseTabObjNet = g_TabObjNet = (ObjetNetListStruct *) MyZMalloc(i);
	if( BaseTabObjNet == NULL ) return(NULL);

	/* 2eme passe : Remplissage des champs des structures des objets de Net */

	s_PassNumber ++;
	Affiche_1_Parametre(this, 1,_("List"), wxEmptyString,RED);
	for ( screen = ScreenList.GetFirst(); screen != NULL; screen = ScreenList.GetNext() )
	{
		g_TabObjNet += ListeObjetConnection(this, screen, g_TabObjNet );
	}

	Affiche_1_Parametre(this, -1, wxEmptyString,_("Done"),RED);

	msg.Printf( wxT("%d"), g_NbrObjNet);
	Affiche_1_Parametre(this, 8, _("NbItems"),msg,GREEN);

	/* Recherche des connections pour les Segments et les Pins */
	/* Tri du Tableau des objets de Net par Sheet */

	qsort(BaseTabObjNet, g_NbrObjNet, sizeof(ObjetNetListStruct),
				(int (*)(const void *, const void *)) TriBySheet);

	Affiche_1_Parametre(this, 18,_("Conn"), wxEmptyString,CYAN);

	g_TabObjNet = BaseTabObjNet;
	SheetNumber = g_TabObjNet[0].m_SheetNumber;
	LastNetCode = LastBusNetCode = 1;
	for (i = istart = 0; i < g_NbrObjNet; i++)
	{
		if(g_TabObjNet[i].m_SheetNumber != SheetNumber )
		{
			SheetNumber = g_TabObjNet[i].m_SheetNumber; istart = i;
		}

		switch( g_TabObjNet[i].m_Type )
		{
			case NET_PIN:
			case NET_PINLABEL:
			case NET_SHEETLABEL:
			case NET_NOCONNECT:
				if ( g_TabObjNet[i].m_NetCode != 0 ) break; /* Deja connecte */
			case NET_SEGMENT:
				/* Controle des connexions type point a point ( Sans BUS ) */
				if( g_TabObjNet[i].m_NetCode == 0 )
					{
					g_TabObjNet[i].m_NetCode = LastNetCode;
					LastNetCode++;
					}
				PointToPointConnect(g_TabObjNet+i, 0, istart);
				break;

			case NET_JONCTION:
				/* Controle des jonction , hors BUS */
				if( g_TabObjNet[i].m_NetCode == 0 )
					{
					g_TabObjNet[i].m_NetCode = LastNetCode;
					LastNetCode++;
					}
				SegmentToPointConnect( g_TabObjNet+i, 0, istart);

				/* Controle des jonction , sur BUS */
				if( g_TabObjNet[i].m_BusNetCode == 0 )
					{
					g_TabObjNet[i].m_BusNetCode = LastBusNetCode;
					LastBusNetCode++;
					}
				SegmentToPointConnect( g_TabObjNet+i, ISBUS, istart );
				break;

			case NET_LABEL:
			case NET_GLOBLABEL:
				/* Controle des connexions type jonction ( Sans BUS ) */
				if( g_TabObjNet[i].m_NetCode == 0 )
					{
					g_TabObjNet[i].m_NetCode = LastNetCode;
					LastNetCode++;
					}
				SegmentToPointConnect( g_TabObjNet+i, 0, istart );
				break;

			case NET_SHEETBUSLABELMEMBER:
				if ( g_TabObjNet[i].m_BusNetCode != 0 ) break; /* Deja connecte */
			case NET_BUS:
				/* Controle des connexions type point a point mode BUS */
				if( g_TabObjNet[i].m_BusNetCode == 0 )
					{
					g_TabObjNet[i].m_BusNetCode = LastBusNetCode;
					LastBusNetCode++;
					}
				PointToPointConnect(g_TabObjNet+i, ISBUS, istart);
				break;

			case NET_BUSLABELMEMBER:
			case NET_GLOBBUSLABELMEMBER:
				/* Controle des connexions semblables a des sur BUS */
				if( g_TabObjNet[i].m_NetCode == 0 )
					{
					g_TabObjNet[i].m_BusNetCode = LastBusNetCode;
					LastBusNetCode++;
					}
				SegmentToPointConnect( g_TabObjNet+i, ISBUS, istart);
				break;

		}
	}
	Affiche_1_Parametre(this, -1, wxEmptyString,_("Done"),CYAN);

	/* Mise a jour des NetCodes des Bus Labels connectes par les Bus */
	ConnectBusLabels( g_TabObjNet, g_NbrObjNet);

	Affiche_1_Parametre(this, 26,_("Labels"), wxEmptyString,CYAN);

	/* Connections des groupes d'objets par labels identiques */
	for (i = 0; i < g_NbrObjNet; i++)
	{
		switch( g_TabObjNet[i].m_Type )
		{
			case NET_PIN:
			case NET_SHEETLABEL:
			case NET_SEGMENT:
			case NET_JONCTION:
			case NET_BUS:
			case NET_NOCONNECT:
				break;

			case NET_LABEL:
			case NET_GLOBLABEL:
			case NET_PINLABEL:
			case NET_BUSLABELMEMBER:
			case NET_GLOBBUSLABELMEMBER:
				LabelConnection( g_TabObjNet+i );
				break;
			case NET_SHEETBUSLABELMEMBER:
				break;
		}
	}

	Affiche_1_Parametre(this, -1, wxEmptyString,_("Done"),CYAN);


	/* Connexion des hierarchies */
	Affiche_1_Parametre(this, 36,_("Hierar."), wxEmptyString,LIGHTRED);

	for (i = 0; i < g_NbrObjNet; i++)
	{
		if( (g_TabObjNet[i].m_Type == NET_SHEETLABEL ) ||
			( g_TabObjNet[i].m_Type == NET_SHEETBUSLABELMEMBER ) )
				SheetLabelConnection(g_TabObjNet + i);
	}

	/* Tri du Tableau des objets de Net par NetCode */
	qsort(g_TabObjNet, g_NbrObjNet, sizeof(ObjetNetListStruct),
				(int (*)(const void *, const void *)) TriNetCode);

	Affiche_1_Parametre(this, -1, wxEmptyString,_("Done"),RED);

	/* Compression des numeros de NetCode a des valeurs consecutives */
	Affiche_1_Parametre(this, 46,_("Sorting"), wxEmptyString,GREEN);
	LastNetCode = NetCode = 0;
	for (i = 0; i < g_NbrObjNet; i++)
	{
		if(g_TabObjNet[i].m_NetCode != LastNetCode)
		{
			NetCode++; LastNetCode = g_TabObjNet[i].m_NetCode;
		}
		g_TabObjNet[i].m_NetCode = NetCode;
	}

	Affiche_1_Parametre(this, -1, wxEmptyString,_("Done"),GREEN);

	/* Affectation du m_FlagOfConnection en fonction de connection ou non */
	SetUnconnectedFlag( BaseTabObjNet, g_NbrObjNet);

	return( (void*) BaseTabObjNet);
}

/*************************************************************
* Routine qui connecte les sous feuilles par les sheetLabels  *
**************************************************************/
static void SheetLabelConnection(ObjetNetListStruct *SheetLabel)
{
int i;
ObjetNetListStruct *ObjetNet;

	if( SheetLabel->m_NetCode == 0 ) return;

	/* Calcul du numero de sous feuille correspondante au sheetlabel */

	/* Comparaison du SheetLabel avec les GLABELS de la sous feuille
			pour regroupement des NetCodes */
	for (i = 0, ObjetNet = g_TabObjNet; i < g_NbrObjNet; i++)
	{
		if( ObjetNet[i].m_SheetNumber != SheetLabel->m_NumInclude ) continue;
		if( (ObjetNet[i].m_Type != NET_GLOBLABEL ) &&
			(ObjetNet[i].m_Type != NET_GLOBBUSLABELMEMBER ) )
			continue;
		if( ObjetNet[i].m_NetCode == SheetLabel->m_NetCode ) continue;
		if( ObjetNet[i].m_Label->CmpNoCase(*SheetLabel->m_Label) != 0) continue;

		/* Propagation du Netcode a tous les Objets de meme NetCode */
		if( ObjetNet[i].m_NetCode )
			PropageNetCode(ObjetNet[i].m_NetCode, SheetLabel->m_NetCode, 0);
		else ObjetNet[i].m_NetCode = SheetLabel->m_NetCode;
	}
}

/*****************************************************************************/
static int ListeObjetConnection(WinEDA_SchematicFrame * frame, SCH_SCREEN *screen,
		ObjetNetListStruct *ObjNet)
/*****************************************************************************/
/* Routine generant la liste des objets relatifs aux connection
	entree:
		screen: pointeur sur l'ecran a traiter
		ObjNet:
			si NULL: la routine compte seulement le nombre des objets
			sinon: pointe le tableau a remplir
*/
{
int ii, NbrItem = 0, NumSheet;
EDA_BaseStruct *DrawList;
EDA_SchComponentStruct *DrawLibItem;
int TransMat[2][2], PartX, PartY, x2, y2;
EDA_LibComponentStruct *Entry;
LibEDA_BaseStruct *DEntry;
DrawSheetLabelStruct *SheetLabel;
int NumInclude;

	NumSheet = screen->m_SheetNumber;
	DrawList = screen->EEDrawList;

	while ( DrawList )
	{
		switch( DrawList->m_StructType )
		{
			case DRAW_SEGMENT_STRUCT_TYPE :
				#undef STRUCT
				#define STRUCT ((EDA_DrawLineStruct *) DrawList)
				if( ObjNet)
					{
					if ( (STRUCT->m_Layer != LAYER_BUS) &&
						 (STRUCT->m_Layer != LAYER_WIRE) )
						 break;

					ObjNet[NbrItem].m_Comp = STRUCT;
					ObjNet[NbrItem].m_Screen = screen;
					ObjNet[NbrItem].m_SheetNumber = NumSheet;
					ObjNet[NbrItem].m_Start = STRUCT->m_Start;
					ObjNet[NbrItem].m_End = STRUCT->m_End;
					if (STRUCT->m_Layer == LAYER_BUS)
						{
						ObjNet[NbrItem].m_Type = NET_BUS;
						}
					else	/* Cas des WIRE */
						{
						ObjNet[NbrItem].m_Type = NET_SEGMENT;
						}
					}
				NbrItem++;
				break;

			case DRAW_JUNCTION_STRUCT_TYPE :
				#undef STRUCT
				#define STRUCT ((DrawJunctionStruct *) DrawList)
				if( ObjNet)
					{
					ObjNet[NbrItem].m_Comp = STRUCT;
					ObjNet[NbrItem].m_Screen = screen;
					ObjNet[NbrItem].m_Type = NET_JONCTION;
					ObjNet[NbrItem].m_SheetNumber = NumSheet;
					ObjNet[NbrItem].m_Start = STRUCT->m_Pos;
					ObjNet[NbrItem].m_End = ObjNet[NbrItem].m_Start;
					}
				NbrItem++;
				break;

			case DRAW_NOCONNECT_STRUCT_TYPE :
				#undef STRUCT
				#define STRUCT ((DrawNoConnectStruct *) DrawList)
				if( ObjNet)
					{
					ObjNet[NbrItem].m_Comp = STRUCT;
					ObjNet[NbrItem].m_Screen = screen;
					ObjNet[NbrItem].m_Type = NET_NOCONNECT;
					ObjNet[NbrItem].m_SheetNumber = NumSheet;
					ObjNet[NbrItem].m_Start = STRUCT->m_Pos;
					ObjNet[NbrItem].m_End = ObjNet[NbrItem].m_Start;
					}
				NbrItem++;
				break;

			case DRAW_LABEL_STRUCT_TYPE :
				#undef STRUCT
				#define STRUCT ((DrawLabelStruct *) DrawList)
				ii = IsBusLabel( STRUCT->m_Text);
				if( ObjNet)
					{
					ObjNet[NbrItem].m_Comp = STRUCT;
					ObjNet[NbrItem].m_Screen = screen;
					ObjNet[NbrItem].m_Type = NET_LABEL;
					if (STRUCT->m_Layer ==  LAYER_GLOBLABEL)
						ObjNet[NbrItem].m_Type = NET_GLOBLABEL;
					ObjNet[NbrItem].m_Label = & STRUCT->m_Text;
					ObjNet[NbrItem].m_SheetNumber = NumSheet;
					ObjNet[NbrItem].m_Start = STRUCT->m_Pos;
					ObjNet[NbrItem].m_End = ObjNet[NbrItem].m_Start;
					/* Si c'est un Bus, eclatement en Label */
					if ( ii ) ConvertBusToMembers(ObjNet + NbrItem);
					}
				NbrItem += ii+1;
				break;

			case DRAW_GLOBAL_LABEL_STRUCT_TYPE :
				#undef STRUCT
				#define STRUCT ((DrawGlobalLabelStruct *) DrawList)
				ii = IsBusLabel( STRUCT->m_Text);
				if( ObjNet)
					{
					ObjNet[NbrItem].m_Comp = STRUCT;
					ObjNet[NbrItem].m_Screen = screen;
					ObjNet[NbrItem].m_Type = NET_LABEL;
					if (STRUCT->m_Layer ==  LAYER_GLOBLABEL)
							ObjNet[NbrItem].m_Type = NET_GLOBLABEL;
					ObjNet[NbrItem].m_Label = & STRUCT->m_Text;
					ObjNet[NbrItem].m_SheetNumber = NumSheet;
					ObjNet[NbrItem].m_Start = STRUCT->m_Pos;
					ObjNet[NbrItem].m_End = ObjNet[NbrItem].m_Start;
					/* Si c'est un Bus, eclatement en Label */
					if ( ii ) ConvertBusToMembers(ObjNet + NbrItem);
					}
				NbrItem += ii+1;
				break;

			case DRAW_LIB_ITEM_STRUCT_TYPE :
				DrawLibItem = (EDA_SchComponentStruct *) DrawList;
				memcpy(TransMat, DrawLibItem->m_Transform, sizeof(TransMat));
				PartX = DrawLibItem->m_Pos.x; PartY = DrawLibItem->m_Pos.y;
				Entry = FindLibPart(DrawLibItem->m_ChipName, wxEmptyString, FIND_ROOT);

				if( Entry == NULL) break;
				if(Entry->m_Drawings == NULL) break ;
				DEntry = Entry->m_Drawings;
				for ( ;DEntry != NULL; DEntry = DEntry->Next())
					{
					LibDrawPin * Pin = (LibDrawPin *) DEntry;
					if( DEntry->m_StructType != COMPONENT_PIN_DRAW_TYPE) continue;
					if( DEntry->m_Unit &&
						(DEntry->m_Unit != DrawLibItem->m_Multi) ) continue;
					if( DEntry->m_Convert &&
						(DEntry->m_Convert != DrawLibItem->m_Convert)) continue;

					x2 = PartX + TransMat[0][0] * Pin->m_Pos.x
								+ TransMat[0][1] * Pin->m_Pos.y;
					y2 = PartY + TransMat[1][0] * Pin->m_Pos.x
								+ TransMat[1][1] * Pin->m_Pos.y;

					if( ObjNet)
						{
						ObjNet[NbrItem].m_Comp = DEntry;
						ObjNet[NbrItem].m_Type = NET_PIN;
						ObjNet[NbrItem].m_Link = DrawLibItem;
						ObjNet[NbrItem].m_Screen = screen;
						ObjNet[NbrItem].m_ElectricalType = Pin->m_PinType;
						ObjNet[NbrItem].m_PinNum = Pin->m_PinNum;
						ObjNet[NbrItem].m_Label = & Pin->m_PinName;
						ObjNet[NbrItem].m_SheetNumber = NumSheet;
						ObjNet[NbrItem].m_Start.x = x2;
						ObjNet[NbrItem].m_Start.y = y2;
						ObjNet[NbrItem].m_End = ObjNet[NbrItem].m_Start;
						}
					NbrItem++;

					if( ( (int) Pin->m_PinType == (int) PIN_POWER_IN ) &&
						( Pin->m_Attributs & PINNOTDRAW ) )
						{	/* Il y a un PIN_LABEL Associe */
						if( ObjNet)
							{
							ObjNet[NbrItem].m_Comp = NULL;
							ObjNet[NbrItem].m_Type = NET_PINLABEL;
							ObjNet[NbrItem].m_Screen = screen;
							ObjNet[NbrItem].m_SheetNumber = NumSheet;
							ObjNet[NbrItem].m_Label = & Pin->m_PinName;
							ObjNet[NbrItem].m_Start.x = x2;
							ObjNet[NbrItem].m_Start.y = y2;
							ObjNet[NbrItem].m_End = ObjNet[NbrItem].m_Start;
							}
						NbrItem++;
						}
					}
				break;

			case DRAW_PICK_ITEM_STRUCT_TYPE :
			case DRAW_POLYLINE_STRUCT_TYPE :
			case DRAW_BUSENTRY_STRUCT_TYPE :
			case DRAW_MARKER_STRUCT_TYPE :
			case DRAW_TEXT_STRUCT_TYPE :
				break;

			case DRAW_SHEET_STRUCT_TYPE :
				#undef STRUCT
				#define STRUCT ((DrawSheetStruct *) DrawList)
				NumInclude = STRUCT->m_SheetNumber;

				SheetLabel = STRUCT->m_Label;
				for ( ; SheetLabel != NULL;
						SheetLabel = (DrawSheetLabelStruct*) SheetLabel->Pnext)
					{
					ii = IsBusLabel(SheetLabel->m_Text);
					if( ObjNet)
						{
						ObjNet[NbrItem].m_Comp = SheetLabel;
						ObjNet[NbrItem].m_Link = DrawList;
						ObjNet[NbrItem].m_Type = NET_SHEETLABEL;
						ObjNet[NbrItem].m_Screen = screen;
						ObjNet[NbrItem].m_ElectricalType = SheetLabel->m_Shape;
						ObjNet[NbrItem].m_Label = & SheetLabel->m_Text;
						ObjNet[NbrItem].m_SheetNumber = NumSheet;
						ObjNet[NbrItem].m_NumInclude = NumInclude;
						ObjNet[NbrItem].m_Start = SheetLabel->m_Pos;
						ObjNet[NbrItem].m_End = ObjNet[NbrItem].m_Start;
						/* Si c'est un Bus, eclatement en Label */
						if ( ii ) ConvertBusToMembers(ObjNet + NbrItem);
						}
					NbrItem += ii+1;
					}
				break;

			case DRAW_SHEETLABEL_STRUCT_TYPE :
				DisplayError(frame, wxT("Netlist: Type DRAW_SHEETLABEL inattendu"));
				break;

			default:
			{
			wxString msg;
				msg.Printf( wxT("Netlist: unexpected type struct %d"),
									DrawList->m_StructType);
				DisplayError(frame, msg);
				break;
			}
		}

		DrawList = DrawList->Pnext;
	}

return(NbrItem);
}


/************************************************************************/
static void ConnectBusLabels( ObjetNetListStruct *Label, int NbItems )
/************************************************************************/
/* Routine qui analyse les labels type xxBUSLABELMEMBER
	Propage les Netcodes entre labels correspondants ( c'est a dire lorsque
	leur numero de membre est identique) lorsqu'ils sont connectes
	globalement par leur BusNetCode
	Utilise et met a jour la variable LastNetCode
*/
{
ObjetNetListStruct *LabelInTst, *Lim;

	Lim = Label + NbItems;

	for ( ; Label < Lim; Label++)
		{
		if( (Label->m_Type == NET_SHEETBUSLABELMEMBER) ||
			(Label->m_Type == NET_BUSLABELMEMBER) ||
			(Label->m_Type == NET_GLOBBUSLABELMEMBER) )
			{
			if( Label->m_NetCode == 0 )
				{
				Label->m_NetCode = LastNetCode; LastNetCode++;
				}
			for ( LabelInTst = Label+1; LabelInTst < Lim; LabelInTst++)
				{
				if( (LabelInTst->m_Type == NET_SHEETBUSLABELMEMBER) ||
					(LabelInTst->m_Type == NET_BUSLABELMEMBER) ||
					(LabelInTst->m_Type == NET_GLOBBUSLABELMEMBER) )
					{
					if( LabelInTst->m_BusNetCode != Label->m_BusNetCode ) continue;
					if( LabelInTst->m_Member != Label->m_Member ) continue;
					if( LabelInTst->m_NetCode == 0 )
						LabelInTst->m_NetCode = Label->m_NetCode;
					else
						PropageNetCode( LabelInTst->m_NetCode, Label->m_NetCode,0);
					}
				}
			}
		}
}


/**************************************************/
int IsBusLabel( const wxString & LabelDrawList )
/**************************************************/

/* Routine qui verifie si le Label a une notation de type Bus
	Retourne 0 si non
	nombre de membres si oui
	met a jour FirstNumWireBus, LastNumWireBus et RootBusNameLength
*/

{
unsigned Num;
int ii;
wxString BufLine;
long tmp;
bool error = FALSE;

	/* Search for  '[' because a bus label is like "busname[nn..mm]" */
	ii = LabelDrawList.Find('[');
	if ( ii < 0 ) return(0);
	Num = (unsigned) ii;
	
	FirstNumWireBus = LastNumWireBus = 9;
	RootBusNameLength = Num;
	Num++;
	while ( LabelDrawList[Num] != '.' && Num < LabelDrawList.Len())
	{
		BufLine.Append(LabelDrawList[Num]);
		Num++;
	}

	if ( ! BufLine.ToLong(&tmp) ) error = TRUE;;
	FirstNumWireBus = tmp;
	while ( LabelDrawList[Num] == '.' && Num < LabelDrawList.Len() )
		Num++;
	BufLine.Empty();
	while ( LabelDrawList[Num] != ']' && Num < LabelDrawList.Len())
	{
		BufLine.Append(LabelDrawList[Num]);
		Num++;
	}
	if ( ! BufLine.ToLong(&tmp) ) error = TRUE;;
	LastNumWireBus = tmp;

	if( FirstNumWireBus < 0 ) FirstNumWireBus = 0;
	if( LastNumWireBus < 0 ) LastNumWireBus = 0;
	if( FirstNumWireBus > LastNumWireBus )
	{
		EXCHG( FirstNumWireBus, LastNumWireBus);
	}

	if ( error && (s_PassNumber == 0) )
	{
		wxString msg = _("Bad Bus Label: ") + LabelDrawList;
		DisplayError(NULL, msg);
	}
	return(LastNumWireBus - FirstNumWireBus + 1 );
}


/***************************************************************/
static int ConvertBusToMembers(ObjetNetListStruct * BusLabel)
/***************************************************************/
/* Routine qui eclate un label type Bus en autant de Label qu'il contient de membres,
	et qui cree les structures avec le type NET_GLOBBUSLABELMEMBER, NET_BUSLABELMEMBER
	ou NET_SHEETBUSLABELMEMBER
	entree = pointeur sur l'ObjetNetListStruct initialise corresp au buslabel
	suppose que FirstNumWireBus, LastNumWireBus et RootBusNameLength sont a jour
	modifie l'ObjetNetListStruct de base et remplit les suivants
	m_Label is a pointer to a new wxString
	m_Label must be deallocated by the user (only for a NET_GLOBBUSLABELMEMBER,
	NET_BUSLABELMEMBER or a NET_SHEETBUSLABELMEMBER object type)
*/
{
int NumItem, BusMember;
wxString BufLine;

	if( BusLabel->m_Type == NET_GLOBLABEL )
				BusLabel->m_Type = NET_GLOBBUSLABELMEMBER;
	else if (BusLabel->m_Type == NET_SHEETLABEL)
				BusLabel->m_Type = NET_SHEETBUSLABELMEMBER;
	else BusLabel->m_Type = NET_BUSLABELMEMBER;

	/* Convertion du BusLabel en la racine du Label + le numero du fil */
	BufLine = BusLabel->m_Label->Left(RootBusNameLength);
	BusMember = FirstNumWireBus;
	BufLine << BusMember;
	BusLabel->m_Label = new wxString(BufLine);
	BusLabel->m_Member = BusMember;
	NumItem = 1;

	for ( BusMember++; BusMember <= LastNumWireBus; BusMember++)
	{
		*(BusLabel+1) = *BusLabel; BusLabel ++; NumItem++;
		/* Convertion du BusLabel en la racine du Label + le numero du fil */
		BufLine = BusLabel->m_Label->Left(RootBusNameLength);
		BufLine << BusMember;
		BusLabel->m_Label = new wxString(BufLine);
		BusLabel->m_Member = BusMember;
	}
	return( NumItem);
}

/**********************************************************************/
static void PropageNetCode( int OldNetCode, int NewNetCode, int IsBus )
/**********************************************************************/
/* PropageNetCode propage le netcode NewNetCode sur tous les elements
	appartenant a l'ancien netcode OldNetCode
 Si IsBus == 0; c'est le membre NetCode qui est propage
 Si IsBus != 0; c'est le membre BusNetCode qui est propage
*/

{
int jj;
ObjetNetListStruct * Objet = g_TabObjNet;

	if( OldNetCode == NewNetCode ) return;

	if( IsBus == 0 )	/* Propagation du NetCode */
		{
		for (jj = 0; jj < g_NbrObjNet; jj++, Objet++)
			{
			if ( Objet->m_NetCode == OldNetCode )
				{
				Objet->m_NetCode = NewNetCode;
				}
			}
		}

	else			/* Propagation du BusNetCode */
		{
		for (jj = 0; jj < g_NbrObjNet; jj++, Objet++)
			{
			if ( Objet->m_BusNetCode == OldNetCode )
				{
				Objet->m_BusNetCode = NewNetCode;
				}
			}
		}
}

/***************************************************************************/
static void PointToPointConnect(ObjetNetListStruct *Ref, int IsBus, int start)
/***************************************************************************/
/* Routine qui verifie si l'element *Ref est connecte a
	d'autres elements de la liste des objets du schema, selon le mode Point
	a point ( Extremites superposees )

	si IsBus:
		la connexion ne met en jeu que des elements type bus
			( BUS ou BUSLABEL ou JONCTION )
	sinon
		la connexion ne met en jeu que des elements type non bus
			( autres que BUS ou BUSLABEL )

	L'objet Ref doit avoir un NetCode valide.

	La liste des objets est supposee classe par NumSheet Croissants,
	et la recherche se fait a partir de l'element start, 1er element
	de la feuille de schema
( il ne peut y avoir connexion physique entre elements de differentes sheets)
*/
{
int i, NetCode;
ObjetNetListStruct *Point = g_TabObjNet;

if ( IsBus == 0 )		/* Objets autres que BUS et BUSLABELS */
	{
	NetCode = Ref->m_NetCode;
	for (i = start; i < g_NbrObjNet; i++)
		{
		if( Point[i].m_SheetNumber > Ref->m_SheetNumber ) break;

		switch( Point[i].m_Type )
			{
			case NET_SEGMENT:
			case NET_PIN:
			case NET_LABEL:
			case NET_GLOBLABEL:
			case NET_SHEETLABEL:
			case NET_PINLABEL:
			case NET_JONCTION:
			case NET_NOCONNECT:
				if( (((Ref->m_Start.x == Point[i].m_Start.x) && (Ref->m_Start.y == Point[i].m_Start.y))) ||
					(((Ref->m_Start.x == Point[i].m_End.x) && (Ref->m_Start.y == Point[i].m_End.y))) ||
					(((Ref->m_End.x == Point[i].m_Start.x) && (Ref->m_End.y == Point[i].m_Start.y))) ||
					(((Ref->m_End.x == Point[i].m_End.x) && (Ref->m_End.y == Point[i].m_End.y))) )
						{
						if( Point[i].m_NetCode == 0 ) Point[i].m_NetCode = NetCode;
						else PropageNetCode( Point[i].m_NetCode, NetCode , 0);
						}
				break;
			case NET_BUS:
			case NET_BUSLABELMEMBER:
			case NET_SHEETBUSLABELMEMBER:
			case NET_GLOBBUSLABELMEMBER:
				break;
			}
		}
	}
else		/* Objets type BUS et BUSLABELS ( et JONCTIONS )*/
	{
	NetCode = Ref->m_BusNetCode;
	for (i = start; i < g_NbrObjNet; i++)
		{
		if( Point[i].m_SheetNumber > Ref->m_SheetNumber ) break;

		switch( Point[i].m_Type )
			{
			case NET_SEGMENT:
			case NET_PIN:
			case NET_LABEL:
			case NET_GLOBLABEL:
			case NET_SHEETLABEL:
			case NET_PINLABEL:
			case NET_NOCONNECT:
				break;

			case NET_BUS:
			case NET_BUSLABELMEMBER:
			case NET_SHEETBUSLABELMEMBER:
			case NET_GLOBBUSLABELMEMBER:
			case NET_JONCTION:
				if( (((Ref->m_Start.x == Point[i].m_Start.x) && (Ref->m_Start.y == Point[i].m_Start.y))) ||
					(((Ref->m_Start.x == Point[i].m_End.x) && (Ref->m_Start.y == Point[i].m_End.y))) ||
					(((Ref->m_End.x == Point[i].m_Start.x) && (Ref->m_End.y == Point[i].m_Start.y))) ||
					(((Ref->m_End.x == Point[i].m_End.x) && (Ref->m_End.y == Point[i].m_End.y))) )
						{
						if( Point[i].m_BusNetCode == 0 )
							Point[i].m_BusNetCode = NetCode;
						else PropageNetCode( Point[i].m_BusNetCode, NetCode,1 );
						}
				break;
			}
		}
	}
}


/**************************************************************/
static void SegmentToPointConnect(ObjetNetListStruct *Jonction,
									int IsBus, int start)
/***************************************************************/
/*
Routine qui recherche si un point (jonction) est connecte a des segments,
et regroupe les NetCodes des objets connectes a la jonction.
Le point de jonction doit avoir un netcode valide
	La liste des objets est supposee classe par NumSheet Croissants,
	et la recherche se fait a partir de l'element start, 1er element
	de la feuille de schema
( il ne peut y avoir connexion physique entre elements de differentes sheets)
*/
{
int i;
ObjetNetListStruct *Segment = g_TabObjNet;

	for (i = start; i < g_NbrObjNet; i++)
		{
		if( Segment[i].m_SheetNumber > Jonction->m_SheetNumber ) break;

		if( IsBus == 0)
			{
			if ( Segment[i].m_Type != NET_SEGMENT )  continue;
			}
		else
			{
			if ( Segment[i].m_Type != NET_BUS )  continue;
			}

		if ( SegmentIntersect(Segment[i].m_Start.x, Segment[i].m_Start.y,
							Segment[i].m_End.x, Segment[i].m_End.y,
							Jonction->m_Start.x, Jonction->m_Start.y) )
			{
			/* Propagation du Netcode a tous les Objets de meme NetCode */
			if( IsBus == 0 )
				{
				if( Segment[i].m_NetCode )
					PropageNetCode(Segment[i].m_NetCode,
									Jonction->m_NetCode, IsBus);
				else Segment[i].m_NetCode = Jonction->m_NetCode;
				}
			else
				{
				if( Segment[i].m_BusNetCode )
					PropageNetCode(Segment[i].m_BusNetCode,
									Jonction->m_BusNetCode, IsBus);
				else Segment[i].m_BusNetCode = Jonction->m_BusNetCode;
				}
			}
		}
}

/*****************************************************************
* Routine qui connecte les groupes d'objets si labels identiques  *
*******************************************************************/
static void LabelConnection(ObjetNetListStruct *LabelRef)
{
int i, NetCode;
ObjetNetListStruct *ObjetNet;

	if( LabelRef->m_NetCode == 0 ) return;

	ObjetNet = g_TabObjNet;

	for (i = 0; i < g_NbrObjNet; i++)
		{
		NetCode = ObjetNet[i].m_NetCode;
		if( NetCode == LabelRef->m_NetCode ) continue;

		if( ObjetNet[i].m_SheetNumber != LabelRef->m_SheetNumber )
			{
			if (ObjetNet[i].m_Type != NET_PINLABEL ) continue;
			}

		if( (ObjetNet[i].m_Type == NET_LABEL ) ||
			(ObjetNet[i].m_Type == NET_GLOBLABEL ) ||
			(ObjetNet[i].m_Type == NET_BUSLABELMEMBER ) ||
			(ObjetNet[i].m_Type == NET_GLOBBUSLABELMEMBER ) ||
			(ObjetNet[i].m_Type == NET_PINLABEL ) )
			{
			if( ObjetNet[i].m_Label->CmpNoCase(*LabelRef->m_Label) != 0) continue;

			/* Ici 2 labels identiques */

			/* Propagation du Netcode a tous les Objets de meme NetCode */
			if( ObjetNet[i].m_NetCode )
				PropageNetCode(ObjetNet[i].m_NetCode, LabelRef->m_NetCode, 0);
			else ObjetNet[i].m_NetCode = LabelRef->m_NetCode;
			}
		}
}



/****************************************************************************/
static int TriNetCode(ObjetNetListStruct *Objet1, ObjetNetListStruct *Objet2)
/****************************************************************************/
/* Routine de comparaison pour le tri par NetCode croissant
	du tableau des elements connectes ( TabPinSort ) par qsort()
*/
{
	return (Objet1->m_NetCode - Objet2->m_NetCode);
}

/*****************************************************************************/
static int TriBySheet(ObjetNetListStruct *Objet1, ObjetNetListStruct *Objet2)
/*****************************************************************************/
/* Routine de comparaison pour le tri par NumSheet
	du tableau des elements connectes ( TabPinSort ) par qsort() */

{
	return (Objet1->m_SheetNumber - Objet2->m_SheetNumber);
}


/**********************************************************************/
static void SetUnconnectedFlag( ObjetNetListStruct *ListObj, int NbItems )
/**********************************************************************/
/* Routine positionnant le membre .FlagNoConnect des elements de
	la liste des objets netliste, tries par ordre de NetCode
*/
{
ObjetNetListStruct * NetItemRef, * NetItemTst, *ItemPtr;
ObjetNetListStruct * NetStart, * NetEnd, * Lim;
int Nb;
IsConnectType StateFlag;


	NetStart = NetEnd = ListObj;
	Lim = ListObj + NbItems;
	NetItemRef = NetStart;
	Nb = 0; StateFlag = UNCONNECT;

	for ( ; NetItemRef < Lim; NetItemRef++ )
	{
		if( NetItemRef->m_Type == NET_NOCONNECT )
			if( StateFlag != CONNECT ) StateFlag = NOCONNECT;

		/* Analyse du net en cours */
		NetItemTst = NetItemRef + 1;

		if( (NetItemTst >= Lim) || 
			(NetItemRef->m_NetCode != NetItemTst->m_NetCode) )
		{	/* Net analyse: mise a jour de m_FlagOfConnection */
			NetEnd = NetItemTst;

			for( ItemPtr = NetStart; ItemPtr < NetEnd; ItemPtr++ )
			{
				ItemPtr->m_FlagOfConnection = StateFlag;
			}
			if(NetItemTst >= Lim) return;

			/* Start Analyse Nouveau Net */
			StateFlag = UNCONNECT;
			NetStart = NetItemTst;
			continue;
		}

		for ( ; ; NetItemTst ++)
		{
			if( (NetItemTst >= Lim) ||
				(NetItemRef->m_NetCode != NetItemTst->m_NetCode) )
				break;

			switch( NetItemTst->m_Type )
			{
				case NET_SEGMENT:
				case NET_LABEL:
				case NET_GLOBLABEL:
				case NET_SHEETLABEL:
				case NET_PINLABEL:
				case NET_BUS:
				case NET_BUSLABELMEMBER:
				case NET_SHEETBUSLABELMEMBER:
				case NET_GLOBBUSLABELMEMBER:
				case NET_JONCTION:
				break;

				case NET_PIN:
					if( NetItemRef->m_Type == NET_PIN )
						StateFlag = CONNECT;
					break;

				case NET_NOCONNECT:
					if( StateFlag != CONNECT ) StateFlag = NOCONNECT;
					break;
			}
		}
	}
}

