/**************************************************/
/* Module de tst "ERC" ( Electrical Rules Check ) */
/**************************************************/

#include "fctsys.h"

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

#include "protos.h"

#include "bitmaps.h"

#include "dialog_erc.h"

/* On teste
 *  1 - conflits entre pins connectees ( ex: 2 sorties connectees )
 *  2 - les imperatifs minimaux ( 1 entree doit etre connectee a une sortie )
 */


/* fonctions exportees */

/* fonctions importees */

/* fonctions locales */
static bool WriteDiagnosticERC( const wxString& FullFileName );
static void Diagnose( WinEDA_DrawPanel* panel, wxDC* DC,
                      ObjetNetListStruct* NetItemRef,
                      ObjetNetListStruct* NetItemTst, int MinConnexion, int Diag );
static void TestOthersItems( WinEDA_DrawPanel* panel,
                             wxDC* DC, ObjetNetListStruct* NetItemRef,
                             ObjetNetListStruct* NetStart,
                             int* NetNbItems, int* MinConnexion );
static void TestLabel( WinEDA_DrawPanel* panel, wxDC* DC,
                       ObjetNetListStruct* NetItemRef,
                       ObjetNetListStruct* StartNet );

/* Variable locales */
int WriteFichierERC = FALSE;

/* Tableau des types de conflit :
 *  PIN_INPUT, PIN_OUTPUT, PIN_BIDI, PIN_TRISTATE, PIN_PASSIVE,
 *  PIN_UNSPECIFIED, PIN_POWER_IN, PIN_POWER_OUT, PIN_OPENCOLLECTOR,
 *  PIN_OPENEMITTER, PIN_NC
 */
#define OK  0
#define WAR 1   // utilis� aussi dans eeredraw
#define ERR 2
#define UNC 3

static const wxChar* CommentERC_H[] =
{
    wxT( "Input Pin...." ),
    wxT( "Output Pin..." ),
    wxT( "BiDi Pin....." ),
    wxT( "3 State Pin.." ),
    wxT( "Passive Pin.." ),
    wxT( "Unspec Pin..." ),
    wxT( "Power IN Pin." ),
    wxT( "PowerOUT Pin." ),
    wxT( "Open Coll...." ),
    wxT( "Open Emit...." ),
    wxT( "No Conn......" ),
    NULL
};
static const wxChar* CommentERC_V[] =
{
    wxT( "Input Pin" ),
    wxT( "Output Pin" ),
    wxT( "BiDi Pin" ),
    wxT( "3 State Pin" ),
    wxT( "Passive Pin" ),
    wxT( "Unspec Pin" ),
    wxT( "Power IN Pin" ),
    wxT( "PowerOUT Pin" ),
    wxT( "Open Coll" ),
    wxT( "Open Emit" ),
    wxT( "No Conn" ),
    NULL
};


/* Look up table which gives the diag for a pair of connected pins
 *  Can be modified by ERC options.
 *  at start up: must be loaded by DefaultDiagErc
 */
static int DiagErc[PIN_NMAX][PIN_NMAX];
bool       DiagErcTableInit; // go to TRUE after DiagErc init

/* Default Look up table which gives the diag for a pair of connected pins
 *  Same as DiagErc, but cannot be modified
 *  Used to init or reset DiagErc
 */
static int DefaultDiagErc[PIN_NMAX][PIN_NMAX] =
{ /*       I,   O,   Bi,  3S, Pas, UnS,PwrI,PwrO,  OC,  OE,  NC */
/* I */
    { OK, OK, OK, OK, OK, WAR, OK, OK, OK, OK, WAR },
/* O */ { OK, ERR, OK, WAR, OK, WAR, OK, ERR, ERR, ERR, WAR },
/* Bi*/ { OK, OK, OK, OK, OK, WAR, OK, WAR, OK, WAR, WAR },
/* 3S*/ { OK, WAR, OK, OK, OK, WAR, WAR, ERR, WAR, WAR, WAR },
/*Pas*/ { OK, OK, OK, OK, OK, WAR, OK, OK, OK, OK, WAR },
/*UnS */ { WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR },
/*PwrI*/ { OK, OK, OK, WAR, OK, WAR, OK, OK, OK, OK, ERR },
/*PwrO*/ { OK, ERR, WAR, ERR, OK, WAR, OK, ERR, ERR, ERR, WAR },
/* OC */ { OK, ERR, OK, WAR, OK, WAR, OK, ERR, OK, OK, WAR },
/* OE */ { OK, ERR, WAR, WAR, OK, WAR, OK, ERR, OK, OK, WAR },
/* NC */ { WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR, WAR }
};


