/* Move marked items, at new position = old position + offset
 */
void MoveMarkedItems( MODULE* module, wxPoint offset )
{
    EDA_ITEM* item;

    if( module == NULL )
        return;

    if( module->Reference().IsSelected() )
        module->Reference().Move( offset );

    if( module->Value().IsSelected() )
        module->Value().Move( offset );

    D_PAD* pad = module->Pads();

    for( ; pad != NULL; pad = pad->Next() )
    {
        if( !pad->IsSelected() )
            continue;

        pad->SetPosition( pad->GetPosition() + offset );
        pad->SetPos0( pad->GetPos0() + offset );
    }

    item = module->GraphicalItems();

    for( ; item != NULL; item = item->Next() )
    {
        if( !item->IsSelected() )
            continue;

        switch( item->Type() )
        {
        case PCB_MODULE_TEXT_T:
            static_cast<TEXTE_MODULE*>( item )->Move( offset );
            break;

        case PCB_MODULE_EDGE_T:
        {
            EDGE_MODULE* em = (EDGE_MODULE*) item;
            em->SetStart( em->GetStart() + offset );
            em->SetEnd( em->GetEnd() + offset );
            em->SetStart0( em->GetStart0() + offset );
            em->SetEnd0( em->GetEnd0() + offset );
        }
        break;

        default:
            ;
        }
    }

    ClearMarkItems( module );
}
/* Move marked items, at new position = old position + offset
 */
void MoveMarkedItems( MODULE* module, wxPoint offset )
{
    EDA_ITEM* item;

    if( module == NULL )
        return;

    D_PAD* pad = module->Pads();

    for( ; pad != NULL; pad = pad->Next() )
    {
        if( !pad->IsSelected() )
            continue;

        pad->SetPosition( pad->GetPosition() + offset );
        pad->SetPos0( pad->GetPos0() + offset );
    }

    item = module->GraphicalItems();

    for( ; item != NULL; item = item->Next() )
    {
        if( !item->IsSelected() )
            continue;

        switch( item->Type() )
        {
        case PCB_MODULE_TEXT_T:
        {
            TEXTE_MODULE* tm = (TEXTE_MODULE*) item;
            tm->Offset( offset );
            tm->SetPos0( tm->GetPos0() + offset );
        }
        break;

        case PCB_MODULE_EDGE_T:
        {
            EDGE_MODULE* em = (EDGE_MODULE*) item;
            em->SetStart( em->GetStart() + offset );
            em->SetEnd( em->GetEnd() + offset );
            em->SetStart0( em->GetStart0() + offset );
            em->SetEnd0( em->GetEnd0() + offset );
        }
        break;

        default:
            ;
        }

        item->ClearFlags();
    }
}
/** Rotate marked items, refer to a rotation point at position offset
 * Note: because this function is used in global transform,
 * if force_all is true, all items will be rotated
 */
void RotateMarkedItems( MODULE* module, wxPoint offset, bool force_all )
{
#define ROTATE( z ) RotatePoint( (&z), offset, 900 )

    if( module == NULL )
        return;

    if( module->Reference().IsSelected() || force_all )
        module->Reference().Rotate( offset, 900 );

    if( module->Value().IsSelected() || force_all )
        module->Value().Rotate( offset, 900 );

    for( D_PAD* pad = module->Pads();  pad;  pad = pad->Next() )
    {
        if( !pad->IsSelected() && !force_all )
            continue;

        wxPoint pos = pad->GetPos0();
        ROTATE( pos );
        pad->SetPos0( pos );
        pad->SetOrientation( pad->GetOrientation() + 900 );

        pad->SetDrawCoord();
    }

    for( EDA_ITEM* item = module->GraphicalItems();  item;  item = item->Next() )
    {
        if( !item->IsSelected() && !force_all )
            continue;

        switch( item->Type() )
        {
        case PCB_MODULE_EDGE_T:
            ((EDGE_MODULE*) item)->Rotate( offset, 900 );
            break;

        case PCB_MODULE_TEXT_T:
            static_cast<TEXTE_MODULE*>( item )->Rotate( offset, 900 );
            break;

        default:
            break;
        }
    }

    ClearMarkItems( module );
}
/** Rotate marked items, refer to a rotation point at position offset
 * Note: because this function is used in global transform,
 * if force_all is true, all items will be rotated
 */
