/*
 * This program source code file is part of KiCad, a free EDA CAD application.
 *
 * Copyright (C) 2007 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
 * Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
 * Copyright (C) 1992-2011 KiCad Developers, see AUTHORS.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
 */

/**
 * @file zones_by_polygon.cpp
 */

#include "fctsys.h"
#include "appl_wxstruct.h"
#include "class_drawpanel.h"
#include "confirm.h"
#include "wxPcbStruct.h"

#include "class_board.h"
#include "class_zone.h"

#include "pcbnew.h"
#include "zones.h"
#include "pcbnew_id.h"
#include "protos.h"
#include "zones_functions_for_undo_redo.h"
#include "drc_stuff.h"

bool s_Verbose = false;       // false if zone outline diags must not be shown

// Outline creation:
static void Abort_Zone_Create_Outline( EDA_DRAW_PANEL* Panel, wxDC* DC );
static void Show_New_Edge_While_Move_Mouse( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
                                            const wxPoint& aPosition, bool aErase );

// Corner moving
static void Abort_Zone_Move_Corner_Or_Outlines( EDA_DRAW_PANEL* Panel, wxDC* DC );
static void Show_Zone_Corner_Or_Outline_While_Move_Mouse( EDA_DRAW_PANEL* aPanel,
                                                          wxDC*           aDC,
                                                          const wxPoint&  aPosition,
                                                          bool            aErase );

/* Local variables */
static wxPoint         s_CornerInitialPosition;     // Used to abort a move corner command
static bool            s_CornerIsNew;               // Used to abort a move corner command (if it is a new corner, it must be deleted)
static bool            s_AddCutoutToCurrentZone;    // if true, the next outline will be added to s_CurrentZone
static ZONE_CONTAINER* s_CurrentZone;               // if != NULL, these ZONE_CONTAINER params will be used for the next zone
static wxPoint         s_CursorLastPosition;        // in move zone outline, last cursor position. Used to calculate the move vector
static PICKED_ITEMS_LIST s_PickedList;              // a picked list to save zones for undo/redo command
static PICKED_ITEMS_LIST _AuxiliaryList;            // a picked list to store zones that are deleted or added when combined

#include "dialog_copper_zones.h"


void PCB_EDIT_FRAME::Add_Similar_Zone( wxDC* DC, ZONE_CONTAINER* zone_container )
{
    if ( zone_container == NULL )
        return;

    s_AddCutoutToCurrentZone = false;
    s_CurrentZone = zone_container;

    /* set zones setup to the current zone */
    g_Zone_Default_Setting.ImportSetting( *zone_container );

    // Use the general event handle to set others params (like toolbar) */
    wxCommandEvent evt;
    evt.SetId( ID_PCB_ZONES_BUTT );
    OnSelectTool( evt );
}


void PCB_EDIT_FRAME::Add_Zone_Cutout( wxDC* DC, ZONE_CONTAINER* zone_container )
{
    if ( zone_container == NULL )
        return;

    s_AddCutoutToCurrentZone = true;
    s_CurrentZone = zone_container;

    /* set zones setup to the current zone */
    g_Zone_Default_Setting.ImportSetting( *zone_container );

    // Use the general event handle to set others params (like toolbar) */
    wxCommandEvent evt;
    evt.SetId( ID_PCB_ZONES_BUTT );
    OnSelectTool( evt );
}


int PCB_EDIT_FRAME::Delete_LastCreatedCorner( wxDC* DC )
{
    ZONE_CONTAINER* zone = GetBoard()->m_CurrentZoneContour;

    if( zone == NULL )
        return 0;

    if( zone->GetNumCorners() == 0 )
        return 0;

    zone->DrawWhileCreateOutline( m_canvas, DC, GR_XOR );

    if( zone->GetNumCorners() > 2 )
    {
        zone->m_Poly->DeleteCorner( zone->GetNumCorners() - 1 );

        if( m_canvas->IsMouseCaptured() )
            m_canvas->CallMouseCapture( DC, wxDefaultPosition, false );
    }
    else
    {
        m_canvas->SetMouseCapture( NULL, NULL );
        SetCurItem( NULL );
        zone->RemoveAllContours();
        zone->ClearFlags();
    }

    return zone->GetNumCorners();
}