/* Minimal connection table */
#define DRV    3    /* Net driven by a signal (a pin output for instance) */
#define NET_NC 2    /* Net "connected" to a "NoConnect symbol" */
#define NOD    1    /* Net not driven ( Such as 2 or more connected inputs )*/
#define NOC    0    /* Pin isolee, non connectee */

/* Look up table which gives the minimal drive for a pair of connected pins on a net
 *  Initial state of a net is NOC (No Connection)
 *  Can be updated to NET_NC, or NOD (Not Driven) or DRV (DRIven)
 *
 *  Can be updated to NET_NC only if the previous state is NOC
 *
 *  Nets are OK when their final state is NET_NC or DRV
 *  Nets with the state NOD have no source signal
 */
static int MinimalReq[PIN_NMAX][PIN_NMAX] =
{         /* In, Out,  Bi,  3S, Pas, UnS,PwrI,PwrO,  OC,  OE,  NC */
/* In*/
    {   NOD, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NOC },
/*Out*/ {   DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, NOC },
/* Bi*/ {   DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NOC },
/* 3S*/ {   DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NOC },
/*Pas*/ {   DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NOC },
/*UnS*/ {   DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NOC },
/*PwrI*/ {   NOD, DRV, NOD, NOD, NOD, NOD, NOD, DRV, NOD, NOD, NOC },
/*PwrO*/ {   DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, DRV, NOC },
/* OC*/ {   DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NOC },
/* OE*/ {   DRV, DRV, DRV, DRV, DRV, DRV, NOD, DRV, DRV, DRV, NOC },
/* NC*/ {   NOC, NOC, NOC, NOC, NOC, NOC, NOC, NOC, NOC, NOC, NOC }
};


/*********************************************/
void WinEDA_ErcFrame::ReBuildMatrixPanel()
/*********************************************/

