/********************************************/
/* Routines for managing on block commands. */
/* (Common section Eeschema / pcbnew ...    */
/********************************************/

#include "fctsys.h"
#include "gr_basic.h"
#include "wxstruct.h"
#include "common.h"
#include "macros.h"
#include "base_struct.h"
#include "class_base_screen.h"
#include "class_drawpanel.h"
#include "confirm.h"
#include "block_commande.h"


BLOCK_SELECTOR::BLOCK_SELECTOR() :
    EDA_BaseStruct( BLOCK_LOCATE_STRUCT_TYPE ),
    EDA_Rect()
{
    m_State   = STATE_NO_BLOCK; /* State (enum BlockState) of block. */
    m_Command = BLOCK_IDLE;     /* Type (enum CmdBlockType) of operation. */
    m_Color   = BROWN;
}


BLOCK_SELECTOR::~BLOCK_SELECTOR()
{
}


/*
 *  Print block command message (Block move, Block copy ...) in status bar
 */
void BLOCK_SELECTOR::SetMessageBlock( WinEDA_DrawFrame* frame )
{
    wxString msg;

    switch( m_Command )
    {
    case BLOCK_IDLE:
        break;

    case BLOCK_MOVE:                /* Move */
    case BLOCK_PRESELECT_MOVE:      /* Move with preselection list*/
        msg = _( "Block Move" );
        break;

    case BLOCK_DRAG:     /* Drag */
        msg = _( "Block Drag" );
        break;

    case BLOCK_COPY:     /* Copy */
        msg = _( "Block Copy" );
        break;

    case BLOCK_DELETE:     /* Delete */
        msg = _( "Block Delete" );
        break;

    case BLOCK_SAVE:     /* Save */
        msg = _( "Block Save" );
        break;

    case BLOCK_PASTE:
        msg = _( "Block Paste" );
        break;

    case BLOCK_ZOOM:     /* Window Zoom */
        msg = _( "Win Zoom" );
        break;

    case BLOCK_ROTATE:     /* Rotate 90 deg */
        msg = _( "Block Rotate" );
        break;

    case BLOCK_FLIP:     /* Flip */
        msg = _( "Block Flip" );
        break;

    case BLOCK_MIRROR_X:
    case BLOCK_MIRROR_Y:     /* mirror */
        msg = _( "Block Mirror" );
        break;

    case BLOCK_ABORT:
        break;

    default:
        msg = wxT( "????" );
        break;
    }

    frame->DisplayToolMsg( msg );
}


void BLOCK_SELECTOR::Draw( WinEDA_DrawPanel* aPanel, wxDC* aDC,
                           const wxPoint& aOffset,
                           int aDrawMode,
                           int aColor )
{

    int w = aPanel->GetScreen()->Scale( GetWidth() );
    int h = aPanel->GetScreen()->Scale( GetHeight() );

    GRSetDrawMode( aDC, aDrawMode );
    if(  w == 0 || h == 0 )
        GRLine( &aPanel->m_ClipBox, aDC, GetX() + aOffset.x, GetY() + aOffset.y,
                GetRight() + aOffset.x, GetBottom() + aOffset.y, 0, aColor );
    else
        GRRect( &aPanel->m_ClipBox, aDC, GetX() + aOffset.x, GetY() + aOffset.y,
                GetRight() + aOffset.x, GetBottom() + aOffset.y, 0, aColor );
}


/** function InitData
 *  Init the initial values of a BLOCK_SELECTOR, before starting a block command
 */
void BLOCK_SELECTOR::InitData( WinEDA_DrawPanel* aPanel,
                               const wxPoint&    startpos )
{
    m_State = STATE_BLOCK_INIT;
    SetOrigin( startpos );
    SetSize( wxSize( 0, 0 ) );
    m_ItemsSelection.ClearItemsList();
    aPanel->ManageCurseur = DrawAndSizingBlockOutlines;
    aPanel->ForceCloseManageCurseur = AbortBlockCurrentCommand;
}


/** Function ClearItemsList
 * delete only the list of EDA_BaseStruct * pointers, NOT the pointed data
 * itself
 */
void BLOCK_SELECTOR::ClearItemsList()
{
    m_ItemsSelection.ClearItemsList();
}

/** Function ClearListAndDeleteItems
 * delete only the list of EDA_BaseStruct * pointers, AND the data pinted
 * by m_Item
 */
void BLOCK_SELECTOR::ClearListAndDeleteItems()
{
     m_ItemsSelection.ClearListAndDeleteItems();
}

/** Function PushItem
 * Add aItem to the list of items
 * @param aItem = an ITEM_PICKER to add to the list
 */
void BLOCK_SELECTOR::PushItem( ITEM_PICKER& aItem )
{
    m_ItemsSelection.PushItem(  aItem );
}



/*  First command block function:
 *  Init the Block infos: command type, initial position, and other variables..
 */
