# Copyright (c) 2001, 2003 by Intevation GmbH
# Authors:
# Frank Koormann    <frank.koormann@intevation.de>
#
# This program is free software under the GPL (>=v2)
# Read the file COPYING coming with Thuban for details.

"""
Dialogs to the geographic projection library PROJ
"""

__version__ = "$Revision: 1.9 $"

from wxPython.wx import *

from Thuban import _

ID_PROJECTION_EDIT   = 4010
ID_PROJECTION_SELECT = 4011
ID_PROJECTION_OK     = 4001
ID_PROJECTION_CANCEL = 4002

ID_UTM_DIALOG_OK           = 4101
ID_UTM_DIALOG_CANCEL       = 4102
ID_UTM_DIALOG_PROPOSE_ZONE = 4103

ID_UTM_PROPOSE_ZONE_DIALOG_TAKE   = 4201
ID_UTM_PROPOSE_ZONE_DIALOG_CANCEL = 4202

projectionDict = {'None' : 'None', 'UTM' : 'utm'}
projectionMapping = {'None' : 'None', 'utm' : 'UTM'}

class Proj4Dialog(wxDialog):

    """Let the user select a projection and specify related parameters"""
    
    def __init__(self, parent, projectionParamsList, map_bounding_box):
        wxDialog.__init__(self, parent, -1, _("Projection"),
                          style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)

        self.map_bounding_box = map_bounding_box
        self.dialogLayout()
        self.projectionParams={}
        combo = self.projection
        if projectionParamsList is not None:
            for element in projectionParamsList:
                key, val = element.split('=')
                self.projectionParams[key] = val
            if self.projectionParams.has_key('proj'):
                proj = projectionMapping[self.projectionParams['proj']]
                combo.SetSelection(combo.FindString(proj))
            else:
                combo.SetSelection(combo.FindString('None'))
            self.UpdateProjectionInfo()
        else:
            self.projection.SetValue('None')
            self.UpdateProjectionInfo()


    def dialogLayout(self):
        topBox = wxBoxSizer(wxVERTICAL)

        # Projection selection:
        projectionBox = wxBoxSizer(wxHORIZONTAL)
        projectionBox.Add(wxStaticText(self, -1, _("Projection")), 
            0, wxALIGN_CENTER|wxALL, 4)
        
        self.projection = wxComboBox(self, ID_PROJECTION_SELECT, "", 
                                     style = wxCB_READONLY)
        for projection in projectionDict.keys():
            self.projection.Append(projection)
        projectionBox.Add(self.projection, 0, wxALL, 4)
        projectionBox.Add(wxButton(self, ID_PROJECTION_EDIT, _("Edit")), 
                          0, wxALL, 4) 
        EVT_COMBOBOX(self, ID_PROJECTION_SELECT, self.OnProj4Select)
        EVT_BUTTON(self, ID_PROJECTION_EDIT, self.OnEdit)
        
        topBox.Add(projectionBox, 0, 0)

        # Info about current projection:
        self.projectionInfo = wxTextCtrl(self, -1, "", 
                                         style = wxTE_MULTILINE|wxTE_READONLY,
                                         size = (-1, 60))
        topBox.Add(self.projectionInfo,1,wxEXPAND|wxALL, 4)

        # Control buttons: 
        buttonBox = wxBoxSizer( wxHORIZONTAL ) 
        buttonBox.Add(wxButton(self, ID_PROJECTION_OK, _("OK")), 
                      0, wxALL, 4) 
        buttonBox.Add(wxButton(self, ID_PROJECTION_CANCEL, _("Cancel")), 
                      0, wxALL, 4) 
        topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 10)

        EVT_BUTTON(self, ID_PROJECTION_OK, self.OnProj4OK)
        EVT_BUTTON(self, ID_PROJECTION_CANCEL, self.OnProj4Cancel)

        self.SetAutoLayout(True)
        self.SetSizer(topBox)
        topBox.Fit(self)
        topBox.SetSizeHints(self)

    def OnProj4Select(self, event):
        projection = self.projection.GetStringSelection()
        if projection == 'None':
            self.projectionParams = {}
            self.UpdateProjectionInfo()

    def OnEdit(self, event):
        projection = self.projection.GetStringSelection()
        if projection is not 'None':
            dialogname = getattr(self, 'launch' + projection + 'Dialog', None)
            if dialogname is not None:
                if dialogname(self):
                    self.UpdateProjectionInfo()
                else:
                    pass
        else:
            self.projectionParams = {}

    def UpdateProjectionInfo(self):
        self.projectionInfo.Clear()
        for key in self.projectionParams.keys():
            self.projectionInfo.AppendText(key+": "
                +str(self.projectionParams[key])+"\n")
        

    def OnProj4OK(self, event):
        self.EndModal(wxID_OK)

    def OnProj4Cancel(self, event):
        self.EndModal(wxID_CANCEL)

    def launchUTMDialog(self, parent):
        dlg = UTMDialog(parent, parent.projectionInfo )
        if dlg.ShowModal():
            return True
        else:
            return False

    def GetParams(self):
        if len(self.projectionParams.keys()) > 0:    
            projection = []
            for key in self.projectionParams.keys():
                projection.append(key+"="+str(self.projectionParams[key]))
        else:
            projection=None

        return projection