/**
 * Function Abort_Zone_Create_Outline
 * cancels the Begin_Zone command if at least one EDGE_ZONE was created.
 */
static void Abort_Zone_Create_Outline( EDA_DRAW_PANEL* Panel, wxDC* DC )
{
    PCB_EDIT_FRAME* pcbframe = (PCB_EDIT_FRAME*) Panel->GetParent();
    ZONE_CONTAINER* zone = pcbframe->GetBoard()->m_CurrentZoneContour;

    if( zone )
    {
        zone->DrawWhileCreateOutline( Panel, DC, GR_XOR );
        zone->ClearFlags();
        zone->RemoveAllContours();
    }

    pcbframe->SetCurItem( NULL );
    s_AddCutoutToCurrentZone = false;
    s_CurrentZone = NULL;
    Panel->SetMouseCapture( NULL, NULL );
}


void PCB_EDIT_FRAME::Start_Move_Zone_Corner( wxDC* DC, ZONE_CONTAINER* zone_container,
                                             int corner_id, bool IsNewCorner )
{
    if( zone_container->IsOnCopperLayer() ) /* Show the Net */
    {
        if( GetBoard()->IsHighLightNetON() && DC )
        {
            HighLight( DC );  // Remove old highlight selection
        }

        g_Zone_Default_Setting.m_NetcodeSelection = zone_container->GetNet();
        GetBoard()->SetHighLightNet( zone_container->GetNet() );

        if( DC )
            HighLight( DC );
    }


    // Prepare copy of old zones, for undo/redo.
    // if the corner is new, remove it from list, save and insert it in list
    int cx = zone_container->m_Poly->GetX( corner_id );
    int cy = zone_container->m_Poly->GetY( corner_id );

    if ( IsNewCorner )
        zone_container->m_Poly->DeleteCorner( corner_id );

    _AuxiliaryList.ClearListAndDeleteItems();
    s_PickedList.ClearListAndDeleteItems();

    SaveCopyOfZones( s_PickedList, GetBoard(), zone_container->GetNet(),
                     zone_container->GetLayer() );

    if ( IsNewCorner )
        zone_container->m_Poly->InsertCorner(corner_id-1, cx, cy );

    zone_container->SetFlags( IN_EDIT );
    m_canvas->SetMouseCapture( Show_Zone_Corner_Or_Outline_While_Move_Mouse,
                                Abort_Zone_Move_Corner_Or_Outlines );
    s_CornerInitialPosition = zone_container->GetCornerPosition( corner_id );
    s_CornerIsNew = IsNewCorner;
    s_AddCutoutToCurrentZone = false;
    s_CurrentZone = NULL;
}


void PCB_EDIT_FRAME::Start_Move_Zone_Drag_Outline_Edge( wxDC*           DC,
                                                        ZONE_CONTAINER* zone_container,
                                                        int             corner_id )
{
    zone_container->SetFlags( IS_DRAGGED );
    zone_container->m_CornerSelection = corner_id;
    m_canvas->SetMouseCapture( Show_Zone_Corner_Or_Outline_While_Move_Mouse,
                                Abort_Zone_Move_Corner_Or_Outlines );
    s_CursorLastPosition     = s_CornerInitialPosition = GetScreen()->GetCrossHairPosition();
    s_AddCutoutToCurrentZone = false;
    s_CurrentZone = NULL;

    s_PickedList.ClearListAndDeleteItems();
    _AuxiliaryList.ClearListAndDeleteItems();
    SaveCopyOfZones( s_PickedList, GetBoard(), zone_container->GetNet(),
                     zone_container->GetLayer() );
}