void RotateMarkedItems( MODULE* module, wxPoint offset, bool force_all )
{
#define ROTATE( z ) RotatePoint( (&z), offset, 900 )

    if( module == NULL )
        return;

    for( D_PAD* pad = module->Pads();  pad;  pad = pad->Next() )
    {
        if( !pad->IsSelected() && !force_all )
            continue;

        wxPoint pos = pad->GetPosition();
        ROTATE( pos );
        pad->SetPosition( pos );

        pad->SetPos0( pad->GetPosition() );
        pad->SetOrientation( pad->GetOrientation() + 900 );
    }

    for( EDA_ITEM* item = module->GraphicalItems();  item;  item = item->Next() )
    {
        if( !item->IsSelected() && !force_all)
            continue;

        switch( item->Type() )
        {
        case PCB_MODULE_EDGE_T:
        {
            EDGE_MODULE* em = (EDGE_MODULE*) item;

            wxPoint tmp = em->GetStart();
            ROTATE( tmp );
            em->SetStart( tmp );
            em->SetStart0( tmp );

            tmp = em->GetEnd();
            ROTATE( tmp );
            em->SetEnd( tmp );
            em->SetEnd0( tmp );
        }
        break;

        case PCB_MODULE_TEXT_T:
        {
            TEXTE_MODULE* tm = (TEXTE_MODULE*) item;
            wxPoint pos = tm->GetTextPosition();
            ROTATE( pos );
            tm->SetTextPosition( pos );
            tm->SetPos0( tm->GetTextPosition() );
            tm->SetOrientation( tm->GetOrientation() + 900 );
        }
        break;

        default:
            ;
        }

        item->ClearFlags();
    }
}
/** Mirror marked items, refer to a Vertical axis at position offset
 * Note: because this function is used in global transform,
 * if force_all is true, all items will be mirrored
 */