bool WinEDA_DrawFrame::HandleBlockBegin( wxDC* DC, int key,
                                         const wxPoint& startpos )
{
    BLOCK_SELECTOR* Block = &GetBaseScreen()->m_BlockLocate;

    if( ( Block->m_Command != BLOCK_IDLE )
       || ( Block->m_State != STATE_NO_BLOCK ) )
        return FALSE;

    Block->m_Flags   = 0;
    Block->m_Command = (CmdBlockType) ReturnBlockCommand( key );
    if( Block->m_Command == 0 )
        return FALSE;

    switch( Block->m_Command )
    {
    case BLOCK_IDLE:
        break;

    case BLOCK_MOVE:                /* Move */
    case BLOCK_DRAG:                /* Drag */
    case BLOCK_COPY:                /* Copy */
    case BLOCK_DELETE:              /* Delete */
    case BLOCK_SAVE:                /* Save */
    case BLOCK_ROTATE:              /* Rotate 90 deg */
    case BLOCK_FLIP:                /* Flip */
    case BLOCK_ZOOM:                /* Window Zoom */
    case BLOCK_MIRROR_X:
    case BLOCK_MIRROR_Y:            /* mirror */
    case BLOCK_PRESELECT_MOVE:      /* Move with preselection list*/
        Block->InitData( DrawPanel, startpos );
        break;

    case BLOCK_PASTE:
        Block->InitData( DrawPanel, startpos );
        Block->m_BlockLastCursorPosition.x = 0;
        Block->m_BlockLastCursorPosition.y = 0;
        InitBlockPasteInfos();
        if( Block->m_ItemsSelection.GetCount() == 0 )      /* No data to paste */
        {
            DisplayError( this, wxT( "No Block to paste" ), 20 );
            GetBaseScreen()->m_BlockLocate.m_Command = BLOCK_IDLE;
            DrawPanel->ManageCurseur = NULL;
            return TRUE;
        }
        if( DrawPanel->ManageCurseur == NULL )
        {
            Block->m_ItemsSelection.ClearItemsList();
            DisplayError( this,
                          wxT( "WinEDA_DrawFrame::HandleBlockBegin() Err: ManageCurseur NULL" ) );
            return TRUE;
        }
        Block->m_State = STATE_BLOCK_MOVE;
        DrawPanel->ManageCurseur( DrawPanel, DC, FALSE );
        break;

    default:
    {
        wxString msg;
        msg << wxT( "WinEDA_DrawFrame::HandleBlockBegin() error: Unknown command " ) <<
        Block->m_Command;
        DisplayError( this, msg );
    }
    break;
    }

    Block->SetMessageBlock( this );
    return TRUE;
}


/* Redraw the outlines of the block which shows the search area for block
 * commands
 *  The first point of the rectangle showing the area is initialised
 *  by Initm_BlockLocateDatas().
 *  The other point of the rectangle is the mouse cursor
 */
void DrawAndSizingBlockOutlines( WinEDA_DrawPanel* panel, wxDC* DC, bool erase )
{
    BLOCK_SELECTOR* PtBlock;

    PtBlock = &panel->GetScreen()->m_BlockLocate;

    PtBlock->m_MoveVector = wxPoint( 0, 0 );

    if( erase )
        PtBlock->Draw( panel, DC, wxPoint( 0, 0 ), g_XorMode, PtBlock->m_Color );

    PtBlock->m_BlockLastCursorPosition = panel->GetScreen()->m_Curseur;
    PtBlock->SetEnd( panel->GetScreen()->m_Curseur );

    PtBlock->Draw( panel, DC, wxPoint( 0, 0 ), g_XorMode, PtBlock->m_Color );

    if( PtBlock->m_State == STATE_BLOCK_INIT )
    {
        if( PtBlock->GetWidth() || PtBlock->GetHeight() )
            /* 2nd point exists: the rectangle is not surface anywhere */
            PtBlock->m_State = STATE_BLOCK_END;
    }
}


/*
 *  Cancel Current block operation.
 */
void AbortBlockCurrentCommand( WinEDA_DrawPanel* Panel, wxDC* DC )
{
    BASE_SCREEN* screen = Panel->GetScreen();

    if( Panel->ManageCurseur )                     /* Erase current drawing
                                                    * on screen */
    {
        Panel->ManageCurseur( Panel, DC, FALSE );  /* Clear block outline. */
        Panel->ManageCurseur = NULL;
        Panel->ForceCloseManageCurseur = NULL;
        screen->SetCurItem( NULL );

        /* Delete the picked wrapper if this is a picked list. */
        if( screen->m_BlockLocate.m_Command != BLOCK_PASTE )
            screen->m_BlockLocate.ClearItemsList();
    }

    screen->m_BlockLocate.m_Flags = 0;
    screen->m_BlockLocate.m_State = STATE_NO_BLOCK;

    screen->m_BlockLocate.m_Command = BLOCK_ABORT;
    Panel->GetParent()->HandleBlockEnd( DC );

    screen->m_BlockLocate.m_Command = BLOCK_IDLE;
    Panel->GetParent()->DisplayToolMsg( wxEmptyString );
}