void PCB_EDIT_FRAME::Start_Move_Zone_Outlines( wxDC* DC, ZONE_CONTAINER* zone_container )
{
    /* Show the Net */
    if( zone_container->IsOnCopperLayer() ) /* Show the Net */
    {
        if( GetBoard()->IsHighLightNetON() )
        {
            HighLight( DC );  // Remove old highlight selection
        }

        g_Zone_Default_Setting.m_NetcodeSelection = zone_container->GetNet();
        GetBoard()->SetHighLightNet( zone_container->GetNet() );
        HighLight( DC );
    }

    s_PickedList.ClearListAndDeleteItems();
    _AuxiliaryList.ClearListAndDeleteItems();
    SaveCopyOfZones( s_PickedList, GetBoard(), zone_container->GetNet(),
                     zone_container->GetLayer() );

    zone_container->SetFlags( IS_MOVED );
    m_canvas->SetMouseCapture( Show_Zone_Corner_Or_Outline_While_Move_Mouse,
                                Abort_Zone_Move_Corner_Or_Outlines );
    s_CursorLastPosition = s_CornerInitialPosition = GetScreen()->GetCrossHairPosition();
    s_CornerIsNew = false;
    s_AddCutoutToCurrentZone = false;
    s_CurrentZone = NULL;
}


void PCB_EDIT_FRAME::End_Move_Zone_Corner_Or_Outlines( wxDC* DC, ZONE_CONTAINER* zone_container )
{
    zone_container->ClearFlags();
    m_canvas->SetMouseCapture( NULL, NULL );

    if( DC )
        zone_container->Draw( m_canvas, DC, GR_OR );

    OnModify();
    s_AddCutoutToCurrentZone = false;
    s_CurrentZone = NULL;

    SetCurItem( NULL );       // This outline can be deleted when merging outlines

    /* Combine zones if possible */
    wxBusyCursor dummy;
    GetBoard()->AreaPolygonModified( &_AuxiliaryList, zone_container, true, s_Verbose );
    m_canvas->Refresh();


    int ii = GetBoard()->GetAreaIndex( zone_container );     // test if zone_container exists

    if( ii < 0 )
        zone_container = NULL;                          // was removed by combining zones

    UpdateCopyOfZonesList( s_PickedList, _AuxiliaryList, GetBoard() );
    SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED);
    s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items

    int error_count = GetBoard()->Test_Drc_Areas_Outlines_To_Areas_Outlines( zone_container, true );

    if( error_count )
    {
        DisplayError( this, _( "Area: DRC outline error" ) );
    }
}


void PCB_EDIT_FRAME::Remove_Zone_Corner( wxDC* DC, ZONE_CONTAINER* zone_container )
{
    OnModify();

    if( zone_container->m_Poly->GetNumCorners() <= 3 )
    {
        m_canvas->RefreshDrawingRect( zone_container->GetBoundingBox() );

        if( DC )
        {  // Remove the full zone because this is no more an area
            zone_container->UnFill();
            zone_container->DrawFilledArea( m_canvas, DC, GR_XOR );
        }

        GetBoard()->Delete( zone_container );
        return;
    }

    int layer = zone_container->GetLayer();

    if( DC )
    {
        GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_XOR, layer );
        GetBoard()->RedrawFilledAreas( m_canvas, DC, GR_XOR, layer );
    }

    _AuxiliaryList.ClearListAndDeleteItems();
    s_PickedList. ClearListAndDeleteItems();
    SaveCopyOfZones( s_PickedList, GetBoard(), zone_container->GetNet(),
                     zone_container->GetLayer() );
    zone_container->m_Poly->DeleteCorner( zone_container->m_CornerSelection );

    // modify zones outlines according to the new zone_container shape
    GetBoard()->AreaPolygonModified( &_AuxiliaryList, zone_container, true, s_Verbose );

    if( DC )
    {
        GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_OR, layer );
        GetBoard()->RedrawFilledAreas( m_canvas, DC, GR_OR, layer );
    }

    UpdateCopyOfZonesList( s_PickedList, _AuxiliaryList, GetBoard() );
    SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED);
    s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items

    int ii = GetBoard()->GetAreaIndex( zone_container );     // test if zone_container exists

    if( ii < 0 )
        zone_container = NULL;   // zone_container does not exist anymore, after combining zones

    int error_count = GetBoard()->Test_Drc_Areas_Outlines_To_Areas_Outlines( zone_container, true );

    if( error_count )
    {
        DisplayError( this, _( "Area: DRC outline error" ) );
    }
}


/**
 * Function Abort_Zone_Move_Corner_Or_Outlines
 * cancels the Begin_Zone state if at least one EDGE_ZONE has been created.
 */