/* Build or rebuild the panel showing the ERC matrix
 */
{
    int           ii, jj, event_id, text_height;
    wxPoint       pos, BoxMatrixPosition;

#define BITMAP_SIZE 19
    int           bitmap_size = BITMAP_SIZE;
    wxStaticText* text;
    int           x, y;
    wxSize        BoxMatrixMinSize;

    if( !DiagErcTableInit )
    {
        memcpy( DiagErc, DefaultDiagErc, sizeof(DefaultDiagErc) );
        DiagErcTableInit = TRUE;
    }

    // Get the current text size :
    text = new wxStaticText( m_PanelERCOptions, -1, wxT( "W" ), pos );    // this is a dummy text

    text_height = text->GetRect().GetHeight();
    bitmap_size = MAX( bitmap_size, text_height );
    SAFE_DELETE( text );

    // compute the Y pos interval:
    BoxMatrixMinSize.y = ( bitmap_size * (PIN_NMAX + 1) ) + 5;
    GetSizer()->Fit( this );
    GetSizer()->SetSizeHints( this );
    pos = m_MatrixSizer->GetPosition();

    // Size computation is not made in constructor, in some wxWidgets version,
    // and m_BoxSizerForERC_Opt position is always 0,0. and we can't use it
    pos.x = MAX( pos.x, 5 );
    pos.y = MAX( pos.y, m_ResetOptButton->GetRect().GetHeight() + 30 );

    BoxMatrixPosition = pos;

    pos.y += text_height;

    if( m_Initialized == FALSE )
    {
        for( ii = 0; ii < PIN_NMAX; ii++ )
        {
            y    = pos.y + (ii * bitmap_size);
            text = new wxStaticText( m_PanelERCOptions, -1, CommentERC_H[ii], wxPoint( 5, y ) );

            x     = text->GetRect().GetRight();
            pos.x = MAX( pos.x, x );
        }

        pos.x += 5;
    }
    else
        pos = m_ButtonList[0][0]->GetPosition();

    for( ii = 0; ii < PIN_NMAX; ii++ )
    {
        y = pos.y + (ii * bitmap_size);
        for( jj = 0; jj <= ii; jj++ )
        {
            int diag = DiagErc[ii][jj];
            x = pos.x + (jj * bitmap_size);
            if( (ii == jj) && !m_Initialized )
            {
                wxPoint txtpos;
                txtpos.x = x + 4; txtpos.y = y - bitmap_size;
                text = new wxStaticText( m_PanelERCOptions, -1, CommentERC_V[ii], txtpos );

                BoxMatrixMinSize.x = MAX( BoxMatrixMinSize.x, text->GetRect().GetRight() );
            }
            event_id = ID_MATRIX_0 + ii + (jj * PIN_NMAX);
            delete m_ButtonList[ii][jj];

            switch( diag )
            {
            case OK:
                m_ButtonList[ii][jj] = new wxBitmapButton( m_PanelERCOptions,
                                                          event_id,
                                                          wxBitmap (green_xpm),
                                                          wxPoint (x, y) );

                break;

            case WAR:
                m_ButtonList[ii][jj] = new wxBitmapButton( m_PanelERCOptions,
                                                          event_id,
                                                          wxBitmap (warning_xpm),
                                                          wxPoint (x, y) );

                break;

            case ERR:
                m_ButtonList[ii][jj] = new wxBitmapButton( m_PanelERCOptions,
                                                          event_id,
                                                          wxBitmap (error_xpm),
                                                          wxPoint (x, y) );

                break;
            }
        }
    }

    if( !m_Initialized )
    {
        BoxMatrixMinSize.x += 5;
        m_MatrixSizer->SetMinSize( BoxMatrixMinSize );
        BoxMatrixMinSize.y += BoxMatrixPosition.y;
        m_PanelMatrixSizer->SetMinSize( BoxMatrixMinSize );
    }
    m_Initialized = TRUE;
}


