# Copyright (C) 2003 by Intevation GmbH
# Authors:
# Bernhard Herzog <bh@intevation.de>
#
# This program is free software under the GPL (>=v2)
# Read the file COPYING coming with the software for details.

"""Extension to draw polygons

*** Warning: ***

This extension is very experimental and may corrupt your data. Use at
your own peril.
"""

__version__ = "$Revision: 2207 $"
# $Source$
# $Id: drawshape.py 2207 2004-05-16 09:30:34Z jan $


import os

from wxPython.wx import *

import shapelib
import Thuban
from Thuban import _
from Thuban.Model.data import SHAPETYPE_POLYGON
from Thuban.Model.table import FIELDTYPE_INT, FIELDTYPE_STRING, \
     FIELDTYPE_DOUBLE
from Thuban.UI.command import registry, ToolCommand
from Thuban.UI.mainwindow import main_menu, main_toolbar
from Thuban.UI.viewport import Tool


def write_empty_row(table, row):
    """Write an empty record to the row

    The values in the record will be set to suitable default values
    depending on the type: 0 for numeric types and the empty string for
    strings.
    """
    values = {}
    for col in table.Columns():
        if col.type == FIELDTYPE_INT:
            value = 0
        elif col.type == FIELDTYPE_DOUBLE:
            value = 0.0
        elif col.type == FIELDTYPE_STRING:
            value = ""
        else:
            print "write_empty_row: Unhandled col.type", col.type
        values[col.name] = value
    table.write_record(row, values)


def write_shape(shapestore, points):
    """Addd the points as a new shape to the shapestore

    The points argument should be a list of the same structure as that
    returned by the shapelib bindings for a polygon. It is passed
    directly to the SHPObject constructor.
    """
    shapefile = shapelib.ShapeFile(shapestore.FileName(), "r+b")
    obj = shapelib.SHPObject(shapelib.SHPT_POLYGON, 1, points)
    newid = shapefile.write_object(-1, obj)
    write_empty_row(shapestore.Table(), newid)
    shapefile.close()
    shapestore._open_shapefile()


class ShapeDrawTool(Tool):

    def __init__(self, view):
        Tool.__init__(self, view)
        self.points = []

    def Name(self):
        return "ShapeDrawTool"

    def find_shapestore(self):
        """Return the shapestore into which to write and the projection

        If the currently selected layer is a layer with polygons return
        a tuple of the shapestore and the layer's projection.
        Otherwise return a tuple of Nones.
        """
        layer = self.view.SelectedLayer()
        if layer is not None and layer.HasShapes() \
               and layer.ShapeType() == SHAPETYPE_POLYGON:
            return layer.ShapeStore(), layer.GetProjection()
        return None, None

    def MouseDown(self, event):
        Tool.MouseDown(self, event)
        if event.RightDown():
            map_proj = self.view.Map().GetProjection()
            shapestore, proj = self.find_shapestore()
            if shapestore is not None and len(self.points) > 2:
                points = self.points[:]
                if map_proj is not None:
                    points = [tuple(map_proj.Inverse(*p)) for p in points]
                if proj is not None:
                    points = [tuple(proj.Forward(*p)) for p in points]
                points.append(points[0])
                write_shape(shapestore, [points])
                self.points = []
                self.view.full_redraw()
        else:
            if not self.points:
                self.points.append(self.view.win_to_proj(*self.current))

    def MouseUp(self, event):
        Tool.MouseUp(self, event)
        self.points.append(self.view.win_to_proj(*self.current))

    def draw(self, dc):
        points = [self.view.proj_to_win(*p) for p in self.points] \
                 + [self.current]
        if len(points) == 2:
            dc.DrawLines(points)
        else:
            dc.DrawPolygon(points)

    def DrawPermanent(self, dc):
        dc.SetPen(wxPen(wxColor(255, 128, 0), 2))
        dc.SetBrush(wxTRANSPARENT_BRUSH)
        dc.DrawPolygon([self.view.proj_to_win(*p) for p in self.points])


def shape_draw_tool(context):
    canvas = context.mainwindow.canvas
    canvas.SelectTool(ShapeDrawTool(canvas))

def check_shape_draw_tool(context):
    return context.mainwindow.canvas.CurrentTool() == "ShapeDrawTool"


iconfile = os.path.join(os.path.abspath(Thuban.__path__[0]),
                        "..", "Resources", "Bitmaps", "identify")
registry.Add(ToolCommand("shape_draw_tool", "Shape Draw Tool",
                         shape_draw_tool, icon = iconfile,
                         helptext = "Draw a shape",
                         checked = check_shape_draw_tool))

# Add the command to the toolbar
main_toolbar.InsertSeparator()
main_toolbar.InsertItem("shape_draw_tool")

# find the experimental menu (create it anew if not found)
experimental_menu = main_menu.FindOrInsertMenu('experimental',
                                               _('Experimenta&l'))

# finally add the new command to the experimental menu
experimental_menu.InsertItem('shape_draw_tool')