class UTMDialog(wxDialog):

    """Let the user specify parameters for UTM projection (Zone, Spheroid)"""
    
    def __init__(self, parent, projection):
        wxDialog.__init__(self, parent, -1, _("Projection: UTM Parameters"),
                          wxDefaultPosition, wxSize(200, 100))
        self.parent = parent
        self.dialogLayout()
        if self.parent.projectionParams.has_key('zone'):
            text = str(self.parent.projectionParams['zone'])
            self.zone.SetSelection(self.zone.FindString(text))
        if self.parent.projectionParams.has_key('ellps'):
            text = str(self.parent.projectionParams['ellps'])
            self.ellps.SetSelection(self.ellps.FindString(text))

    def dialogLayout(self):
        topBox = wxBoxSizer(wxVERTICAL)

        zoneBox = wxBoxSizer(wxHORIZONTAL)
        zoneBox.Add(wxStaticText(self, -1, _("UTM Zone")), 
                    0, wxALIGN_CENTER|wxALL, 4)
        self.zone = wxComboBox(self, -1, "", style = wxCB_READONLY)
        for zone in range(1,61):
            self.zone.Append(str(zone))
        zoneBox.Add(self.zone, 0, wxALIGN_CENTER|wxALL, 4)
        zoneBox.Add(wxButton(self, ID_UTM_DIALOG_PROPOSE_ZONE, _("Propose")), 
                    0, wxALL, 4) 
        EVT_BUTTON(self, ID_UTM_DIALOG_PROPOSE_ZONE, self.OnProposeZone)

        topBox.Add(zoneBox, 1, wxEXPAND|wxALL, 4)

        ellipsoidBox = wxBoxSizer(wxHORIZONTAL)
        ellipsoidBox.Add(wxStaticText(self, -1, _("Ellipsoid")), 
                         0, wxALIGN_CENTER|wxALL, 4)
        self.ellps = wxComboBox(self, -1, "", style = wxCB_READONLY)
        for ellps in ["clrk66", "GRS80"]:
            self.ellps.Append(ellps)
        ellipsoidBox.Add(self.ellps, 0, wxALIGN_CENTER|wxALL, 4)

        topBox.Add(ellipsoidBox, 1, wxEXPAND|wxALL, 4)

        buttonBox = wxBoxSizer(wxHORIZONTAL)
        buttonBox.Add(wxButton(self, ID_UTM_DIALOG_OK, _("OK")), 
                      0, wxALL, 4) 
        buttonBox.Add(wxButton(self, ID_UTM_DIALOG_CANCEL, _("Cancel")), 
                      0, wxALL, 4) 
        topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 10)
        EVT_BUTTON(self, ID_UTM_DIALOG_OK, self.OnOK)
        EVT_BUTTON(self, ID_UTM_DIALOG_CANCEL, self.OnCancel)

        self.SetAutoLayout(True)
        self.SetSizer(topBox)
        topBox.Fit(self)
        topBox.SetSizeHints(self)

    def OnProposeZone(self, event):
        dlg = UTMProposeZoneDialog(self)
        if dlg.ShowModal():
            return True
        else:
            return False

    def OnOK(self, event):
        self.parent.projectionParams = {}
        self.parent.projectionParams['zone'] = self.zone.GetStringSelection()
        self.parent.projectionParams['ellps'] = self.ellps.GetStringSelection()
        self.parent.projectionParams['proj'] = "utm"
        self.Close(True)

    def OnCancel(self, event):
        self.Close(False)

class UTMProposeZoneDialog(wxDialog):

    """Propose a sensible Zone considering the current map extent."""
    
    def __init__(self, parent):
        wxDialog.__init__(self, parent, -1, _("Projection: Propose UTM Zone"),
                          wxDefaultPosition, wxSize(200, 100))
        self.parent = parent
        x, y, x2, y2 = self.parent.parent.map_bounding_box
        x = x + 180
        x2 = x2 + 180
        center = (x2 - x) / 2 + x
        self.proposedZone = str(int(center / 6 + 1))
        self.dialogLayout()

    def dialogLayout(self):
        topBox = wxBoxSizer(wxVERTICAL)

        textBox = wxBoxSizer(wxVERTICAL)
        textBox.Add(wxStaticText(self, -1, _("The current map extent center "
                                             "lies in UTM Zone")),
                    0, wxALIGN_CENTER|wxALL, 4)
        textBox.Add(wxStaticText(self, -1, self.proposedZone), 
                    0, wxALIGN_CENTER|wxALL, 4)

        topBox.Add(textBox, 1, wxEXPAND|wxALL, 4)

        buttonBox = wxBoxSizer(wxHORIZONTAL)
        buttonBox.Add(wxButton(self, ID_UTM_PROPOSE_ZONE_DIALOG_TAKE,
                      _("Take")), 0, wxALL, 4) 
        buttonBox.Add(wxButton(self, ID_UTM_PROPOSE_ZONE_DIALOG_CANCEL,
                               _("Cancel")), 0, wxALL, 4) 
        topBox.Add(buttonBox, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 10)
        EVT_BUTTON(self, ID_UTM_PROPOSE_ZONE_DIALOG_TAKE, self.OnTake)
        EVT_BUTTON(self, ID_UTM_PROPOSE_ZONE_DIALOG_CANCEL, self.OnCancel)

        self.SetAutoLayout(True)
        self.SetSizer(topBox)
        topBox.Fit(self)
        topBox.SetSizeHints(self)

    def OnTake(self, event):
        self.parent.zone.SetSelection(self.parent.zone.FindString(self.proposedZone))
        self.Close(True)

    def OnCancel(self, event):
        self.Close(False)