void MirrorMarkedItems( MODULE* module, wxPoint offset, bool force_all )
{
#define SETMIRROR( z ) (z) -= offset.x; (z) = -(z); (z) += offset.x;
    wxPoint     tmp;
    wxSize      tmpz;

    if( module == NULL )
        return;

    for( D_PAD* pad = module->Pads();  pad;  pad = pad->Next() )
    {
        // Skip pads not selected, i.e. not inside the block to mirror:
        if( !pad->IsSelected() && !force_all )
            continue;

        tmp = pad->GetPosition();
        SETMIRROR( tmp.x );
        pad->SetPosition( tmp );

        pad->SetX0( pad->GetPosition().x );

        tmp = pad->GetOffset();
        NEGATE( tmp.x );
        pad->SetOffset( tmp );

        tmpz = pad->GetDelta();
        NEGATE( tmpz.x );
        pad->SetDelta( tmpz );

        pad->SetOrientation( 1800 - pad->GetOrientation() );
    }

    for( EDA_ITEM* item = module->GraphicalItems();  item;  item = item->Next() )
    {
        // Skip items not selected, i.e. not inside the block to mirror:
        if( !item->IsSelected() && !force_all )
            continue;

        switch( item->Type() )
        {
        case PCB_MODULE_EDGE_T:
            {
                EDGE_MODULE* em = (EDGE_MODULE*) item;

                tmp = em->GetStart0();
                SETMIRROR( tmp.x );
                em->SetStart0( tmp );
                em->SetStartX( tmp.x );

                tmp = em->GetEnd0();
                SETMIRROR( tmp.x );
                em->SetEnd0( tmp );
                em->SetEndX( tmp.x );

                em->SetAngle( -em->GetAngle() );
            }
            break;

        case PCB_MODULE_TEXT_T:
            {
                TEXTE_MODULE* tm = (TEXTE_MODULE*) item;
                tmp = tm->GetTextPosition();
                SETMIRROR( tmp.x );
                tm->SetTextPosition( tmp );
                tmp.y = tm->GetPos0().y;
                tm->SetPos0( tmp );
            }
            break;

        default:
            break;
        }

        item->ClearFlags();
    }
}
void MoveMarkedItemsExactly( MODULE* module, const wxPoint& centre,
                             const wxPoint& translation,
                             double rotation, bool force_all )
{
    if( module == NULL )
        return;

    if( module->Reference().IsSelected() || force_all )
    {
        module->Reference().Rotate( centre, rotation );
        module->Reference().Move( translation );
    }

    if( module->Value().IsSelected() || force_all )
    {
        module->Value().Rotate( centre, rotation );
        module->Value().Move( translation );
    }

    D_PAD* pad = module->Pads();

    for( ; pad != NULL; pad = pad->Next() )
    {
        if( !pad->IsSelected() && !force_all )
            continue;

        // rotate about centre point,
        wxPoint newPos = pad->GetPosition();
        RotatePoint( &newPos, centre, rotation );

        // shift and update
        newPos += translation;
        pad->SetPosition( newPos );
        pad->SetPos0( newPos );

        // finally apply rotation to the pad itself
        pad->Rotate( newPos, rotation );
    }

    EDA_ITEM* item = module->GraphicalItems();

    for( ; item != NULL; item = item->Next() )
    {
        if( !item->IsSelected() && !force_all )
            continue;

        switch( item->Type() )
        {
        case PCB_MODULE_TEXT_T:
        {
            TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( item );

            text->Rotate( centre, rotation );
            text->Move( translation );
            break;
        }
        case PCB_MODULE_EDGE_T:
        {
            EDGE_MODULE* em = static_cast<EDGE_MODULE*>( item );
            em->Rotate( centre, rotation );
            em->Move( translation );
            break;
        }
        default:
            ;
        }
    }

    ClearMarkItems( module );
}
/** Mirror marked items, refer to a Vertical axis at position offset
 * Note: because this function is used in global transform,
 * if force_all is true, all items will be mirrored
 */
void MirrorMarkedItems( MODULE* module, wxPoint offset, bool force_all )
{
#define SETMIRROR( z ) (z) -= offset.x; (z) = -(z); (z) += offset.x;
    wxPoint     tmp;
    wxSize      tmpz;

    if( module == NULL )
        return;

    if( module->Reference().IsSelected() || force_all )
        module->Reference().Mirror( offset, false );

    if( module->Value().IsSelected() || force_all )
        module->Value().Mirror( offset, false );

    for( D_PAD* pad = module->Pads();  pad;  pad = pad->Next() )
    {
        // Skip pads not selected, i.e. not inside the block to mirror:
        if( !pad->IsSelected() && !force_all )
            continue;

        tmp = pad->GetPosition();
        SETMIRROR( tmp.x );
        pad->SetPosition( tmp );

        pad->SetX0( pad->GetPosition().x );

        tmp = pad->GetOffset();
        tmp.x = -tmp.x;
        pad->SetOffset( tmp );

        tmpz = pad->GetDelta();
        tmpz.x = -tmpz.x;
        pad->SetDelta( tmpz );

        pad->SetOrientation( 1800 - pad->GetOrientation() );
    }

    for( EDA_ITEM* item = module->GraphicalItems();  item;  item = item->Next() )
    {
        // Skip items not selected, i.e. not inside the block to mirror:
        if( !item->IsSelected() && !force_all )
            continue;

        switch( item->Type() )
        {
        case PCB_MODULE_EDGE_T:
            ((EDGE_MODULE*) item)->Mirror( offset, false );
            break;

        case PCB_MODULE_TEXT_T:
            static_cast<TEXTE_MODULE*>( item )->Mirror( offset, false );
            break;

        default:
            break;
        }
    }

    ClearMarkItems( module );
}