/**
 * @file title_block_shapes.cpp
 * @brief description of graphic items and texts to build a title block
 */

/*
 * This file creates a lot of structures which define the shape of a title block
 * and frame references
 */

/*
 * This program source code file is part of KiCad, a free EDA CAD application.
 *
 * Copyright (C) 1992-2013 Jean-Pierre Charras <jp.charras at wanadoo.fr>.
 * Copyright (C) 1992-2013 KiCad Developers, see change_log.txt for contributors.
 *
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, you may find one here:
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * or you may search the http://www.gnu.org website for the version 2 license,
 * or you may write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 */

#include <fctsys.h>
#include <drawtxt.h>
#include <worksheet.h>
#include <class_title_block.h>
#include <worksheet_shape_builder.h>

#define GRID_REF_W                      Mm2mils( 1.8 )  // height of the band reference grid
#define TEXTSIZE                        Mm2mils( 1.5 )  // worksheet text size
#define FRMREF_TXTSIZE                  Mm2mils( 1.3 )  // worksheet frame reference text size
#define VARIABLE_BLOCK_START_POSITION   (TEXTSIZE * 10)

// The coordinates below are relative to the bottom right corner of page and
// will be subtracted from this origin.
#define BLOCK_OX                Mm2mils( 106 )
#define BLOCK_KICAD_VERSION_X   BLOCK_OX - TEXTSIZE
#define BLOCK_KICAD_VERSION_Y   TEXTSIZE
#define BLOCK_REV_X             Mm2mils( 22 )
#define BLOCK_REV_Y             (TEXTSIZE * 3)
#define BLOCK_DATE_X            BLOCK_OX - (TEXTSIZE * 15)
#define BLOCK_DATE_Y            (TEXTSIZE * 3)
#define BLOCK_ID_SHEET_X        Mm2mils( 22 )
#define BLOCK_ID_SHEET_Y        TEXTSIZE
#define BLOCK_SIZE_SHEET_X      BLOCK_OX - TEXTSIZE
#define BLOCK_SIZE_SHEET_Y      (TEXTSIZE * 3)
#define BLOCK_TITLE_X           BLOCK_OX - TEXTSIZE
#define BLOCK_TITLE_Y           (TEXTSIZE * 5)
#define BLOCK_FULLSHEETNAME_X   BLOCK_OX - TEXTSIZE
#define BLOCK_FULLSHEETNAME_Y   (TEXTSIZE * 7)
#define BLOCK_FILENAME_X        BLOCK_OX - TEXTSIZE
#define BLOCK_FILENAME_Y        (TEXTSIZE * 9)
#define BLOCK_COMMENT_X         BLOCK_OX - TEXTSIZE
#define BLOCK_COMPANY_Y         (TEXTSIZE * 11)
#define BLOCK_COMMENT1_Y        (TEXTSIZE * 13)
#define BLOCK_COMMENT2_Y        (TEXTSIZE * 15)
#define BLOCK_COMMENT3_Y        (TEXTSIZE * 17)
#define BLOCK_COMMENT4_Y        (TEXTSIZE * 19)


// Text attributes set in m_Flags (ORed bits)
 #define USE_BOLD 1             // has meaning for texts
 #define USE_THICK_LINE 1       // equivalent to bold for lines
 #define USE_ITALIC 2           // has meaning for texts
 #define USE_TEXT_COLOR 4
 #define SET_UPPER_LIMIT 8      // Flag used to calculate variable position items

// Work sheet structure type definitions.
enum TypeKi_WorkSheetData {
    WS_TEXT,
    WS_SEGMENT,
    WS_UPPER_SEGMENT,
    WS_LEFT_SEGMENT
};


// superior horizontal segment: should be after comments
// to know the exact position
Ki_WorkSheetData WS_MostUpperLine =
{
    WS_UPPER_SEGMENT,
    NULL,
    BLOCK_OX,        TEXTSIZE * 16,
    0,               TEXTSIZE * 16,
    NULL
};

// Left vertical segment: should be after comments
// to know the exact position
Ki_WorkSheetData WS_MostLeftLine =
{
    WS_LEFT_SEGMENT,
    &WS_MostUpperLine,
    BLOCK_OX,         TEXTSIZE * 16,
    BLOCK_OX,             0,
    NULL
};

// horizontal segment between filename and comments
Ki_WorkSheetData WS_SeparatorLine =
{
    WS_SEGMENT,
    &WS_MostLeftLine,
    BLOCK_OX,         VARIABLE_BLOCK_START_POSITION,
    0,                VARIABLE_BLOCK_START_POSITION,
    NULL
};

