/* Plot an arc in DXF format
 * Filling is not supported
 */
void DXF_PLOTTER::Arc( const wxPoint& centre, double StAngle, double EndAngle, int radius,
                       FILL_T fill, int width )
{
    wxASSERT( outputFile );

    if( radius <= 0 )
        return;

    // In DXF, arcs are drawn CCW.
    // In Kicad, arcs are CW or CCW
    // If StAngle > EndAngle, it is CW. So transform it to CCW
    if( StAngle > EndAngle )
    {
        std::swap( StAngle, EndAngle );
    }

    DPOINT centre_dev = userToDeviceCoordinates( centre );
    double radius_dev = userToDeviceSize( radius );

    // Emit a DXF ARC entity
    wxString cname( ColorGetName( m_currentColor ) );
    fprintf( outputFile,
             "0\nARC\n8\n%s\n10\n%g\n20\n%g\n40\n%g\n50\n%g\n51\n%g\n",
             TO_UTF8( cname ),
             centre_dev.x, centre_dev.y, radius_dev,
             StAngle / 10.0, EndAngle / 10.0 );
}
/**
 * DXF circle: full functionality; it even does 'fills' drawing a
 * circle with a dual-arc polyline wide as the radius.
 *
 * I could use this trick to do other filled primitives
 */