/**************************************************/
void WinEDA_ErcFrame::TestErc( wxCommandEvent& event )
/**************************************************/
{
    ObjetNetListStruct* NetItemRef;
    ObjetNetListStruct* OldItem;
    ObjetNetListStruct* StartNet;
    ObjetNetListStruct* Lim;

    int NetNbItems, MinConn;

    if( !DiagErcTableInit )
    {
        memcpy( DiagErc, DefaultDiagErc, sizeof(DefaultDiagErc) );
        DiagErcTableInit = TRUE;
    }

    WriteFichierERC = m_WriteResultOpt->GetValue();

    ReAnnotatePowerSymbolsOnly();
    if( CheckAnnotate( m_Parent, 0 ) )
    {
        DisplayError( this, _( "Annotation Required!" ) );
        return;
    }

    /* Effacement des anciens marqueurs DRC */
    DelERCMarkers( event );

    wxClientDC dc( m_Parent->DrawPanel );

    m_Parent->DrawPanel->PrepareGraphicContext( &dc );

    g_EESchemaVar.NbErrorErc   = 0;
    g_EESchemaVar.NbWarningErc = 0;

    /* Cleanup the entire hierarchy */
    EDA_ScreenList ScreenList;

    for( SCH_SCREEN* Screen = ScreenList.GetFirst(); Screen != NULL; Screen = ScreenList.GetNext() )
    {
        bool ModifyWires;
        ModifyWires = Screen->SchematicCleanUp( NULL );

        /* if wire list has changed, delete Udo Redo list to avoid
         *  pointers on deleted data problems */
        if( ModifyWires )
            Screen->ClearUndoRedoList();
    }

    m_Parent->BuildNetListBase();

    /* Analyse de la table des connexions : */
    Lim = g_TabObjNet + g_NbrObjNet;

    /* Reset du flag m_FlagOfConnection, utilise par la suite */
    for( NetItemRef = g_TabObjNet;  NetItemRef < Lim;   NetItemRef++ )
        NetItemRef->m_FlagOfConnection = (IsConnectType) 0;

    NetNbItems = 0;
    MinConn    = NOC;

    StartNet = OldItem = NetItemRef = g_TabObjNet;

    for( ; NetItemRef < Lim; NetItemRef++ )
    {
        /* Tst changement de net */
        if( OldItem->GetNet() != NetItemRef->GetNet() )
        {
            MinConn    = NOC;
            NetNbItems = 0;
            StartNet   = NetItemRef;
        }

        switch( NetItemRef->m_Type )
        {
        case NET_SEGMENT:
        case NET_BUS:
        case NET_JONCTION:
        case NET_LABEL:
        case NET_BUSLABELMEMBER:
        case NET_PINLABEL:
        case NET_GLOBLABEL: //not sure how to handle global labels -- they should be treated like other nets (just global!0
        case NET_GLOBBUSLABELMEMBER:
            break;

        case NET_HIERLABEL:
        case NET_HIERBUSLABELMEMBER:
        case NET_SHEETLABEL:
        case NET_SHEETBUSLABELMEMBER:
            TestLabel( m_Parent->DrawPanel, &dc, NetItemRef, StartNet );
            break;

        case NET_NOCONNECT:
            MinConn = NET_NC;
            if( NetNbItems != 0 )
                Diagnose( m_Parent->DrawPanel, &dc, NetItemRef, NULL, MinConn, UNC );
            break;

        case NET_PIN:
            TestOthersItems( m_Parent->DrawPanel, &dc,
                NetItemRef, StartNet, &NetNbItems, &MinConn );
            break;
        }

        OldItem = NetItemRef;
    }

    FreeTabNetList( g_TabObjNet, g_NbrObjNet );

    wxString num;
    num.Printf( wxT( "%d" ), g_EESchemaVar.NbErrorErc );
    m_TotalErrCount->SetLabel( num );

    num.Printf( wxT( "%d" ), g_EESchemaVar.NbErrorErc - g_EESchemaVar.NbWarningErc );
    m_LastErrCount->SetLabel( num );

    num.Printf( wxT( "%d" ), g_EESchemaVar.NbWarningErc );
    m_LastWarningCount->SetLabel( num );

    /* Generation ouverture fichier diag */
    if( WriteFichierERC == TRUE )
    {
        wxString ErcFullFileName;
        ErcFullFileName = g_RootSheet->m_AssociatedScreen->m_FileName;
        ChangeFileNameExt( ErcFullFileName, wxT( ".erc" ) );

        ErcFullFileName = EDA_FileSelector( _( "ERC file:" ),
            wxEmptyString,                                      /* Chemin par defaut */
            ErcFullFileName,                                    /* nom fichier par defaut */
            wxT( ".erc" ),                                      /* extension par defaut */
            wxT( "*.erc" ),                                     /* Masque d'affichage */
            this,
            wxFD_SAVE,
            TRUE
            );
        if( ErcFullFileName.IsEmpty() )
            return;

        if( WriteDiagnosticERC( ErcFullFileName ) )
        {
            Close( TRUE );
            wxString editorname = GetEditorName();
            AddDelimiterString( ErcFullFileName );
            ExecuteFile( this, editorname, ErcFullFileName );
        }
    }
}


/***********************************************************/
void WinEDA_ErcFrame::DelERCMarkers( wxCommandEvent& event )
/***********************************************************/

/* Delete the old ERC markers, over the whole hierarchy
 */
{
    EDA_BaseStruct*   DrawStruct;
    DrawMarkerStruct* Marker;

    wxClientDC dc( m_Parent->DrawPanel );

    m_Parent->DrawPanel->PrepareGraphicContext( &dc );

    // Delete markers for the current screen
    DrawStruct = m_Parent->GetScreen()->EEDrawList;
    for( ; DrawStruct != NULL; DrawStruct = DrawStruct->Pnext )
    {
        if( DrawStruct->Type() != DRAW_MARKER_STRUCT_TYPE )
            continue;

        /* Marqueur trouve */
        Marker = (DrawMarkerStruct*) DrawStruct;
        if( Marker->m_Type == MARQ_ERC )
            RedrawOneStruct( m_Parent->DrawPanel, &dc, Marker, g_XorMode );
    }

    /* Suppression en memoire des marqueurs ERC */
    DeleteAllMarkers( MARQ_ERC );
}