Ki_WorkSheetData        WS_Date =
{
    WS_TEXT,
    &WS_SeparatorLine,
    BLOCK_DATE_X,   BLOCK_DATE_Y,
    0,                          0,
    wxT( "Date: %D" )
};

Ki_WorkSheetData        WS_Licence =
{
    WS_TEXT,
    &WS_Date,
    BLOCK_KICAD_VERSION_X,BLOCK_KICAD_VERSION_Y,
    0,
    0,
    wxT("%K")       // Kicad version
};

Ki_WorkSheetData        WS_Revision =
{
    WS_TEXT,
    &WS_Licence,
    BLOCK_REV_X,   BLOCK_REV_Y,
    0,                      0,
    wxT( "Rev: %R" ),
    USE_BOLD
};

Ki_WorkSheetData        WS_SizeSheet =
{
    WS_TEXT,
    &WS_Revision,
    BLOCK_SIZE_SHEET_X,BLOCK_SIZE_SHEET_Y,
    0,                                   0,
    wxT( "Size: %Z" )   // Paper format name
};

Ki_WorkSheetData        WS_IdentSheet =
{
    WS_TEXT,
    &WS_SizeSheet,
    BLOCK_ID_SHEET_X,BLOCK_ID_SHEET_Y,
    0,                               0,
    wxT( "Id: %S/%N" )
};

Ki_WorkSheetData        WS_Title =
{
    WS_TEXT,
    &WS_IdentSheet,
    BLOCK_TITLE_X,    BLOCK_TITLE_Y,
    0,                         0,
    wxT( "Title: %T" ),
    USE_BOLD
};

Ki_WorkSheetData        WS_SheetFilename =
{
    WS_TEXT,
    &WS_Title,
    BLOCK_FILENAME_X, BLOCK_FILENAME_Y,
    0,                               0,
    wxT( "File: %F" )
};

Ki_WorkSheetData        WS_FullSheetName =
{
    WS_TEXT,
    &WS_SheetFilename,
    BLOCK_FULLSHEETNAME_X,BLOCK_FULLSHEETNAME_Y,
    0,
    0,
    wxT( "Sheet: %P" )  // Full sheet name (sheet path)
};

Ki_WorkSheetData        WS_Company =
{
    WS_TEXT,
    &WS_FullSheetName,
    BLOCK_COMMENT_X,BLOCK_COMPANY_Y,
    0,                             0,
    wxT("%Y"),          // Company name
    USE_BOLD | SET_UPPER_LIMIT | USE_TEXT_COLOR
};

Ki_WorkSheetData        WS_Comment1 =
{
    WS_TEXT,
    &WS_Company,
    BLOCK_COMMENT_X,BLOCK_COMMENT1_Y,
    0,                              0,
    wxT("%C1"),           // Comment 1
    SET_UPPER_LIMIT | USE_TEXT_COLOR
};

Ki_WorkSheetData        WS_Comment2 =
{
    WS_TEXT,
    &WS_Comment1,
    BLOCK_COMMENT_X,BLOCK_COMMENT2_Y,
    0,                              0,
    wxT("%C2"),           // Comment 2
    SET_UPPER_LIMIT | USE_TEXT_COLOR
};

Ki_WorkSheetData        WS_Comment3 =
{
    WS_TEXT,
    &WS_Comment2,
    BLOCK_COMMENT_X,BLOCK_COMMENT3_Y,
    0,                              0,
    wxT("%C3"),           // Comment 3
    SET_UPPER_LIMIT | USE_TEXT_COLOR
};

Ki_WorkSheetData        WS_Comment4 =
{
    WS_TEXT,
    &WS_Comment3,
    BLOCK_COMMENT_X, BLOCK_COMMENT4_Y,
    0,                              0,
    wxT("%C4"),           // Comment 4
    SET_UPPER_LIMIT | USE_TEXT_COLOR
};


// horizontal segment above COMPANY NAME
Ki_WorkSheetData WS_Segm3 =
{
    WS_SEGMENT,
    &WS_Comment4,
    BLOCK_OX,  TEXTSIZE * 6,
    0,         TEXTSIZE * 6,
    NULL
};


// vertical segment of the left REV and SHEET
Ki_WorkSheetData WS_Segm4 =
{
    WS_SEGMENT,
    &WS_Segm3,
    BLOCK_REV_X + TEXTSIZE,TEXTSIZE * 4,
    BLOCK_REV_X + TEXTSIZE,            0,
    NULL
};