void DXF_PLOTTER::Circle( const wxPoint& centre, int diameter, FILL_T fill, int width )
{
    wxASSERT( outputFile );
    double radius = userToDeviceSize( diameter / 2 );
    DPOINT centre_dev = userToDeviceCoordinates( centre );
    if( radius > 0 )
    {
        wxString cname( ColorGetName( m_currentColor ) );
        if (!fill)
        {
            fprintf( outputFile, "0\nCIRCLE\n8\n%s\n10\n%g\n20\n%g\n40\n%g\n",
                    TO_UTF8( cname ),
                    centre_dev.x, centre_dev.y, radius );
        }
        if (fill == FILLED_SHAPE)
        {
            double r = radius*0.5;
            fprintf( outputFile, "0\nPOLYLINE\n");
            fprintf( outputFile, "8\n%s\n66\n1\n70\n1\n", TO_UTF8( cname ));
            fprintf( outputFile, "40\n%g\n41\n%g\n", radius, radius);
            fprintf( outputFile, "0\nVERTEX\n8\n%s\n", TO_UTF8( cname ));
            fprintf( outputFile, "10\n%g\n 20\n%g\n42\n1.0\n",
                    centre_dev.x-r, centre_dev.y );
            fprintf( outputFile, "0\nVERTEX\n8\n%s\n", TO_UTF8( cname ));
            fprintf( outputFile, "10\n%g\n 20\n%g\n42\n1.0\n",
                    centre_dev.x+r, centre_dev.y );
            fprintf( outputFile, "0\nSEQEND\n");
        }
    }
}
void PARAM_CFG_SETCOLOR::SaveParam( wxConfigBase* aConfig ) const
{
    if( !m_Pt_param || !aConfig )
        return;

    aConfig->Write( m_Ident, ColorGetName( *m_Pt_param ) );
}
EDA_COLOR_T ColorByName( const wxString& aName )
{
    // look for a match in the palette itself
    for( EDA_COLOR_T trying = BLACK; trying < NBCOLORS; trying = NextColor(trying) )
    {
        if( 0 == aName.CmpNoCase( ColorGetName( trying ) ) )
            return trying;
    }

    // Not found, no idea...
    return UNSPECIFIED_COLOR;
}
void LIB_VIEW_FRAME::SaveSettings( wxConfigBase* aCfg )
{
    EDA_DRAW_FRAME::SaveSettings( aCfg );

    wxConfigPathChanger cpc( aCfg, m_configPath );

    if( m_libListWidth && m_libList )
    {
        m_libListWidth = m_libList->GetSize().x;
        aCfg->Write( LIBLIST_WIDTH_KEY, m_libListWidth );
    }

    m_cmpListWidth = m_cmpList->GetSize().x;
    aCfg->Write( CMPLIST_WIDTH_KEY, m_cmpListWidth );
    aCfg->Write( LIBVIEW_BGCOLOR, ColorGetName( GetDrawBgColor() ) );
}
void DXF_PLOTTER::PenTo( const wxPoint& pos, char plume )
{
    wxASSERT( outputFile );
    if( plume == 'Z' )
    {
        return;
    }
    DPOINT pos_dev = userToDeviceCoordinates( pos );
    DPOINT pen_lastpos_dev = userToDeviceCoordinates( penLastpos );

    if( penLastpos != pos && plume == 'D' )
    {
        // DXF LINE
        wxString cname( ColorGetName( m_currentColor ) );
        fprintf( outputFile, "0\nLINE\n8\n%s\n10\n%g\n20\n%g\n11\n%g\n21\n%g\n",
                 TO_UTF8( cname ),
                 pen_lastpos_dev.x, pen_lastpos_dev.y, pos_dev.x, pos_dev.y );
    }
    penLastpos = pos;
}
void DXF_PLOTTER::Text( const wxPoint&              aPos,
                        enum EDA_COLOR_T            aColor,
                        const wxString&             aText,
                        double                      aOrient,
                        const wxSize&               aSize,
                        enum EDA_TEXT_HJUSTIFY_T    aH_justify,
                        enum EDA_TEXT_VJUSTIFY_T    aV_justify,
                        int                         aWidth,
                        bool                        aItalic,
                        bool                        aBold,
                        bool                        aMultilineAllowed )
{
    // Fix me: see how to use DXF text mode for multiline texts
    if( aMultilineAllowed && !aText.Contains( wxT( "\n" ) ) )
        aMultilineAllowed = false;  // the text has only one line.

    if( textAsLines || containsNonAsciiChars( aText ) || aMultilineAllowed )
    {
        // output text as graphics.
        // Perhaps miltiline texts could be handled as DXF text entity
        // but I do not want spend time about this (JPC)
        PLOTTER::Text( aPos, aColor, aText, aOrient, aSize, aH_justify, aV_justify,
                aWidth, aItalic, aBold, aMultilineAllowed );
    }
    else
    {
        /* Emit text as a text entity. This loses formatting and shape but it's
           more useful as a CAD object */
        DPOINT origin_dev = userToDeviceCoordinates( aPos );
        SetColor( aColor );
        wxString cname( ColorGetName( m_currentColor ) );
        DPOINT size_dev = userToDeviceSize( aSize );
        int h_code = 0, v_code = 0;
        switch( aH_justify )
        {
        case GR_TEXT_HJUSTIFY_LEFT:
            h_code = 0;
            break;
        case GR_TEXT_HJUSTIFY_CENTER:
            h_code = 1;
            break;
        case GR_TEXT_HJUSTIFY_RIGHT:
            h_code = 2;
            break;
        }
        switch( aV_justify )
        {
        case GR_TEXT_VJUSTIFY_TOP:
            v_code = 3;
            break;
        case GR_TEXT_VJUSTIFY_CENTER:
            v_code = 2;
            break;
        case GR_TEXT_VJUSTIFY_BOTTOM:
            v_code = 1;
            break;
        }

        // Position, size, rotation and alignment
        // The two alignment point usages is somewhat idiot (see the DXF ref)
        // Anyway since we don't use the fit/aligned options, they're the same
        fprintf( outputFile,
                "  0\n"
                "TEXT\n"
                "  7\n"
                "%s\n"          // Text style
                "  8\n"
                "%s\n"          // Layer name
                "  10\n"
                "%g\n"          // First point X
                "  11\n"
                "%g\n"          // Second point X
                "  20\n"
                "%g\n"          // First point Y
                "  21\n"
                "%g\n"          // Second point Y
                "  40\n"
                "%g\n"          // Text height
                "  41\n"
                "%g\n"          // Width factor
                "  50\n"
                "%g\n"          // Rotation
                "  51\n"
                "%g\n"          // Oblique angle
                "  71\n"
                "%d\n"          // Mirror flags
                "  72\n"
                "%d\n"          // H alignment
                "  73\n"
                "%d\n",         // V alignment
                aBold ? (aItalic ? "KICADBI" : "KICADB")
                      : (aItalic ? "KICADI" : "KICAD"),
                TO_UTF8( cname ),
                origin_dev.x, origin_dev.x,
                origin_dev.y, origin_dev.y,
                size_dev.y, fabs( size_dev.x / size_dev.y ),
                aOrient / 10.0,
                aItalic ? DXF_OBLIQUE_ANGLE : 0,
                size_dev.x < 0 ? 2 : 0, // X mirror flag
                h_code, v_code );

        /* There are two issue in emitting the text:
           - Our overline character (~) must be converted to the appropriate
           control sequence %%O or %%o
           - Text encoding in DXF is more or less unspecified since depends on
           the DXF declared version, the acad version reading it *and* some
           system variables to be put in the header handled only by newer acads
           Also before R15 unicode simply is not supported (you need to use
           bigfonts which are a massive PITA). Common denominator solution:
           use Latin1 (and however someone could choke on it, anyway). Sorry
           for the extended latin people. If somewant want to try fixing this
           recent version seems to use UTF-8 (and not UCS2 like the rest of
           Windows)

           XXX Actually there is a *third* issue: older DXF formats are limited
           to 255 bytes records (it was later raised to 2048); since I'm lazy
           and text so long is not probable I just don't implement this rule.
           If someone is interested in fixing this, you have to emit the first
           partial lines with group code 3 (max 250 bytes each) and then finish
           with a group code 1 (less than 250 bytes). The DXF refs explains it
           in no more details...
         */

        bool overlining = false;
        fputs( "  1\n", outputFile );
        for( unsigned i = 0; i < aText.length(); i++ )
        {
            /* Here I do a bad thing: writing the output one byte at a time!
               but today I'm lazy and I have no idea on how to coerce a Unicode
               wxString to spit out latin1 encoded text ...

               Atleast stdio is *supposed* to do output buffering, so there is
               hope is not too slow */
            wchar_t ch = aText[i];
            if( ch > 255 )
            {
                // I can't encode this...
                putc( '?', outputFile );
            }
            else
            {
                if( ch == '~' )
                {
                    // Handle the overline toggle
                    fputs( overlining ? "%%o" : "%%O", outputFile );
                    overlining = !overlining;
                }
                else
                {
                    putc( ch, outputFile );
                }
            }
        }
        putc( '\n', outputFile );
    }
}