/**************************************************************/
void WinEDA_ErcFrame::ResetDefaultERCDiag( wxCommandEvent& event )
/**************************************************************/

/* Remet aux valeurs par defaut la matrice de diagnostic
 */
{
    memcpy( DiagErc, DefaultDiagErc, sizeof(DiagErc) );
    ReBuildMatrixPanel();
}


/************************************************************/
void WinEDA_ErcFrame::ChangeErrorLevel( wxCommandEvent& event )
/************************************************************/

/* Change the error level for the pressed button, on the matrix table
 */
{
    int             id, level, ii, x, y;
    wxBitmapButton* Butt;
    const char**    new_bitmap_xpm = NULL;
    wxPoint         pos;

    id   = event.GetId();
    ii   = id - ID_MATRIX_0;
    Butt = (wxBitmapButton*) event.GetEventObject();
    pos  = Butt->GetPosition();

    x = ii / PIN_NMAX; y = ii % PIN_NMAX;

    level = DiagErc[y][x];

    switch( level )
    {
    case OK:
        level = WAR;
        new_bitmap_xpm = warning_xpm;
        break;

    case WAR:
        level = ERR;
        new_bitmap_xpm = error_xpm;
        break;

    case ERR:
        level = OK;
        new_bitmap_xpm = green_xpm;
        break;
    }

    if( new_bitmap_xpm )
    {
        delete Butt;
        Butt = new wxBitmapButton( m_PanelERCOptions, id,
                                   wxBitmap (new_bitmap_xpm), pos );

        m_ButtonList[y][x] = Butt;
        DiagErc[y][x] = DiagErc[x][y] = level;
    }
}


/********************************************************/
static void Diagnose( WinEDA_DrawPanel* panel, wxDC* DC,
                      ObjetNetListStruct* NetItemRef,
                      ObjetNetListStruct* NetItemTst,
                      int MinConn, int Diag )
/********************************************************/

/* Routine de creation du marqueur ERC correspondant au conflit electrique
 *  entre NetItemRef et NetItemTst
 *  si MinConn < 0: Traitement des erreurs sur labels
 */
{
    DrawMarkerStruct* Marker = NULL;
    wxString          DiagLevel;
    SCH_SCREEN*       screen;
    int ii, jj;

    if( Diag == OK )
        return;

    /* Creation du nouveau marqueur type Erreur ERC */
    Marker = new DrawMarkerStruct( NetItemRef->m_Start, wxEmptyString );

    Marker->m_Type      = MARQ_ERC;
    Marker->m_MarkFlags = WAR;
    screen = NetItemRef->m_SheetList.LastScreen();
    Marker->Pnext      = screen->EEDrawList;
    screen->EEDrawList = Marker;
    g_EESchemaVar.NbErrorErc++;
    g_EESchemaVar.NbWarningErc++;

    if( MinConn < 0 )   // Traitement des erreurs sur labels
    {
        if( (NetItemRef->m_Type == NET_HIERLABEL)
           || (NetItemRef->m_Type == NET_HIERBUSLABELMEMBER) )
        {
            Marker->m_Comment.Printf( _( "Warning HLabel %s not connected to SheetLabel" ),
                NetItemRef->m_Label->GetData() );
        }
        else
            Marker->m_Comment.Printf( _( "Warning SheetLabel %s not connected to HLabel" ),
                NetItemRef->m_Label->GetData() );

        if( screen == panel->GetScreen() )
            RedrawOneStruct( panel, DC, Marker, GR_COPY );
        return;
    }

    ii = NetItemRef->m_ElectricalType;

    if( NetItemTst == NULL )
    {
        if( MinConn == NOC )    /* 1 seul element dans le net */
        {
            Marker->m_Comment.Printf( _( "Warning Pin %s Unconnected" ), MsgPinElectricType[ii] );
            if( screen == panel->GetScreen() )
                RedrawOneStruct( panel, DC, Marker, GR_COPY );
            return;
        }

        if( MinConn == NOD )    /* pas de pilotage du net */
        {
            Marker->m_Comment.Printf(
                _( "Warning Pin %s not driven (Net %d)" ),
                MsgPinElectricType[ii], NetItemRef->GetNet() );

            if( screen == panel->GetScreen() )
                RedrawOneStruct( panel, DC, Marker, GR_COPY );
            return;
        }

        if( Diag == UNC )
        {
            Marker->m_Comment.Printf(
                _( "Warning More than 1 Pin connected to UnConnect symbol" ) );

            if( screen == panel->GetScreen() )
                RedrawOneStruct( panel, DC, Marker, GR_COPY );
            return;
        }
    }

    if( NetItemTst )         /* Erreur entre 2 pins */
    {
        jj = NetItemTst->m_ElectricalType;
        DiagLevel = _( "Warning" );
        if( Diag == ERR )
        {
            DiagLevel = _( "Error" );
            Marker->m_MarkFlags = ERR;
            g_EESchemaVar.NbWarningErc--;
        }

        Marker->m_Comment.Printf( _(
                "%s: Pin %s connected to Pin %s (net %d)" ),
            DiagLevel.GetData(),
            MsgPinElectricType[ii],
            MsgPinElectricType[jj], NetItemRef->GetNet() );

        if( screen == panel->GetScreen() )
            RedrawOneStruct( panel, DC, Marker, GR_COPY );
    }
}