Ki_WorkSheetData WS_Segm5 =
{
    WS_SEGMENT,
    &WS_Segm4,
    BLOCK_OX,  TEXTSIZE * 2,
    0,         TEXTSIZE * 2,
    NULL
};


Ki_WorkSheetData WS_Segm6 =
{
    WS_SEGMENT,
    &WS_Segm5,
    BLOCK_OX,  TEXTSIZE * 4,
    0,         TEXTSIZE * 4,
    NULL
};


Ki_WorkSheetData WS_Segm7 =
{
    WS_SEGMENT,
    &WS_Segm6,
    BLOCK_OX - (TEXTSIZE * 11),TEXTSIZE * 4,
    BLOCK_OX - (TEXTSIZE * 11),TEXTSIZE * 2,
    NULL
};

#include <worksheet_shape_builder.h>

void WS_DRAW_ITEM_LIST::BuildWorkSheetGraphicList(
                       const wxString& aPaperFormat,
                       const wxString& aFileName,
                       const wxString& aSheetPathHumanReadable,
                       const TITLE_BLOCK& aTitleBlock,
                       EDA_COLOR_T aLineColor, EDA_COLOR_T aTextColor )
{
    wxSize              textsize( TEXTSIZE * m_milsToIu, TEXTSIZE * m_milsToIu );
    wxSize              size_ref( FRMREF_TXTSIZE * m_milsToIu,
                                  FRMREF_TXTSIZE * m_milsToIu );
    wxString            msg;

    m_titleBlock = &aTitleBlock,
    m_paperFormat = &aPaperFormat,
    m_fileName = &aFileName,
    m_sheetFullName = &aSheetPathHumanReadable;


    // Left top corner position
    wxPoint lt_corner;
    lt_corner.x = m_LTmargin.x;
    lt_corner.y = m_LTmargin.y;

    // Right bottom corner position
    wxPoint rb_corner;
    rb_corner.x = m_pageSize.x - m_RBmargin.x;
    rb_corner.y = m_pageSize.y - m_RBmargin.y;

    // Draw the border.
    int ii, jj, ipas, gxpas, gypas;

    wxPoint pos = lt_corner;
    wxPoint end = rb_corner;
    for( ii = 0; ii < 2; ii++ )
    {
        Append( new WS_DRAW_ITEM_RECT(
                    wxPoint( pos.x * m_milsToIu, pos.y * m_milsToIu ),
                    wxPoint( end.x * m_milsToIu, end.y * m_milsToIu ),
                    m_penSize, aLineColor ) );

        pos.x += GRID_REF_W;
        pos.y += GRID_REF_W;
        end.x -= GRID_REF_W;
        end.y -= GRID_REF_W;
    }

    ipas    = ( rb_corner.x - lt_corner.x ) / PAS_REF;
    gxpas   = ( rb_corner.x - lt_corner.x ) / ipas;

    for( ii = lt_corner.x + gxpas, jj = 1; ipas > 0; ii += gxpas, jj++, ipas-- )
    {
        msg.Printf( wxT( "%d" ), jj );

        if( ii < rb_corner.x - PAS_REF / 2 )
        {
            Append( new WS_DRAW_ITEM_LINE(
                        wxPoint( ii * m_milsToIu, lt_corner.y * m_milsToIu ),
                        wxPoint( ii * m_milsToIu, ( lt_corner.y + GRID_REF_W ) * m_milsToIu ),
                        m_penSize, aLineColor ) );
        }

        Append( new WS_DRAW_ITEM_TEXT( msg,
                                       wxPoint( ( ii - gxpas / 2 ) * m_milsToIu,
                                                ( lt_corner.y + GRID_REF_W / 2 ) * m_milsToIu ),
                                       size_ref, m_penSize, aLineColor ) );

        if( ii < rb_corner.x - PAS_REF / 2 )
        {
            Append( new WS_DRAW_ITEM_LINE(
                        wxPoint( ii * m_milsToIu, rb_corner.y * m_milsToIu ),
                        wxPoint( ii * m_milsToIu, (rb_corner.y - GRID_REF_W ) * m_milsToIu ),
                        m_penSize, aLineColor ) );
        }

        Append( new WS_DRAW_ITEM_TEXT( msg,
                                       wxPoint( ( ii - gxpas / 2 ) * m_milsToIu,
                                                ( rb_corner.y - GRID_REF_W / 2) * m_milsToIu ),
                                       size_ref, m_penSize, aLineColor ) );
    }

    ipas    = ( rb_corner.y - lt_corner.y ) / PAS_REF;
    gypas   = ( rb_corner.y - lt_corner.y ) / ipas;

    for( ii = lt_corner.y + gypas, jj = 0; ipas > 0; ii += gypas, jj++, ipas-- )
    {
        if( jj < 26 )
            msg.Printf( wxT( "%c" ), jj + 'A' );
        else // I hope 52 identifiers are enough...
            msg.Printf( wxT( "%c" ), 'a' + jj - 26 );

        if( ii < rb_corner.y - PAS_REF / 2 )
        {
            Append( new WS_DRAW_ITEM_LINE(
                        wxPoint( lt_corner.x * m_milsToIu, ii * m_milsToIu ),
                        wxPoint( ( lt_corner.x + GRID_REF_W ) * m_milsToIu, ii * m_milsToIu ),
                        m_penSize, aLineColor ) );
        }

        Append( new WS_DRAW_ITEM_TEXT( msg,
                                       wxPoint( ( lt_corner.x + GRID_REF_W / 2 ) * m_milsToIu,
                                                ( ii - gypas / 2 ) * m_milsToIu ),
                                       size_ref, m_penSize, aLineColor ) );

        if( ii < rb_corner.y - PAS_REF / 2 )
        {
            Append( new WS_DRAW_ITEM_LINE(
                        wxPoint( rb_corner.x * m_milsToIu, ii * m_milsToIu ),
                        wxPoint( ( rb_corner.x - GRID_REF_W ) * m_milsToIu, ii * m_milsToIu ),
                        m_penSize, aLineColor ) );
        }

        Append( new WS_DRAW_ITEM_TEXT( msg,
                                       wxPoint( ( rb_corner.x - GRID_REF_W / 2 ) * m_milsToIu,
                                                ( ii - gxpas / 2 ) * m_milsToIu ),
                                       size_ref, m_penSize, aLineColor ) );
    }

    int upperLimit = VARIABLE_BLOCK_START_POSITION;
    rb_corner.x -= GRID_REF_W;
    rb_corner.y -= GRID_REF_W;

    WS_DRAW_ITEM_TEXT* gtext;
    Ki_WorkSheetData*  WsItem;
    int pensize;
    bool bold;
    bool italic = false;
    EDA_COLOR_T color;

    for( WsItem = &WS_Segm7; WsItem != NULL; WsItem = WsItem->Pnext )
    {
        pos.x   = (rb_corner.x - WsItem->m_Posx) * m_milsToIu;
        pos.y   = (rb_corner.y - WsItem->m_Posy) * m_milsToIu;

        msg.Empty();

        if( WsItem->m_Type == WS_TEXT && WsItem->m_TextBase )
            msg = BuildFullText( WsItem->m_TextBase );

        switch( WsItem->m_Type )
        {
        case WS_TEXT:
            if( msg.IsEmpty() )
                break;
            bold = false;
            pensize = m_penSize;
            color = aLineColor;
            if( WsItem->m_Flags & USE_TEXT_COLOR )
                color = aTextColor;

            if( WsItem->m_Flags & USE_BOLD )
            {
                bold = true;
                pensize = GetPenSizeForBold( std::min( textsize.x, textsize.y ) );
            }
            Append( gtext = new WS_DRAW_ITEM_TEXT( msg, pos, textsize,
                                                   pensize, color, italic, bold ) );
            gtext->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );

            if( WsItem->m_Flags & SET_UPPER_LIMIT )
                upperLimit = std::max( upperLimit, WsItem->m_Posy + TEXTSIZE );
            break;

        case WS_UPPER_SEGMENT:

            if( upperLimit == 0 )
                break;

        case WS_LEFT_SEGMENT:
            WS_MostUpperLine.m_Posy = upperLimit;
            WS_MostUpperLine.m_Endy = upperLimit;
            WS_MostLeftLine.m_Posy  = upperLimit;
            pos.y = (rb_corner.y - WsItem->m_Posy) * m_milsToIu;

        case WS_SEGMENT:
            end.x  = rb_corner.x - WsItem->m_Endx;
            end.y  = rb_corner.y - WsItem->m_Endy;
            Append( new WS_DRAW_ITEM_LINE( pos,
                                           wxPoint( end.x * m_milsToIu, end.y * m_milsToIu ),
                                           m_penSize, aLineColor ) );
            break;
        }
    }
}
