# Copyright (C) 2003, 2004 by Intevation GmbH
# Authors:
# Jan-Oliver Wagner <jan@intevation.de> (2003, 2004)
#
# This program is free software under the GPL (>=v2)
# Read the file COPYING coming with Thuban for details.

"""
Extend thuban with a gns2shp converter.

This module also works without Thuban on the command line
if the shapelib and dbflib python wrappers can be found via the
PYTHONPATH (e.g. via including directory 'Lib' of thuban directory).

The GUI should eventually be extended to allow pre-selection
of the points to import in order to reduce immense quantities
of some country files.
"""

__version__ = '$Revision: 2845 $'
# $Source$
# $Id: gns2shp.py 2845 2008-06-20 05:20:03Z elachuni $

import os, sys

# only import GUI and register when not called as command line tool
if __name__ != '__main__':
    import wx

    from Thuban.UI import internal_from_wxstring
    from Thuban.UI.command import registry, Command
    from Thuban.UI.mainwindow import main_menu
    from Thuban import _
    from Thuban.Model.layer import Layer

import shapelib
import dbflib

def gns2shp(src_fname, dest_fname):
    """Convert a file from gns textformat into a Shapefile.

    The GNS text format is described on
    http://www.nima.mil/gns/html/gis.html

    src_fname  -- Filename of the GNS standard textfile (including suffix '.txt)
    dest_fname -- Filename where to write the Shapefile components (name
                  without suffix). After successful completion there
                  will be files "dest_fname".shp, "dest_fname".shx and
                  "dest_fname.dbf".

    Return: Number of sucessfully converted entries
    """
    gns_filename = src_fname
    shp_filename = dest_fname + '.shp'
    dbf_filename = dest_fname + '.dbf'

    gns = open(gns_filename, 'r').readlines()

    shp = shapelib.create(shp_filename, shapelib.SHPT_POINT)
    dbf = dbflib.create(dbf_filename)

    dbf.add_field('RC', dbflib.FTInteger, 1, 0)
    dbf.add_field('UFI', dbflib.FTInteger, 10, 0)
    dbf.add_field('UNI', dbflib.FTInteger, 10, 0)
    dbf.add_field('MGRS', dbflib.FTString, 15, 0)
    dbf.add_field('JOG', dbflib.FTString, 7, 0)
    dbf.add_field('FC', dbflib.FTString, 1, 0)
    dbf.add_field('DSG', dbflib.FTString, 5, 0)
    dbf.add_field('PC', dbflib.FTInteger, 1, 0)
    dbf.add_field('CC1', dbflib.FTString, 2, 0)
    dbf.add_field('ADM1', dbflib.FTString, 2, 0)
    dbf.add_field('ADM2', dbflib.FTString, 200, 0)
    dbf.add_field('POP', dbflib.FTInteger, 10, 0)
    dbf.add_field('ELEV', dbflib.FTInteger, 10, 0)
    dbf.add_field('CC2', dbflib.FTString, 2, 0)
    dbf.add_field('NT', dbflib.FTString, 2, 0)
    dbf.add_field('LC', dbflib.FTString, 3, 0)
    dbf.add_field('SHORT_FORM', dbflib.FTString, 128, 0)
    dbf.add_field('GENERIC', dbflib.FTString, 128, 0)
    dbf.add_field('SORT_NAME', dbflib.FTString, 200, 0)
    dbf.add_field('FULL_NAME', dbflib.FTString, 200, 0)
    dbf.add_field('FULL_ND', dbflib.FTString, 200, 0) # FULL_NAME_ND
    dbf.add_field('MODIFY_DATE', dbflib.FTString, 11, 0)
    del dbf
    dbf = dbflib.open(dbf_filename, 'r+b')

    gns.pop(0) # drop the header line

    i = 0
    for line in gns:
        if line[0] == '#': continue
        RC, UFI, UNI, LAT, LONG, DMS_LAT, DMS_LONG, MGRS, JOG, FC, DSG, PC, \
            CC1, ADM1, ADM2, POP, ELEV, CC2, NT, LC, SHORT_FORM, GENERIC, \
            SORT_NAME, FULL_NAME, FULL_NAME_ND, MODIFY_DATE = line.split('\t')
        try: RC = int(RC)
        except ValueError: RC = None
        UFI = int(UFI)
        UNI = int(UNI)
        LAT = float(LAT)
        LONG = float(LONG)
        try: PC = int(PC)
        except ValueError: PC = None
        try: POP = int(POP)
        except ValueError: POP = None
        try: ELEV = int(ELEV)
        except ValueError: ELEV = None
        MODIFY_DATE = MODIFY_DATE[0:10] # kill trailing "\n" or "\r\n"
        obj = shapelib.SHPObject(shapelib.SHPT_POINT, i, [[(LONG, LAT)]])
        shp.write_object(-1, obj)

        vals = {'RC': RC, 'UFI': UFI, 'UNI': UNI, 'MGRS':MGRS, 'JOG': JOG,
                'FC': FC, 'DSG': DSG, 'PC': PC, 'CC1': CC1, 'ADM1': ADM1,
                'ADM2': ADM2, 'POP': POP, 'ELEV': ELEV, 'CC2': CC2, 'NT': NT,
                'LC': LC, 'SHORT_FORM': SHORT_FORM, 'GENERIC': GENERIC,
                'SORT_NAME': SORT_NAME, 'FULL_NAME': FULL_NAME,
                'FULL_ND': FULL_NAME_ND, 'MODIFY_DAT': MODIFY_DATE}
        dbf.write_record(i, vals)
        i += 1

    del shp
    del dbf

    return i