void Abort_Zone_Move_Corner_Or_Outlines( EDA_DRAW_PANEL* Panel, wxDC* DC )
{
    PCB_EDIT_FRAME* pcbframe = (PCB_EDIT_FRAME*) Panel->GetParent();
    ZONE_CONTAINER*  zone_container = (ZONE_CONTAINER*) pcbframe->GetCurItem();

    if( zone_container->IsMoving() )
    {
        wxPoint offset;
        offset = s_CornerInitialPosition - s_CursorLastPosition;
        zone_container->Move( offset );
    }
    else if( zone_container->IsDragging() )
    {
        wxPoint offset;
        offset = s_CornerInitialPosition - s_CursorLastPosition;
        zone_container->MoveEdge( offset );
    }
    else
    {
        if( s_CornerIsNew )
        {
            zone_container->m_Poly->DeleteCorner( zone_container->m_CornerSelection );
        }
        else
        {
            wxPoint pos = s_CornerInitialPosition;
            zone_container->m_Poly->MoveCorner( zone_container->m_CornerSelection, pos.x, pos.y );
        }
    }

    Panel->SetMouseCapture( NULL, NULL );
    _AuxiliaryList.ClearListAndDeleteItems();
    s_PickedList. ClearListAndDeleteItems();
    Panel->Refresh();

    pcbframe->SetCurItem( NULL );
    zone_container->ClearFlags();
    s_AddCutoutToCurrentZone = false;
    s_CurrentZone = NULL;
}


/* Redraws the zone outline when moving a corner according to the cursor position
 */
void Show_Zone_Corner_Or_Outline_While_Move_Mouse( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
                                                   const wxPoint& aPosition, bool aErase )
{
    PCB_EDIT_FRAME* pcbframe = (PCB_EDIT_FRAME*) aPanel->GetParent();
    ZONE_CONTAINER* zone = (ZONE_CONTAINER*) pcbframe->GetCurItem();

    if( aErase )    /* Undraw edge in old position*/
    {
        zone->Draw( aPanel, aDC, GR_XOR );
    }

    wxPoint          pos = pcbframe->GetScreen()->GetCrossHairPosition();

    if( zone->IsMoving() )
    {
        wxPoint offset;
        offset = pos - s_CursorLastPosition;
        zone->Move( offset );
        s_CursorLastPosition = pos;
    }
    else if( zone->IsDragging() )
    {
        wxPoint offset;
        offset = pos - s_CursorLastPosition;
        zone->MoveEdge( offset );
        s_CursorLastPosition = pos;
    }
    else
    {
        zone->m_Poly->MoveCorner( zone->m_CornerSelection, pos.x, pos.y );
    }

    zone->Draw( aPanel, aDC, GR_XOR );
}