/********************************************************************/
static void TestOthersItems( WinEDA_DrawPanel* panel, wxDC* DC,
                             ObjetNetListStruct* NetItemRef,
                             ObjetNetListStruct* netstart,
                             int* NetNbItems, int* MinConnexion )
/********************************************************************/

/* Routine testant les conflits electriques entre
 *  NetItemRef
 *  et les autres items du meme net
 */
{
    ObjetNetListStruct* NetItemTst;
    ObjetNetListStruct* Lim;

    int ref_elect_type, jj, erc = OK, local_minconn;

    /* Analyse de la table des connexions : */
    Lim = g_TabObjNet + g_NbrObjNet;    // pointe la fin de la liste

    ref_elect_type = NetItemRef->m_ElectricalType;

    NetItemTst    = netstart;
    local_minconn = NOC;

    /* Examen de la liste des Pins connectees a NetItemRef */
    for( ; ; NetItemTst++ )
    {
        if( NetItemRef == NetItemTst )
            continue;

        /* Est - on toujours dans le meme net ? */
        if( (NetItemTst >= Lim)                                     // fin de liste (donc fin de net)
           || ( NetItemRef->GetNet() != NetItemTst->GetNet() ) )    // fin de net
        {                                                           /* Fin de netcode trouve: Tst connexion minimum */
            if( (*MinConnexion < NET_NC )
               && (local_minconn < NET_NC ) )                       /* pin non connect�e ou non pilotee */
            {
                Diagnose( panel, DC, NetItemRef, NULL, local_minconn, WAR );
                *MinConnexion = DRV;   // inhibition autres messages de ce type pour ce net
            }
            return;
        }

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

        case NET_NOCONNECT:
            local_minconn = MAX( NET_NC, local_minconn );
            break;

        case NET_PIN:
            jj = NetItemTst->m_ElectricalType;
            local_minconn = MAX( MinimalReq[ref_elect_type][jj], local_minconn );

            if( NetItemTst <= NetItemRef )
                break;

            *NetNbItems += 1;
            if( erc == OK )         // 1 marqueur par pin maxi
            {
                erc = DiagErc[ref_elect_type][jj];
                if( erc != OK )
                {
                    if( NetItemTst->m_FlagOfConnection == 0 )
                    {
                        Diagnose( panel, DC, NetItemRef, NetItemTst, 0, erc );
                        NetItemTst->m_FlagOfConnection = (IsConnectType) 1;
                    }
                }
            }
            break;
        }
    }
}


/********************************************************/
static bool WriteDiagnosticERC( const wxString& FullFileName )
/*********************************************************/