def gns2shp_dialog(context):
    """Request filename from user, run conversion and add
    resulting shapefile to the current map.

    context -- The Thuban context.
    """
    dlg = wx.FileDialog(context.mainwindow,
                       _('Select GNS file'), '.', '',
                       _('Generate Files (*.txt)|*.txt|') +
                       _('All Files (*.*)|*.*'),
                       wx.OPEN|wx.OVERWRITE_PROMPT)
    if dlg.ShowModal() == wx.ID_OK:
        gns_filename = internal_from_wxstring(dlg.GetPath())
        dlg.Destroy()
    else:
        return

    no = gns2shp(gns_filename, gns_filename[:-4])
    if no <= 0:
        context.mainwindow.RunMessageBox(_('gns2shp'), _('Conversion failed'))
        return
    else:
        context.mainwindow.RunMessageBox(_('gns2shp %s') % __version__,
                                         _('%d locations converted' % no))

    # Now load the newly created shapefile
    filename = gns_filename[:-4] + '.shp'
    title = os.path.splitext(os.path.basename(filename))[0]
    map = context.mainwindow.canvas.Map()
    has_layers = map.HasLayers()
    try:
        store = context.session.OpenShapefile(filename)
    except IOError:
        # the layer couldn't be opened
        context.mainwindow.RunMessageBox(_('Add GNS Layer'),
                           _("Can't open the file '%s'.") % filename)
    else:
        layer = Layer(title, store)
        map.AddLayer(layer)
        if not has_layers:
            # if we're adding a layer to an empty map, fit the
            # new map to the window
            context.mainwindow.canvas.FitMapToWindow()

if __name__ == '__main__': # gns2shp executed as a command line tool
    print 'gns2shp.py %s' % __version__
    if len(sys.argv) == 3:
        no = gns2shp(sys.argv[1], sys.argv[2][:-4])
        print '%d locations converted' % no
        sys.exit(0)
    else:
        print 'usage: gns2shp.py GNS-file Shapefile'
        sys.exit(1)


# gns2shp executed as an extension to Thuban

# register the new command
registry.Add(Command('gns2shp', _('gns2shp...'), gns2shp_dialog,
                     helptext = _('Convert GNS-file into a shapefile')))

# find the extensions menu (create it anew if not found)
extensions_menu = main_menu.FindOrInsertMenu('extensions', _('E&xtensions'))

# finally add the new entry to the extensions menu
extensions_menu.InsertItem('gns2shp')