int PCB_EDIT_FRAME::Begin_Zone( wxDC* DC )
{
    // verify if s_CurrentZone exists (could be deleted since last selection) :
    int ii;

    for( ii = 0; ii < GetBoard()->GetAreaCount(); ii++ )
    {
        if( s_CurrentZone == GetBoard()->GetArea( ii ) )
            break;
    }

    if( ii >= GetBoard()->GetAreaCount() ) // Not found: could be deleted since last selection
    {
        s_AddCutoutToCurrentZone = false;
        s_CurrentZone = NULL;
    }

    // If no zone contour in progress, a new zone is being created:
    if( GetBoard()->m_CurrentZoneContour == NULL )
        GetBoard()->m_CurrentZoneContour = new ZONE_CONTAINER( GetBoard() );

    ZONE_CONTAINER* zone = GetBoard()->m_CurrentZoneContour;

    if( zone->GetNumCorners() == 0 )    // Start a new contour: init zone params (net, layer ...)
    {
        if( s_CurrentZone == NULL )     // A new outline is created, from scratch
        {
            int diag;
            // Init zone params to reasonable values
            zone->SetLayer( getActiveLayer() );

            // Prompt user for parameters:
            m_canvas->SetIgnoreMouseEvents( true );

            if( zone->IsOnCopperLayer() )
            {   // Put a zone on a copper layer
                if ( GetBoard()->GetHighLightNetCode() > 0 )
                {
                    g_Zone_Default_Setting.m_NetcodeSelection = GetBoard()->GetHighLightNetCode();

                    zone->SetNet( g_Zone_Default_Setting.m_NetcodeSelection );
                    zone->SetNetNameFromNetCode( );
                }

                wxGetApp().GetSettings()->Read( ZONE_THERMAL_RELIEF_GAP_STRING_KEY,
                                                &g_Zone_Default_Setting.m_ThermalReliefGap );
                wxGetApp().GetSettings()->Read( ZONE_THERMAL_RELIEF_COPPER_WIDTH_STRING_KEY,
                                                &g_Zone_Default_Setting.m_ThermalReliefCopperBridge );

                g_Zone_Default_Setting.m_CurrentZone_Layer = zone->GetLayer();
                DIALOG_COPPER_ZONE* frame = new DIALOG_COPPER_ZONE( this, &g_Zone_Default_Setting  );
                diag = frame->ShowModal();
                frame->Destroy();
            }
            else   // Put a zone on a non copper layer (technical layer)
            {
                diag = InstallDialogNonCopperZonesEditor( zone );
                g_Zone_Default_Setting.m_NetcodeSelection = 0;     // No net for non copper zones
            }

            m_canvas->MoveCursorToCrossHair();
            m_canvas->SetIgnoreMouseEvents( false );

            if( diag ==  ZONE_ABORT )
                return 0;

            // Switch active layer to the selected zone layer
            setActiveLayer( g_Zone_Default_Setting.m_CurrentZone_Layer );
        }
        else  // Start a new contour: init zone params (net and layer) from an existing
        {     // zone (add cutout or similar zone)
            g_Zone_Default_Setting.m_CurrentZone_Layer = s_CurrentZone->GetLayer();
            setActiveLayer( s_CurrentZone->GetLayer() );
            g_Zone_Default_Setting.ImportSetting( * s_CurrentZone);
        }

        /* Show the Net for zones on copper layers */
        if( g_Zone_Default_Setting.m_CurrentZone_Layer  < FIRST_NO_COPPER_LAYER )
        {
            if( s_CurrentZone )
                g_Zone_Default_Setting.m_NetcodeSelection = s_CurrentZone->GetNet();

            if( GetBoard()->IsHighLightNetON() )
            {
                HighLight( DC ); // Remove old highlight selection
            }

            GetBoard()->SetHighLightNet( g_Zone_Default_Setting.m_NetcodeSelection );
            HighLight( DC );
        }

        if( !s_AddCutoutToCurrentZone )
            s_CurrentZone = NULL; // the zone is used only once ("add similar zone" command)
    }

    // if first segment
    if(  zone->GetNumCorners() == 0 )
    {
        zone->SetFlags( IS_NEW );
        zone->SetTimeStamp( GetNewTimeStamp() );
        g_Zone_Default_Setting.ExportSetting( *zone );
        zone->m_Poly->Start( g_Zone_Default_Setting.m_CurrentZone_Layer,
                             GetScreen()->GetCrossHairPosition().x,
                             GetScreen()->GetCrossHairPosition().y,
                             zone->GetHatchStyle() );
        zone->AppendCorner( GetScreen()->GetCrossHairPosition() );

        if( Drc_On && (m_drc->Drc( zone, 0 ) == BAD_DRC) && zone->IsOnCopperLayer() )
        {
            zone->ClearFlags();
            zone->RemoveAllContours();

            // use the form of SetCurItem() which does not write to the msg panel,
            // SCREEN::SetCurItem(), so the DRC error remains on screen.
            // PCB_EDIT_FRAME::SetCurItem() calls DisplayInfo().
            GetScreen()->SetCurItem( NULL );
            DisplayError( this,
                          _( "DRC error: this start point is inside or too close an other area" ) );
            return 0;
        }

        SetCurItem( zone );
        m_canvas->SetMouseCapture( Show_New_Edge_While_Move_Mouse, Abort_Zone_Create_Outline );
    }
    else    // edge in progress:
    {
        ii = zone->GetNumCorners() - 1;

        /* edge in progress : the current corner coordinate was set by Show_New_Edge_While_Move_Mouse */
        if( zone->GetCornerPosition( ii - 1 ) != zone->GetCornerPosition( ii ) )
        {
            if( !Drc_On || !zone->IsOnCopperLayer() || ( m_drc->Drc( zone, ii - 1 ) == OK_DRC ) )
            {   // Ok, we can add a new corner
                zone->AppendCorner( GetScreen()->GetCrossHairPosition() );
                SetCurItem( zone );     // calls DisplayInfo().
            }
        }
    }

    return zone->GetNumCorners();
}