/* Create the Diagnostic file (<xxx>.erc file)
 */
{
    EDA_BaseStruct*   DrawStruct;
    DrawMarkerStruct* Marker;
    char Line[256];
    static FILE*      OutErc;
    DrawSheetPath*    Sheet;
    wxString          msg;

    if( ( OutErc = wxFopen( FullFileName, wxT( "wt" ) ) ) == NULL )
        return FALSE;

    DateAndTime( Line );
    msg = _( "ERC control" );

    fprintf( OutErc, "%s (%s)\n", CONV_TO_UTF8( msg ), Line );

    EDA_SheetList SheetList( NULL );

    for( Sheet = SheetList.GetFirst(); Sheet != NULL; Sheet = SheetList.GetNext() )
    {
        if( Sheet->Last() == g_RootSheet )
        {
            msg.Printf( _( "\n***** Sheet / (Root) \n" ) );
        }
        else
        {
            wxString str = Sheet->PathHumanReadable();
            msg.Printf( _( "\n***** Sheet %s\n" ), str.GetData() );
        }

        fprintf( OutErc, "%s", CONV_TO_UTF8( msg ) );

        DrawStruct = Sheet->LastDrawList();
        for( ; DrawStruct != NULL; DrawStruct = DrawStruct->Pnext )
        {
            if( DrawStruct->Type() != DRAW_MARKER_STRUCT_TYPE )
                continue;

            /* Marqueur trouve */
            Marker = (DrawMarkerStruct*) DrawStruct;
            if( Marker->m_Type != MARQ_ERC )
                continue;

            /* Write diag marqueur */
            msg.Printf( _( "ERC: %s (X= %2.3f inches, Y= %2.3f inches\n" ),
                Marker->GetComment().GetData(),
                (float) Marker->m_Pos.x / 1000,
                (float) Marker->m_Pos.y / 1000 );

            fprintf( OutErc, "%s", CONV_TO_UTF8( msg ) );
        }
    }

    msg.Printf( _( "\n >> Errors ERC: %d\n" ), g_EESchemaVar.NbErrorErc );
    fprintf( OutErc, "%s", CONV_TO_UTF8( msg ) );
    fclose( OutErc );

    return TRUE;
}


bool TestLabel_( ObjetNetListStruct* a, ObjetNetListStruct* b )
{
    int at = a->m_Type;
    int bt = b->m_Type;

    if( (at == NET_HIERLABEL || at == NET_HIERBUSLABELMEMBER)
       &&(bt == NET_SHEETLABEL || bt == NET_SHEETBUSLABELMEMBER) )
    {
        if( a->m_SheetList == b->m_SheetListInclude )
        {
            return true; //connected!
        }
    }
    return false; //these two are unconnected
}


/***********************************************************************/
void TestLabel( WinEDA_DrawPanel* panel, wxDC* DC,
                ObjetNetListStruct* NetItemRef, ObjetNetListStruct* StartNet )
/***********************************************************************/

/* Routine controlant qu'un sheetLabel est bien connecte a un Glabel de la
 *  sous-feuille correspondante
 */
{
    ObjetNetListStruct* NetItemTst, * Lim;
    int erc = 1;

    /* Analyse de la table des connexions : */
    Lim = g_TabObjNet + g_NbrObjNet;

    NetItemTst = StartNet;

    /* Examen de la liste des Labels connectees a NetItemRef */
    for( ; ; NetItemTst++ )
    {
        if( NetItemTst == NetItemRef )
            continue;

        /* Est - on toujours dans le meme net ? */
        if( ( NetItemTst ==  Lim )
           || ( NetItemRef->GetNet() != NetItemTst->GetNet() ) )
        {
            /* Fin de netcode trouve */
            if( erc )
            {
                /* GLabel ou SheetLabel orphelin */
                Diagnose( panel, DC, NetItemRef, NULL, -1, WAR );
            }
            return;
        }
        if( TestLabel_( NetItemRef, NetItemTst ) )
            erc = 0;

        //same thing, different order.
        if( TestLabel_( NetItemTst, NetItemRef ) )
            erc = 0;
    }
}
