/**
 * Function missingLegacyLibs
 * tests the list of \a aLibNames by URI to determine if any of them are missing from
 * the #FP_LIB_TABLE.
 *
 * @note The missing legacy footprint library test is performed by using old library
 *       file path lookup method.  If the library is found, it is compared against all
 *       of the URIs in the table rather than the nickname.  This was done because the
 *       user could change the nicknames from the default table.  Using the full path
 *       is more reliable.
 *
 * @param aLibNames is the list of legacy library names.
 * @param aErrorMsg is a pointer to a wxString object to store the URIs of any missing
 *                  legacy library paths.  Can be NULL.
 * @return true if there are missing legacy libraries.  Otherwise false.
 */
static bool missingLegacyLibs( FP_LIB_TABLE* aTbl, SEARCH_STACK& aSStack,
        const wxArrayString& aLibNames, wxString* aErrorMsg )
{
    bool missing = false;

    for( unsigned i = 0;  i < aLibNames.GetCount();  i++ )
    {
        wxFileName  fn( wxEmptyString, aLibNames[i], LegacyFootprintLibPathExtension );

        wxString    legacyLibPath = aSStack.FindValidPath( fn.GetFullPath() );

        /*
        if( legacyLibPath.IsEmpty() )
            continue;
        */

        if( !aTbl->FindRowByURI( legacyLibPath ) )
        {
            missing = true;

            if( aErrorMsg )
            {
                *aErrorMsg += wxChar( '"' );

                if( !legacyLibPath )
                    *aErrorMsg += !legacyLibPath ? aLibNames[i] : legacyLibPath;

                *aErrorMsg += wxT( "\"\n" );
            }
        }
    }

    return missing;
}
static bool copy_pro_file_template( const SEARCH_STACK& aSearchS, const wxString& aDestination )
{
    if( aDestination.IsEmpty() )
    {
        wxLogTrace( tracePathsAndFiles, "%s: destination is empty.", __func__ );
        return false;
    }

    wxString templateFile = wxT( "kicad." ) + ProjectFileExtension;

    wxString kicad_pro_template = aSearchS.FindValidPath( templateFile );

    if( !kicad_pro_template )
    {
        wxLogTrace( tracePathsAndFiles, "%s: template file '%s' not found using search paths.",
                    __func__, TO_UTF8( templateFile ) );

        wxFileName  templ( wxStandardPaths::Get().GetDocumentsDir(),
                            wxT( "kicad" ), ProjectFileExtension );

        if( !templ.IsFileReadable() )
        {
            wxString msg = wxString::Format( _(
                    "Unable to find \"%s\" template config file." ),
                    GetChars( templateFile ) );

            DisplayErrorMessage( nullptr, _( "Error copying project file template" ), msg );

            return false;
        }

        kicad_pro_template = templ.GetFullPath();
    }

    wxLogTrace( tracePathsAndFiles, "%s: using template file '%s' as project file.",
                __func__, TO_UTF8( kicad_pro_template ) );

    // Verify aDestination can be created. if this is not the case, wxCopyFile
    // will generate a crappy log error message, and we *do not want* this kind
    // of stupid message
    wxFileName fn( aDestination );
    bool success = true;

    if( fn.IsOk() && fn.IsDirWritable() )
        success = wxCopyFile( kicad_pro_template, aDestination );
    else
    {
        wxLogMessage( _( "Cannot create prj file \"%s\" (Directory not writable)" ),
                      GetChars( aDestination) );
        success = false;
    }

    return success;
}
/**
 * Function convertFromLegacy
 * converts the footprint names in \a aNetList from the legacy format to the #FPID format.
 *
 * @param aNetList is the #NETLIST object to convert.
 * @param aLibNames is the list of legacy footprint library names from the currently loaded
 *                  project.
 * @param aReporter is the #REPORTER object to dump messages into.
 * @return true if all footprint names were successfully converted to a valid FPID.
 */
static bool convertFromLegacy( FP_LIB_TABLE* aTbl, SEARCH_STACK& aSStack, NETLIST& aNetList,
        const wxArrayString& aLibNames, REPORTER* aReporter = NULL ) throw( IO_ERROR )
{
    wxString   msg;
    FPID       lastFPID;
    COMPONENT* component;
    MODULE*    module = 0;
    bool       retv = true;

    if( aNetList.IsEmpty() )
        return true;

    aNetList.SortByFPID();

    wxString   libPath;

    PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::LEGACY ) );

    for( unsigned ii = 0; ii < aNetList.GetCount(); ii++ )
    {
        component = aNetList.GetComponent( ii );

        // The footprint hasn't been assigned yet so ignore it.
        if( component->GetFPID().empty() )
            continue;

        if( component->GetFPID() != lastFPID )
        {
            module = NULL;

            for( unsigned ii = 0; ii < aLibNames.GetCount(); ii++ )
            {
                wxFileName fn( wxEmptyString, aLibNames[ii], LegacyFootprintLibPathExtension );

                libPath = aSStack.FindValidPath( fn.GetFullPath() );

                if( !libPath )
                {
                    if( aReporter )
                    {
                        msg.Printf( _( "Cannot find footprint library file '%s' in any of the "
                                       "KiCad legacy library search paths.\n" ),
                                    GetChars( fn.GetFullPath() ) );
                        aReporter->Report( msg );
                    }

                    retv = false;
                    continue;
                }

                module = pi->FootprintLoad( libPath, component->GetFPID().GetFootprintName() );

                if( module )
                {
                    lastFPID = component->GetFPID();
                    break;
                }
            }
        }

        if( !module )
        {
            if( aReporter )
            {
                msg.Printf( _( "Component '%s' footprint '%s' was not found in any legacy "
                               "library.\n" ),
                            GetChars( component->GetReference() ),
                            GetChars( component->GetFPID().Format() ) );
                aReporter->Report( msg );
            }

            // Clear the footprint assignment since the old library lookup method is no
            // longer valid.
            FPID emptyFPID;

            component->SetFPID( emptyFPID );
            retv = false;
            continue;
        }
        else
        {
            wxString    libNickname;

            const FP_LIB_TABLE::ROW* row;

            if( ( row = aTbl->FindRowByURI( libPath ) ) != NULL )
                libNickname = row->GetNickName();

            if( libNickname.IsEmpty() )
            {
                if( aReporter )
                {
                    msg.Printf( _( "Component '%s' with footprint '%s' and legacy library path '%s' "
                                   "was not found in the footprint library table.\n" ),
                                GetChars( component->GetReference() ),
                                GetChars( component->GetFPID().Format() ),
                                GetChars( libPath )
                                );
                    aReporter->Report( msg );
                }

                retv = false;
            }
            else
            {
                FPID newFPID = lastFPID;
                newFPID.SetLibNickname( libNickname );

                if( !newFPID.IsValid() )
                {
                    if( aReporter )
                    {
                        msg.Printf( _( "Component '%s' FPID '%s' is not valid.\n" ),
                                    GetChars( component->GetReference() ),
                                    GetChars( newFPID.Format() ) );
                        aReporter->Report( msg );
                    }

                    retv = false;
                }
                else
                {
                    // The footprint name should already be set.
                    component->SetFPID( newFPID );
                }
            }
        }
    }

    return retv;
}