bool PCB_EDIT_FRAME::End_Zone( wxDC* DC )
{
    ZONE_CONTAINER* zone = GetBoard()->m_CurrentZoneContour;

    if( zone == NULL )
        return true;

    // Validate the current outline:
    if( zone->GetNumCorners() <= 2 )   // An outline must have 3 corners or more
    {
        Abort_Zone_Create_Outline( m_canvas, DC );
        return true;
    }

    // Validate the current edge:
    int icorner = zone->GetNumCorners() - 1;
    if( zone->IsOnCopperLayer() )
    {
        if( Drc_On && m_drc->Drc( zone, icorner - 1 ) == BAD_DRC )  // we can't validate last edge
            return false;

        if( Drc_On && m_drc->Drc( zone, icorner ) == BAD_DRC )      // we can't validate the closing edge
        {
            DisplayError( this,
                          _( "DRC error: closing this area creates a drc error with an other area" ) );
            m_canvas->MoveCursorToCrossHair();
            return false;
        }
    }

    zone->ClearFlags();

    zone->DrawWhileCreateOutline( m_canvas, DC, GR_XOR );

    m_canvas->SetMouseCapture( NULL, NULL );

    // Undraw old drawings, because they can have important changes
    int layer = zone->GetLayer();
    GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_XOR, layer );
    GetBoard()->RedrawFilledAreas( m_canvas, DC, GR_XOR, layer );

    // Save initial zones configuration, for undo/redo, before adding new zone
    _AuxiliaryList.ClearListAndDeleteItems();
    s_PickedList.ClearListAndDeleteItems();
    SaveCopyOfZones(s_PickedList, GetBoard(), zone->GetNet(), zone->GetLayer() );

    /* Put new zone in list */
    if( s_CurrentZone == NULL )
    {
        zone->m_Poly->Close(); // Close the current corner list
        GetBoard()->Add( zone );
        GetBoard()->m_CurrentZoneContour = NULL;
        // Add this zone in picked list, as new item
        ITEM_PICKER picker( zone, UR_NEW );
        s_PickedList.PushItem( picker );
    }
    else    // Append this outline as a cutout to an existing zone
    {
        for( int ii = 0; ii < zone->GetNumCorners(); ii++ )
        {
            s_CurrentZone->AppendCorner( zone->GetCornerPosition( ii ) );
        }

        s_CurrentZone->m_Poly->Close(); // Close the current corner list
        zone->RemoveAllContours();      // All corners are copied in s_CurrentZone. Free corner list.
        zone = s_CurrentZone;
    }

    s_AddCutoutToCurrentZone = false;
    s_CurrentZone = NULL;

    GetScreen()->SetCurItem( NULL );       // This outline can be deleted when merging outlines

    // Combine zones if possible :
    GetBoard()->AreaPolygonModified( &_AuxiliaryList, zone, true, s_Verbose );

    // Redraw the real edge zone :
    GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_OR, layer );
    GetBoard()->RedrawFilledAreas( m_canvas, DC, GR_OR, layer );

    int ii = GetBoard()->GetAreaIndex( zone );   // test if zone_container exists

    if( ii < 0 )
        zone = NULL;                        // was removed by combining zones

    int error_count = GetBoard()->Test_Drc_Areas_Outlines_To_Areas_Outlines( zone, true );

    if( error_count )
    {
        DisplayError( this, _( "Area: DRC outline error" ) );
    }

    UpdateCopyOfZonesList( s_PickedList, _AuxiliaryList, GetBoard() );
    SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED);
    s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items

    OnModify();
    return true;
}


/* Redraws the zone outlines when moving mouse
 */
