void GENDRILL_WRITER_BASE::CreateMapFilesSet( const wxString& aPlotDirectory,
                                              REPORTER * aReporter )
{
    wxFileName  fn;
    wxString    msg;

    std::vector<DRILL_LAYER_PAIR> hole_sets = getUniqueLayerPairs();

    // append a pair representing the NPTH set of holes, for separate drill files.
    if( !m_merge_PTH_NPTH )
        hole_sets.push_back( DRILL_LAYER_PAIR( F_Cu, B_Cu ) );

    for( std::vector<DRILL_LAYER_PAIR>::const_iterator it = hole_sets.begin();
         it != hole_sets.end();  ++it )
    {
        DRILL_LAYER_PAIR  pair = *it;
        // For separate drill files, the last layer pair is the NPTH drill file.
        bool doing_npth = m_merge_PTH_NPTH ? false : ( it == hole_sets.end() - 1 );

        buildHolesList( pair, doing_npth );

        // The file is created if it has holes, or if it is the non plated drill file
        // to be sure the NPTH file is up to date in separate files mode.
        if( getHolesCount() > 0 || doing_npth )
        {
            fn = getDrillFileName( pair, doing_npth, m_merge_PTH_NPTH );
            fn.SetPath( aPlotDirectory );

            fn.SetExt( wxEmptyString ); // Will be added by GenDrillMap
            wxString fullfilename = fn.GetFullPath() + wxT( "-drl_map" );
            fullfilename << wxT(".") << GetDefaultPlotExtension( m_mapFileFmt );

            bool success = genDrillMapFile( fullfilename, m_mapFileFmt );

            if( ! success )
            {
                if( aReporter )
                {
                    msg.Printf( _( "** Unable to create %s **\n" ), GetChars( fullfilename ) );
                    aReporter->Report( msg );
                }

                return;
            }
            else
            {
                if( aReporter )
                {
                    msg.Printf( _( "Create file %s\n" ), GetChars( fullfilename ) );
                    aReporter->Report( msg );
                }
            }
        }
    }
}
bool GENDRILL_WRITER_BASE::GenDrillReportFile( const wxString& aFullFileName )
{
    FILE_OUTPUTFORMATTER    out( aFullFileName );

    static const char separator[] =
        "    =============================================================\n";

    wxASSERT( m_pcb );

    unsigned    totalHoleCount;
    wxString    brdFilename = m_pcb->GetFileName();

    std::vector<DRILL_LAYER_PAIR> hole_sets = getUniqueLayerPairs();

    out.Print( 0, "Drill report for %s\n", TO_UTF8( brdFilename ) );
    out.Print( 0, "Created on %s\n\n", TO_UTF8( DateAndTime() ) );

    // Output the cu layer stackup, so layer name references make sense.
    out.Print( 0, "Copper Layer Stackup:\n" );
    out.Print( 0, separator );

    LSET cu = m_pcb->GetEnabledLayers() & LSET::AllCuMask();

    int conventional_layer_num = 1;

    for( LSEQ seq = cu.Seq();  seq;  ++seq, ++conventional_layer_num )
    {
        out.Print( 0, "    L%-2d:  %-25s %s\n",
            conventional_layer_num,
            TO_UTF8( m_pcb->GetLayerName( *seq ) ),
            layerName( *seq ).c_str()       // generic layer name
            );
    }

    out.Print( 0, "\n\n" );

    /* output hole lists:
     * 1 - through holes
     * 2 - for partial holes only: by layer starting and ending pair
     * 3 - Non Plated through holes
     */

    bool buildNPTHlist = false;     // First pass: build PTH list only

    // in this loop are plated only:
    for( unsigned pair_ndx = 0; pair_ndx < hole_sets.size();  ++pair_ndx )
    {
        DRILL_LAYER_PAIR  pair = hole_sets[pair_ndx];

        buildHolesList( pair, buildNPTHlist );

        if( pair == DRILL_LAYER_PAIR( F_Cu, B_Cu ) )
        {
            out.Print( 0, "Drill file '%s' contains\n",
                TO_UTF8( getDrillFileName( pair, false, m_merge_PTH_NPTH ) ) );

            out.Print( 0, "    plated through holes:\n" );
            out.Print( 0, separator );
            totalHoleCount = printToolSummary( out, false );
            out.Print( 0, "    Total plated holes count %u\n", totalHoleCount );
        }
        else    // blind/buried
        {
            out.Print( 0, "Drill file '%s' contains\n",
                TO_UTF8( getDrillFileName( pair, false, m_merge_PTH_NPTH ) ) );

            out.Print( 0, "    holes connecting layer pair: '%s and %s' (%s vias):\n",
                TO_UTF8( m_pcb->GetLayerName( ToLAYER_ID( pair.first ) ) ),
                TO_UTF8( m_pcb->GetLayerName( ToLAYER_ID( pair.second ) ) ),
                pair.first == F_Cu || pair.second == B_Cu ? "blind" : "buried"
                );

            out.Print( 0, separator );
            totalHoleCount = printToolSummary( out, false );
            out.Print( 0, "    Total plated holes count %u\n", totalHoleCount );
        }

        out.Print( 0, "\n\n" );
    }

    // NPTHoles. Generate the full list (pads+vias) if PTH and NPTH are merged,
    // or only the NPTH list (which never has vias)
    if( !m_merge_PTH_NPTH )
        buildNPTHlist = true;

    buildHolesList( DRILL_LAYER_PAIR( F_Cu, B_Cu ), buildNPTHlist );

    // nothing wrong with an empty NPTH file in report.
    if( m_merge_PTH_NPTH )
        out.Print( 0, "Not plated through holes are merged with plated holes\n" );
    else
        out.Print( 0, "Drill file '%s' contains\n",
                   TO_UTF8( getDrillFileName( DRILL_LAYER_PAIR( F_Cu, B_Cu ),
                   true, m_merge_PTH_NPTH ) ) );

    out.Print( 0, "    unplated through holes:\n" );
    out.Print( 0, separator );
    totalHoleCount = printToolSummary( out, true );
    out.Print( 0, "    Total unplated holes count %u\n", totalHoleCount );

    return true;
}
void GERBER_WRITER::CreateDrillandMapFilesSet( const wxString& aPlotDirectory,
                                                 bool aGenDrill, bool aGenMap,
                                                 REPORTER * aReporter )
{
    // Note: In Gerber drill files, NPTH and PTH are always separate files
    m_merge_PTH_NPTH = false;

    wxFileName  fn;
    wxString    msg;

    std::vector<DRILL_LAYER_PAIR> hole_sets = getUniqueLayerPairs();

    // append a pair representing the NPTH set of holes, for separate drill files.
    // (Gerber drill files are separate files for PTH and NPTH)
    hole_sets.push_back( DRILL_LAYER_PAIR( F_Cu, B_Cu ) );

    for( std::vector<DRILL_LAYER_PAIR>::const_iterator it = hole_sets.begin();
         it != hole_sets.end();  ++it )
    {
        DRILL_LAYER_PAIR  pair = *it;
        // For separate drill files, the last layer pair is the NPTH drill file.
        bool doing_npth = ( it == hole_sets.end() - 1 );

        buildHolesList( pair, doing_npth );

        // The file is created if it has holes, or if it is the non plated drill file
        // to be sure the NPTH file is up to date in separate files mode.
        if( getHolesCount() > 0 || doing_npth )
        {
            fn = getDrillFileName( pair, doing_npth, false );
            fn.SetPath( aPlotDirectory );

            if( aGenDrill )
            {
                wxString fullFilename = fn.GetFullPath();

                int result = createDrillFile( fullFilename, doing_npth, pair.first, pair.second );

                if( result < 0 )
                {
                    if( aReporter )
                    {
                        msg.Printf( _( "** Unable to create %s **\n" ), GetChars( fullFilename ) );
                        aReporter->Report( msg );
                    }
                    break;
                }
                else
                {
                    if( aReporter )
                    {
                        msg.Printf( _( "Create file %s\n" ), GetChars( fullFilename ) );
                        aReporter->Report( msg );
                    }
                }

            }
        }
    }

    if( aGenMap )
        CreateMapFilesSet( aPlotDirectory, aReporter );
}