static void Show_New_Edge_While_Move_Mouse( EDA_DRAW_PANEL* aPanel, wxDC* aDC,
                                            const wxPoint& aPosition, bool aErase )
{
    PCB_EDIT_FRAME* pcbframe = (PCB_EDIT_FRAME*) aPanel->GetParent();
    wxPoint         c_pos    = pcbframe->GetScreen()->GetCrossHairPosition();
    ZONE_CONTAINER* zone = pcbframe->GetBoard()->m_CurrentZoneContour;

    if( zone == NULL )
        return;

    int icorner = zone->GetNumCorners() - 1;

    if ( icorner < 1 )
        return;     // We must have 2 (or more) corners

    if( aErase )    /* Undraw edge in old position*/
    {
        zone->DrawWhileCreateOutline( aPanel, aDC );
    }

    /* Redraw the current edge in its new position */
    if( g_Zone_45_Only )
    {
        // calculate the new position as allowed
        wxPoint StartPoint = zone->GetCornerPosition( icorner - 1 );
        CalculateSegmentEndPoint( c_pos, StartPoint.x, StartPoint.y, &c_pos.x, &c_pos.y );
    }

    zone->SetCornerPosition( icorner, c_pos );

    zone->DrawWhileCreateOutline( aPanel, aDC );
}


void PCB_EDIT_FRAME::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* zone_container )
{
    int diag;
    m_canvas->SetIgnoreMouseEvents( true );

    /* Save initial zones configuration, for undo/redo, before adding new zone
     * note the net name and the layer can be changed, so we must save all zones
     */
    _AuxiliaryList.ClearListAndDeleteItems();
    s_PickedList.ClearListAndDeleteItems();
    SaveCopyOfZones(s_PickedList, GetBoard(), -1, -1 );

    if( zone_container->GetLayer() < FIRST_NO_COPPER_LAYER )
    {   // edit a zone on a copper layer
        g_Zone_Default_Setting.ImportSetting(*zone_container);
        DIALOG_COPPER_ZONE* frame = new DIALOG_COPPER_ZONE( this, &g_Zone_Default_Setting );
        diag = frame->ShowModal();
        frame->Destroy();
    }
    else   // edit a zone on a non copper layer (technical layer)
    {
        diag = InstallDialogNonCopperZonesEditor( zone_container );
    }

    m_canvas->MoveCursorToCrossHair();
    m_canvas->SetIgnoreMouseEvents( false );

    if( diag == ZONE_ABORT )
    {
        _AuxiliaryList.ClearListAndDeleteItems();
        s_PickedList.ClearListAndDeleteItems();
        return;
    }

    if( diag == ZONE_EXPORT_VALUES )
    {
        UpdateCopyOfZonesList( s_PickedList, _AuxiliaryList, GetBoard() );
        SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED);
        s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items
        return;
    }

    // Undraw old zone outlines
    for( int ii = 0; ii < GetBoard()->GetAreaCount(); ii++ )
    {
        ZONE_CONTAINER* edge_zone = GetBoard()->GetArea( ii );
        edge_zone->Draw( m_canvas, DC, GR_XOR );
    }

    g_Zone_Default_Setting.ExportSetting( *zone_container);
    NETINFO_ITEM* net = GetBoard()->FindNet( g_Zone_Default_Setting.m_NetcodeSelection );

    if( net )   // net == NULL should not occur
        zone_container->m_Netname = net->GetNetname();

    // Combine zones if possible :
    GetBoard()->AreaPolygonModified( &_AuxiliaryList, zone_container, true, s_Verbose );

    // Redraw the real new zone outlines:
    GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_OR, -1 );

    UpdateCopyOfZonesList( s_PickedList, _AuxiliaryList, GetBoard() );
    SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED);
    s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items

    OnModify();
}


void PCB_EDIT_FRAME::Delete_Zone_Contour( wxDC* DC, ZONE_CONTAINER* zone_container )
{
    int      ncont = zone_container->m_Poly->GetContour( zone_container->m_CornerSelection );

    EDA_RECT dirty = zone_container->GetBoundingBox();

    // For compatibility with old boards: remove old SEGZONE fill segments
    Delete_OldZone_Fill( NULL, zone_container->GetTimeStamp() );

    // Remove current filling:
    zone_container->UnFill();

    if( ncont == 0 )    // This is the main outline: remove all
    {
        SaveCopyInUndoList( zone_container, UR_DELETED );
        GetBoard()->Remove( zone_container );
    }

    else
    {
        zone_container->m_Poly->RemoveContour( ncont );
    }

    m_canvas->RefreshDrawingRect( dirty );

    OnModify();
}
