#!/usr/bin/env python

"""Autogenerated python functions to serialize/deserialize binary messages.

Need to then wrap these functions with the outer AIS packet and then
convert the whole binary blob to a NMEA string.  Those functions are
not currently provided in this file.

serialize: python to ais binary
deserialize: ais binary to python

The generated code uses translators.py, binary.py, and aisstring.py
which should be packaged with the resulting files.

TODO(schwehr): Put in a description of the message here with fields and types.
"""
import sys
from decimal import Decimal
import unittest

from aisutils.BitVector import BitVector

from aisutils import aisstring
from aisutils import binary
from aisutils import sqlhelp
from aisutils import uscg


fieldList = (
    'MessageID',
    'RepeatIndicator',
    'UserID',
    'Spare',
    'corner1_lon',
    'corner1_lat',
    'corner2_lon',
    'corner2_lat',
    'StationType',
    'shipandcargo',
    'Spare2',
    'TxRxMode',
    'ReportingInterval',
    'QuietTime',
    'Spare3',
)

fieldListPostgres = (
    'MessageID',
    'RepeatIndicator',
    'UserID',
    'Spare',
    'corner1',    # PostGIS data type
    'corner2',    # PostGIS data type
    'StationType',
    'shipandcargo',
    'Spare2',
    'TxRxMode',
    'ReportingInterval',
    'QuietTime',
    'Spare3',
)

toPgFields = {
    'corner1_lon':'corner1',
    'corner1_lat':'corner1',
    'corner2_lon':'corner2',
    'corner2_lat':'corner2',
}
"""
Go to the Postgis field names from the straight field name
"""

fromPgFields = {
    'corner1':('corner1_lon','corner1_lat',),
    'corner2':('corner2_lon','corner2_lat',),
}
"""
Go from the Postgis field names to the straight field name
"""

pgTypes = {
    'corner1':'POINT',
    'corner2':'POINT',
}
"""
Lookup table for each postgis field name to get its type.
"""

def encode(params, validate=False):
    '''Create a ChanMngmt binary message payload to pack into an AIS Msg ChanMngmt.

    Fields in params:
      - MessageID(uint): AIS message number.  Must be 23 (field automatically set to "23")
      - RepeatIndicator(uint): Indicated how many times a message has been repeated
      - UserID(uint): Unique ship identification number (MMSI)
      - Spare(uint): Not used.  Should be set to zero. (field automatically set to "0")
      - corner1_lon(decimal): north-east corner of area for assignment  longitude of corner
      - corner1_lat(decimal): north-east corner of area for assignment  latitude of corner
      - corner2_lon(decimal): south-west corner of area for assignment  longitude of corner
      - corner2_lat(decimal): south-west corner of area for assignment  latitude of corner
      - StationType(uint): TODO
      - shipandcargo(uint): what
      - Spare2(uint): Not used.  Should be set to zero. (field automatically set to "0")
      - TxRxMode(uint): TODO
      - ReportingInterval(uint): Command the stations to report as given in table 17
      - QuietTime(uint): How long to be quiet
      - Spare3(uint): Not used.  Should be set to zero. (field automatically set to "0")
    @param params: Dictionary of field names/values.  Throws a ValueError exception if required is missing
    @param validate: Set to true to cause checking to occur.  Runs slower.  FIX: not implemented.
    @rtype: BitVector
    @return: encoded binary message (for binary messages, this needs to be wrapped in a msg 8
    @note: The returned bits may not be 6 bit aligned.  It is up to you to pad out the bits.
    '''

    bvList = []
    bvList.append(binary.setBitVectorSize(BitVector(intVal=23),6))
    if 'RepeatIndicator' in params:
        bvList.append(binary.setBitVectorSize(BitVector(intVal=params['RepeatIndicator']),2))
    else:
        bvList.append(binary.setBitVectorSize(BitVector(intVal=0),2))
    bvList.append(binary.setBitVectorSize(BitVector(intVal=params['UserID']),30))
    bvList.append(binary.setBitVectorSize(BitVector(intVal=0),2))
    if 'corner1_lon' in params:
        bvList.append(binary.bvFromSignedInt(int(Decimal(params['corner1_lon'])*Decimal('600')),18))
    else:
        bvList.append(binary.bvFromSignedInt(108600,18))
    if 'corner1_lat' in params:
        bvList.append(binary.bvFromSignedInt(int(Decimal(params['corner1_lat'])*Decimal('600')),17))
    else:
        bvList.append(binary.bvFromSignedInt(108600,17))
    if 'corner2_lon' in params:
        bvList.append(binary.bvFromSignedInt(int(Decimal(params['corner2_lon'])*Decimal('600')),18))
    else:
        bvList.append(binary.bvFromSignedInt(108600,18))
    if 'corner2_lat' in params:
        bvList.append(binary.bvFromSignedInt(int(Decimal(params['corner2_lat'])*Decimal('600')),17))
    else:
        bvList.append(binary.bvFromSignedInt(108600,17))
    bvList.append(binary.setBitVectorSize(BitVector(intVal=params['StationType']),4))
    if 'shipandcargo' in params:
        bvList.append(binary.setBitVectorSize(BitVector(intVal=params['shipandcargo']),8))
    else:
        bvList.append(binary.setBitVectorSize(BitVector(intVal=0),8))
    bvList.append(binary.setBitVectorSize(BitVector(intVal=0),22))
    bvList.append(binary.setBitVectorSize(BitVector(intVal=params['TxRxMode']),4))
    bvList.append(binary.setBitVectorSize(BitVector(intVal=params['ReportingInterval']),4))
    bvList.append(binary.setBitVectorSize(BitVector(intVal=params['QuietTime']),22))
    bvList.append(binary.setBitVectorSize(BitVector(intVal=0),6))

    return binary.joinBV(bvList)

def decode(bv, validate=False):
    '''Unpack a ChanMngmt message.

    Fields in params:
      - MessageID(uint): AIS message number.  Must be 23 (field automatically set to "23")
      - RepeatIndicator(uint): Indicated how many times a message has been repeated
      - UserID(uint): Unique ship identification number (MMSI)
      - Spare(uint): Not used.  Should be set to zero. (field automatically set to "0")
      - corner1_lon(decimal): north-east corner of area for assignment  longitude of corner
      - corner1_lat(decimal): north-east corner of area for assignment  latitude of corner
      - corner2_lon(decimal): south-west corner of area for assignment  longitude of corner
      - corner2_lat(decimal): south-west corner of area for assignment  latitude of corner
      - StationType(uint): TODO
      - shipandcargo(uint): what
      - Spare2(uint): Not used.  Should be set to zero. (field automatically set to "0")
      - TxRxMode(uint): TODO
      - ReportingInterval(uint): Command the stations to report as given in table 17
      - QuietTime(uint): How long to be quiet
      - Spare3(uint): Not used.  Should be set to zero. (field automatically set to "0")
    @type bv: BitVector
    @param bv: Bits defining a message
    @param validate: Set to true to cause checking to occur.  Runs slower.  FIX: not implemented.
    @rtype: dict
    @return: params
    '''

    #Would be nice to check the bit count here..
    #if validate:
    #    assert (len(bv)==FIX: SOME NUMBER)
    r = {}
    r['MessageID']=23
    r['RepeatIndicator']=int(bv[6:8])
    r['UserID']=int(bv[8:38])
    r['Spare']=0
    r['corner1_lon']=Decimal(binary.signedIntFromBV(bv[40:58]))/Decimal('600')
    r['corner1_lat']=Decimal(binary.signedIntFromBV(bv[58:75]))/Decimal('600')
    r['corner2_lon']=Decimal(binary.signedIntFromBV(bv[75:93]))/Decimal('600')
    r['corner2_lat']=Decimal(binary.signedIntFromBV(bv[93:110]))/Decimal('600')
    r['StationType']=int(bv[110:114])
    r['shipandcargo']=int(bv[114:122])
    r['Spare2']=0
    r['TxRxMode']=int(bv[144:148])
    r['ReportingInterval']=int(bv[148:152])
    r['QuietTime']=int(bv[152:174])
    r['Spare3']=0
    return r

def decodeMessageID(bv, validate=False):
    return 23

def decodeRepeatIndicator(bv, validate=False):
    return int(bv[6:8])

def decodeUserID(bv, validate=False):
    return int(bv[8:38])

def decodeSpare(bv, validate=False):
    return 0

def decodecorner1_lon(bv, validate=False):
    return Decimal(binary.signedIntFromBV(bv[40:58]))/Decimal('600')

def decodecorner1_lat(bv, validate=False):
    return Decimal(binary.signedIntFromBV(bv[58:75]))/Decimal('600')

def decodecorner2_lon(bv, validate=False):
    return Decimal(binary.signedIntFromBV(bv[75:93]))/Decimal('600')

def decodecorner2_lat(bv, validate=False):
    return Decimal(binary.signedIntFromBV(bv[93:110]))/Decimal('600')

def decodeStationType(bv, validate=False):
    return int(bv[110:114])

def decodeshipandcargo(bv, validate=False):
    return int(bv[114:122])

def decodeSpare2(bv, validate=False):
    return 0

def decodeTxRxMode(bv, validate=False):
    return int(bv[144:148])

def decodeReportingInterval(bv, validate=False):
    return int(bv[148:152])

def decodeQuietTime(bv, validate=False):
    return int(bv[152:174])

def decodeSpare3(bv, validate=False):
    return 0


def printHtml(params, out=sys.stdout):
        out.write("<h3>ChanMngmt</h3>\n")
        out.write("<table border=\"1\">\n")
        out.write("<tr bgcolor=\"orange\">\n")
        out.write("<th align=\"left\">Field Name</th>\n")
        out.write("<th align=\"left\">Type</th>\n")
        out.write("<th align=\"left\">Value</th>\n")
        out.write("<th align=\"left\">Value in Lookup Table</th>\n")
        out.write("<th align=\"left\">Units</th>\n")
        out.write("</tr>\n")
        out.write("\n")
        out.write("<tr>\n")
        out.write("<td>MessageID</td>\n")
        out.write("<td>uint</td>\n")
        if 'MessageID' in params:
            out.write("    <td>"+str(params['MessageID'])+"</td>\n")
            out.write("    <td>"+str(params['MessageID'])+"</td>\n")
        out.write("</tr>\n")
        out.write("\n")
        out.write("<tr>\n")
        out.write("<td>RepeatIndicator</td>\n")
        out.write("<td>uint</td>\n")
        if 'RepeatIndicator' in params:
            out.write("    <td>"+str(params['RepeatIndicator'])+"</td>\n")
            if str(params['RepeatIndicator']) in RepeatIndicatorDecodeLut:
                out.write("<td>"+RepeatIndicatorDecodeLut[str(params['RepeatIndicator'])]+"</td>")
            else:
                out.write("<td><i>Missing LUT entry</i></td>")
        out.write("</tr>\n")
        out.write("\n")
        out.write("<tr>\n")
        out.write("<td>UserID</td>\n")
        out.write("<td>uint</td>\n")
        if 'UserID' in params:
            out.write("    <td>"+str(params['UserID'])+"</td>\n")
            out.write("    <td>"+str(params['UserID'])+"</td>\n")
        out.write("</tr>\n")
        out.write("\n")
        out.write("<tr>\n")
        out.write("<td>Spare</td>\n")
        out.write("<td>uint</td>\n")
        if 'Spare' in params:
            out.write("    <td>"+str(params['Spare'])+"</td>\n")
            out.write("    <td>"+str(params['Spare'])+"</td>\n")
        out.write("</tr>\n")
        out.write("\n")
        out.write("<tr>\n")
        out.write("<td>corner1_lon</td>\n")
        out.write("<td>decimal</td>\n")
        if 'corner1_lon' in params:
            out.write("    <td>"+str(params['corner1_lon'])+"</td>\n")
            out.write("    <td>"+str(params['corner1_lon'])+"</td>\n")
        out.write("<td>degrees</td>\n")
        out.write("</tr>\n")
        out.write("\n")
        out.write("<tr>\n")
        out.write("<td>corner1_lat</td>\n")
        out.write("<td>decimal</td>\n")
        if 'corner1_lat' in params:
            out.write("    <td>"+str(params['corner1_lat'])+"</td>\n")
            out.write("    <td>"+str(params['corner1_lat'])+"</td>\n")
        out.write("<td>degrees</td>\n")
        out.write("</tr>\n")
        out.write("\n")
        out.write("<tr>\n")
        out.write("<td>corner2_lon</td>\n")
        out.write("<td>decimal</td>\n")
        if 'corner2_lon' in params:
            out.write("    <td>"+str(params['corner2_lon'])+"</td>\n")
            out.write("    <td>"+str(params['corner2_lon'])+"</td>\n")
        out.write("<td>degrees</td>\n")
        out.write("</tr>\n")
        out.write("\n")
        out.write("<tr>\n")
        out.write("<td>corner2_lat</td>\n")
        out.write("<td>decimal</td>\n")
        if 'corner2_lat' in params:
            out.write("    <td>"+str(params['corner2_lat'])+"</td>\n")
            out.write("    <td>"+str(params['corner2_lat'])+"</td>\n")
        out.write("<td>degrees</td>\n")
        out.write("</tr>\n")
        out.write("\n")
        out.write("<tr>\n")
        out.write("<td>StationType</td>\n")
        out.write("<td>uint</td>\n")
        if 'StationType' in params:
            out.write("    <td>"+str(params['StationType'])+"</td>\n")
            if str(params['StationType']) in StationTypeDecodeLut:
                out.write("<td>"+StationTypeDecodeLut[str(params['StationType'])]+"</td>")
            else:
                out.write("<td><i>Missing LUT entry</i></td>")
        out.write("</tr>\n")
        out.write("\n")
        out.write("<tr>\n")
        out.write("<td>shipandcargo</td>\n")
        out.write("<td>uint</td>\n")
        if 'shipandcargo' in params:
            out.write("    <td>"+str(params['shipandcargo'])+"</td>\n")
            if str(params['shipandcargo']) in shipandcargoDecodeLut:
                out.write("<td>"+shipandcargoDecodeLut[str(params['shipandcargo'])]+"</td>")
            else:
                out.write("<td><i>Missing LUT entry</i></td>")
        out.write("</tr>\n")
        out.write("\n")
        out.write("<tr>\n")
        out.write("<td>Spare2</td>\n")
        out.write("<td>uint</td>\n")
        if 'Spare2' in params:
            out.write("    <td>"+str(params['Spare2'])+"</td>\n")
            out.write("    <td>"+str(params['Spare2'])+"</td>\n")
        out.write("</tr>\n")
        out.write("\n")
        out.write("<tr>\n")
        out.write("<td>TxRxMode</td>\n")
        out.write("<td>uint</td>\n")
        if 'TxRxMode' in params:
            out.write("    <td>"+str(params['TxRxMode'])+"</td>\n")
            if str(params['TxRxMode']) in TxRxModeDecodeLut:
                out.write("<td>"+TxRxModeDecodeLut[str(params['TxRxMode'])]+"</td>")
            else:
                out.write("<td><i>Missing LUT entry</i></td>")
        out.write("</tr>\n")
        out.write("\n")
        out.write("<tr>\n")
        out.write("<td>ReportingInterval</td>\n")
        out.write("<td>uint</td>\n")
        if 'ReportingInterval' in params:
            out.write("    <td>"+str(params['ReportingInterval'])+"</td>\n")
            if str(params['ReportingInterval']) in ReportingIntervalDecodeLut:
                out.write("<td>"+ReportingIntervalDecodeLut[str(params['ReportingInterval'])]+"</td>")
            else:
                out.write("<td><i>Missing LUT entry</i></td>")
        out.write("</tr>\n")
        out.write("\n")
        out.write("<tr>\n")
        out.write("<td>QuietTime</td>\n")
        out.write("<td>uint</td>\n")
        if 'QuietTime' in params:
            out.write("    <td>"+str(params['QuietTime'])+"</td>\n")
            out.write("    <td>"+str(params['QuietTime'])+"</td>\n")
        out.write("<td>min</td>\n")
        out.write("</tr>\n")
        out.write("\n")
        out.write("<tr>\n")
        out.write("<td>Spare3</td>\n")
        out.write("<td>uint</td>\n")
        if 'Spare3' in params:
            out.write("    <td>"+str(params['Spare3'])+"</td>\n")
            out.write("    <td>"+str(params['Spare3'])+"</td>\n")
        out.write("</tr>\n")
        out.write("</table>\n")

def printFields(params, out=sys.stdout, format='std', fieldList=None, dbType='postgres'):
    '''Print a ChanMngmt message to stdout.

    Fields in params:
      - MessageID(uint): AIS message number.  Must be 23 (field automatically set to "23")
      - RepeatIndicator(uint): Indicated how many times a message has been repeated
      - UserID(uint): Unique ship identification number (MMSI)
      - Spare(uint): Not used.  Should be set to zero. (field automatically set to "0")
      - corner1_lon(decimal): north-east corner of area for assignment  longitude of corner
      - corner1_lat(decimal): north-east corner of area for assignment  latitude of corner
      - corner2_lon(decimal): south-west corner of area for assignment  longitude of corner
      - corner2_lat(decimal): south-west corner of area for assignment  latitude of corner
      - StationType(uint): TODO
      - shipandcargo(uint): what
      - Spare2(uint): Not used.  Should be set to zero. (field automatically set to "0")
      - TxRxMode(uint): TODO
      - ReportingInterval(uint): Command the stations to report as given in table 17
      - QuietTime(uint): How long to be quiet
      - Spare3(uint): Not used.  Should be set to zero. (field automatically set to "0")
    @param params: Dictionary of field names/values.
    @param out: File like object to write to.
    @rtype: stdout
    @return: text to out
    '''

    if 'std'==format:
        out.write("ChanMngmt:\n")
        if 'MessageID' in params: out.write("    MessageID:          "+str(params['MessageID'])+"\n")
        if 'RepeatIndicator' in params: out.write("    RepeatIndicator:    "+str(params['RepeatIndicator'])+"\n")
        if 'UserID' in params: out.write("    UserID:             "+str(params['UserID'])+"\n")
        if 'Spare' in params: out.write("    Spare:              "+str(params['Spare'])+"\n")
        if 'corner1_lon' in params: out.write("    corner1_lon:        "+str(params['corner1_lon'])+"\n")
        if 'corner1_lat' in params: out.write("    corner1_lat:        "+str(params['corner1_lat'])+"\n")
        if 'corner2_lon' in params: out.write("    corner2_lon:        "+str(params['corner2_lon'])+"\n")
        if 'corner2_lat' in params: out.write("    corner2_lat:        "+str(params['corner2_lat'])+"\n")
        if 'StationType' in params: out.write("    StationType:        "+str(params['StationType'])+"\n")
        if 'shipandcargo' in params: out.write("    shipandcargo:       "+str(params['shipandcargo'])+"\n")
        if 'Spare2' in params: out.write("    Spare2:             "+str(params['Spare2'])+"\n")
        if 'TxRxMode' in params: out.write("    TxRxMode:           "+str(params['TxRxMode'])+"\n")
        if 'ReportingInterval' in params: out.write("    ReportingInterval:  "+str(params['ReportingInterval'])+"\n")
        if 'QuietTime' in params: out.write("    QuietTime:          "+str(params['QuietTime'])+"\n")
        if 'Spare3' in params: out.write("    Spare3:             "+str(params['Spare3'])+"\n")
        elif 'csv'==format:
                if None == options.fieldList:
                        options.fieldList = fieldList
                needComma = False;
                for field in fieldList:
                        if needComma: out.write(',')
                        needComma = True
                        if field in params:
                                out.write(str(params[field]))
                        # else: leave it empty
                out.write("\n")
    elif 'html'==format:
        printHtml(params,out)
    elif 'sql'==format:
                sqlInsertStr(params,out,dbType=dbType)
    else:
        print "ERROR: unknown format:",format
        assert False

    return # Nothing to return

RepeatIndicatorEncodeLut = {
    'default':'0',
    'do not repeat any more':'3',
    } #RepeatIndicatorEncodeLut

RepeatIndicatorDecodeLut = {
    '0':'default',
    '3':'do not repeat any more',
    } # RepeatIndicatorEncodeLut

StationTypeEncodeLut = {
    'all types of mobiles':'0',
    'reserved for future use':'1',
    'all types of Class B mobile stations':'2',
    'SAR airborne mobile stations':'3',
    'AtoN station':'4',
    'Class B "CS" shipborne mobile stations (IEC62287 only)':'5',
    'regional use and inland waterways':'6',
    'regional use and inland waterways':'7',
    'regional use and inland waterways':'8',
    'regional use and inland waterways':'9',
    'reserved for future use':'10',
    'reserved for future use':'11',
    'reserved for future use':'12',
    'reserved for future use':'13',
    'reserved for future use':'14',
    'reserved for future use':'15',
    } #StationTypeEncodeLut

StationTypeDecodeLut = {
    '0':'all types of mobiles',
    '1':'reserved for future use',
    '2':'all types of Class B mobile stations',
    '3':'SAR airborne mobile stations',
    '4':'AtoN station',
    '5':'Class B "CS" shipborne mobile stations (IEC62287 only)',
    '6':'regional use and inland waterways',
    '7':'regional use and inland waterways',
    '8':'regional use and inland waterways',
    '9':'regional use and inland waterways',
    '10':'reserved for future use',
    '11':'reserved for future use',
    '12':'reserved for future use',
    '13':'reserved for future use',
    '14':'reserved for future use',
    '15':'reserved for future use',
    } # StationTypeEncodeLut

shipandcargoEncodeLut = {
    'Wing in ground (WIG), all ships of this type':'20',
    'Wing in ground (WIG), Hazardous catagory A':'21',
    'Wing in ground (WIG), Hazardous catagory B':'22',
    'Wing in ground (WIG), Hazardous catagory C':'23',
    'Wing in ground (WIG), Hazardous catagory D':'24',
    'Wing in ground (WIG), Reserved for future use':'25',
    'Wing in ground (WIG), Reserved for future use':'26',
    'Wing in ground (WIG), Reserved for future use':'27',
    'Wing in ground (WIG), Reserved for future use':'28',
    'Wing in ground (WIG), No additional information':'29',
    'fishing':'30',
    'towing':'31',
    'towing length exceeds 200m or breadth exceeds 25m':'32',
    'dredging or underwater ops':'33',
    'diving ops':'34',
    'military ops':'35',
    'sailing':'36',
    'pleasure craft':'37',
    'reserved':'38',
    'reserved':'39',
    'High speed craft (HSC), all ships of this type':'40',
    'High speed craft (HSC), Hazardous catagory A':'41',
    'High speed craft (HSC), Hazardous catagory B':'42',
    'High speed craft (HSC), Hazardous catagory C':'43',
    'High speed craft (HSC), Hazardous catagory D':'44',
    'High speed craft (HSC), Reserved for future use':'45',
    'High speed craft (HSC), Reserved for future use':'46',
    'High speed craft (HSC), Reserved for future use':'47',
    'High speed craft (HSC), Reserved for future use':'48',
    'High speed craft (HSC), No additional information':'49',
    'pilot vessel':'50',
    'search and rescue vessel':'51',
    'tug':'52',
    'port tender':'53',
    'anti-polution equipment':'54',
    'law enforcement':'55',
    'spare - local vessel':'56',
    'spare - local vessel':'57',
    'medical transport':'58',
    'ship according to RR Resolution No. 18':'59',
    'passenger, all ships of this type':'60',
    'passenger, Hazardous catagory A':'61',
    'passenger, Hazardous catagory B':'62',
    'passenger, Hazardous catagory C':'63',
    'passenger, Hazardous catagory D':'64',
    'passenger, Reserved for future use':'65',
    'passenger, Reserved for future use':'66',
    'passenger, Reserved for future use':'67',
    'passenger, Reserved for future use':'68',
    'passenger, No additional information':'69',
    'cargo, all ships of this type':'70',
    'cargo, Hazardous catagory A':'71',
    'cargo, Hazardous catagory B':'72',
    'cargo, Hazardous catagory C':'73',
    'cargo, Hazardous catagory D':'74',
    'cargo, Reserved for future use':'75',
    'cargo, Reserved for future use':'76',
    'cargo, Reserved for future use':'77',
    'cargo, Reserved for future use':'78',
    'cargo, No additional information':'79',
    'tanker, all ships of this type':'80',
    'tanker, Hazardous catagory A':'81',
    'tanker, Hazardous catagory B':'82',
    'tanker, Hazardous catagory C':'83',
    'tanker, Hazardous catagory D':'84',
    'tanker, Reserved for future use':'85',
    'tanker, Reserved for future use':'86',
    'tanker, Reserved for future use':'87',
    'tanker, Reserved for future use':'88',
    'tanker, No additional information':'89',
    'other type, all ships of this type':'90',
    'other type, Hazardous catagory A':'91',
    'other type, Hazardous catagory B':'92',
    'other type, Hazardous catagory C':'93',
    'other type, Hazardous catagory D':'94',
    'other type, Reserved for future use':'95',
    'other type, Reserved for future use':'96',
    'other type, Reserved for future use':'97',
    'other type, Reserved for future use':'98',
    'other type, No additional information':'99',
    } #shipandcargoEncodeLut

shipandcargoDecodeLut = {
    '20':'Wing in ground (WIG), all ships of this type',
    '21':'Wing in ground (WIG), Hazardous catagory A',
    '22':'Wing in ground (WIG), Hazardous catagory B',
    '23':'Wing in ground (WIG), Hazardous catagory C',
    '24':'Wing in ground (WIG), Hazardous catagory D',
    '25':'Wing in ground (WIG), Reserved for future use',
    '26':'Wing in ground (WIG), Reserved for future use',
    '27':'Wing in ground (WIG), Reserved for future use',
    '28':'Wing in ground (WIG), Reserved for future use',
    '29':'Wing in ground (WIG), No additional information',
    '30':'fishing',
    '31':'towing',
    '32':'towing length exceeds 200m or breadth exceeds 25m',
    '33':'dredging or underwater ops',
    '34':'diving ops',
    '35':'military ops',
    '36':'sailing',
    '37':'pleasure craft',
    '38':'reserved',
    '39':'reserved',
    '40':'High speed craft (HSC), all ships of this type',
    '41':'High speed craft (HSC), Hazardous catagory A',
    '42':'High speed craft (HSC), Hazardous catagory B',
    '43':'High speed craft (HSC), Hazardous catagory C',
    '44':'High speed craft (HSC), Hazardous catagory D',
    '45':'High speed craft (HSC), Reserved for future use',
    '46':'High speed craft (HSC), Reserved for future use',
    '47':'High speed craft (HSC), Reserved for future use',
    '48':'High speed craft (HSC), Reserved for future use',
    '49':'High speed craft (HSC), No additional information',
    '50':'pilot vessel',
    '51':'search and rescue vessel',
    '52':'tug',
    '53':'port tender',
    '54':'anti-polution equipment',
    '55':'law enforcement',
    '56':'spare - local vessel',
    '57':'spare - local vessel',
    '58':'medical transport',
    '59':'ship according to RR Resolution No. 18',
    '60':'passenger, all ships of this type',
    '61':'passenger, Hazardous catagory A',
    '62':'passenger, Hazardous catagory B',
    '63':'passenger, Hazardous catagory C',
    '64':'passenger, Hazardous catagory D',
    '65':'passenger, Reserved for future use',
    '66':'passenger, Reserved for future use',
    '67':'passenger, Reserved for future use',
    '68':'passenger, Reserved for future use',
    '69':'passenger, No additional information',
    '70':'cargo, all ships of this type',
    '71':'cargo, Hazardous catagory A',
    '72':'cargo, Hazardous catagory B',
    '73':'cargo, Hazardous catagory C',
    '74':'cargo, Hazardous catagory D',
    '75':'cargo, Reserved for future use',
    '76':'cargo, Reserved for future use',
    '77':'cargo, Reserved for future use',
    '78':'cargo, Reserved for future use',
    '79':'cargo, No additional information',
    '80':'tanker, all ships of this type',
    '81':'tanker, Hazardous catagory A',
    '82':'tanker, Hazardous catagory B',
    '83':'tanker, Hazardous catagory C',
    '84':'tanker, Hazardous catagory D',
    '85':'tanker, Reserved for future use',
    '86':'tanker, Reserved for future use',
    '87':'tanker, Reserved for future use',
    '88':'tanker, Reserved for future use',
    '89':'tanker, No additional information',
    '90':'other type, all ships of this type',
    '91':'other type, Hazardous catagory A',
    '92':'other type, Hazardous catagory B',
    '93':'other type, Hazardous catagory C',
    '94':'other type, Hazardous catagory D',
    '95':'other type, Reserved for future use',
    '96':'other type, Reserved for future use',
    '97':'other type, Reserved for future use',
    '98':'other type, Reserved for future use',
    '99':'other type, No additional information',
    } # shipandcargoEncodeLut

TxRxModeEncodeLut = {
    'Tx A/Tx B, Rx A/RX B':'0',
    'Tx A, Rx A/Rx B':'1',
    'Tx B, Rx A/Rx B':'2',
    'reserved for future use':'3',
    } #TxRxModeEncodeLut

TxRxModeDecodeLut = {
    '0':'Tx A/Tx B, Rx A/RX B',
    '1':'Tx A, Rx A/Rx B',
    '2':'Tx B, Rx A/Rx B',
    '3':'reserved for future use',
    } # TxRxModeEncodeLut

ReportingIntervalEncodeLut = {
    'As given by the autonomous mode':'0',
    '10 minutes':'1',
    '6 minutes':'2',
    '3 minutes':'3',
    '1 minute':'4',
    '30 seconds':'5',
    '15 seconds':'6',
    '10 seconds':'7',
    '5 seconds':'8',
    'Next shorter reporting interval':'9',
    'Next longer reporting interval':'10',
    'Reserved for future use':'11',
    'Reserved for future use':'12',
    'Reserved for future use':'13',
    'Reserved for future use':'14',
    'Reserved for future use':'15',
    } #ReportingIntervalEncodeLut

ReportingIntervalDecodeLut = {
    '0':'As given by the autonomous mode',
    '1':'10 minutes',
    '2':'6 minutes',
    '3':'3 minutes',
    '4':'1 minute',
    '5':'30 seconds',
    '6':'15 seconds',
    '7':'10 seconds',
    '8':'5 seconds',
    '9':'Next shorter reporting interval',
    '10':'Next longer reporting interval',
    '11':'Reserved for future use',
    '12':'Reserved for future use',
    '13':'Reserved for future use',
    '14':'Reserved for future use',
    '15':'Reserved for future use',
    } # ReportingIntervalEncodeLut

######################################################################
# SQL SUPPORT
######################################################################

dbTableName='ChanMngmt'
'Database table name'

def sqlCreateStr(outfile=sys.stdout, fields=None, extraFields=None
                ,addCoastGuardFields=True
                ,dbType='postgres'
                ):
        """
        Return the SQL CREATE command for this message type
        @param outfile: file like object to print to.
        @param fields: which fields to put in the create.  Defaults to all.
        @param extraFields: A sequence of tuples containing (name,sql type) for additional fields
        @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format
        @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres')
        @type addCoastGuardFields: bool
        @return: sql create string
        @rtype: str

        @see: sqlCreate
        """
        # FIX: should this sqlCreate be the same as in LaTeX (createFuncName) rather than hard coded?
        outfile.write(str(sqlCreate(fields,extraFields,addCoastGuardFields,dbType=dbType)))

def sqlCreate(fields=None, extraFields=None, addCoastGuardFields=True, dbType='postgres'):
    """Return the sqlhelp object to create the table.

    @param fields: which fields to put in the create.  Defaults to all.
    @param extraFields: A sequence of tuples containing (name,sql type) for additional fields
    @param addCoastGuardFields: Add the extra fields that come after the NMEA check some from the USCG N-AIS format
    @type addCoastGuardFields: bool
    @param dbType: Which flavor of database we are using so that the create is tailored ('sqlite' or 'postgres')
    @return: An object that can be used to generate a return
    @rtype: sqlhelp.create
    """
    if fields is None:
        fields = fieldList
    c = sqlhelp.create('ChanMngmt',dbType=dbType)
    c.addPrimaryKey()
    if 'MessageID' in fields: c.addInt ('MessageID')
    if 'RepeatIndicator' in fields: c.addInt ('RepeatIndicator')
    if 'UserID' in fields: c.addInt ('UserID')
    if 'Spare' in fields: c.addInt ('Spare')
    if dbType != 'postgres':
        if 'corner1_lon' in fields: c.addDecimal('corner1_lon',5,2)
    if dbType != 'postgres':
        if 'corner1_lat' in fields: c.addDecimal('corner1_lat',5,2)
    if dbType != 'postgres':
        if 'corner2_lon' in fields: c.addDecimal('corner2_lon',5,2)
    if dbType != 'postgres':
        if 'corner2_lat' in fields: c.addDecimal('corner2_lat',5,2)
    if 'StationType' in fields: c.addInt ('StationType')
    if 'shipandcargo' in fields: c.addInt ('shipandcargo')
    if 'Spare2' in fields: c.addInt ('Spare2')
    if 'TxRxMode' in fields: c.addInt ('TxRxMode')
    if 'ReportingInterval' in fields: c.addInt ('ReportingInterval')
    if 'QuietTime' in fields: c.addInt ('QuietTime')
    if 'Spare3' in fields: c.addInt ('Spare3')

    if addCoastGuardFields:
        # c.addInt('cg_s_rssi')  # Relative signal strength indicator
        # c.addInt('cg_d_strength')  # dBm receive strength
        # c.addVarChar('cg_x',10)  # Idonno
        c.addInt('cg_t_arrival')  # Receive timestamp from the AIS equipment 'T'
        c.addInt('cg_s_slotnum')  # Slot received in
        c.addVarChar('cg_r',15)  # Receiver station ID  -  should usually be an MMSI, but sometimes is a string
        c.addInt('cg_sec')  # UTC seconds since the epoch

        c.addTimestamp('cg_timestamp') # UTC decoded cg_sec - not actually in the data stream

    if dbType == 'postgres':
        #--- EPSG 4326 : WGS 84
        #INSERT INTO "spatial_ref_sys" ("srid","auth_name","auth_srid","srtext","proj4text") VALUES (4326,'EPSG',4326,'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs ');
        c.addPostGIS('corner1','POINT',2,SRID=4326);
        #--- EPSG 4326 : WGS 84
        #INSERT INTO "spatial_ref_sys" ("srid","auth_name","auth_srid","srtext","proj4text") VALUES (4326,'EPSG',4326,'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs ');
        c.addPostGIS('corner2','POINT',2,SRID=4326);

    return c

def sqlInsertStr(params, outfile=sys.stdout, extraParams=None, dbType='postgres'):
        """
        Return the SQL INSERT command for this message type
        @param params: dictionary of values keyed by field name
        @param outfile: file like object to print to.
        @param extraParams: A sequence of tuples containing (name,sql type) for additional fields
        @return: sql create string
        @rtype: str

        @see: sqlCreate
        """
        outfile.write(str(sqlInsert(params,extraParams,dbType=dbType)))


def sqlInsert(params,extraParams=None,dbType='postgres'):
        """
        Give the SQL INSERT statement
        @param params: dict keyed by field name of values
        @param extraParams: any extra fields that you have created beyond the normal ais message fields
        @rtype: sqlhelp.insert
        @return: insert class instance
         TODO(schwehr):allow optional type checking of params?
        @warning: this will take invalid keys happily and do what???
        """

        i = sqlhelp.insert('ChanMngmt',dbType=dbType)

        if dbType=='postgres':
                finished = []
                for key in params:
                        if key in finished:
                                continue

                        if key not in toPgFields and key not in fromPgFields:
                                if type(params[key])==Decimal: i.add(key,float(params[key]))
                                else: i.add(key,params[key])
                        else:
                                if key in fromPgFields:
                                        val = params[key]
                                        # Had better be a WKT type like POINT(-88.1 30.321)
                                        i.addPostGIS(key,val)
                                        finished.append(key)
                                else:
                                        # Need to construct the type.
                                        pgName = toPgFields[key]
                                        #valStr='GeomFromText(\''+pgTypes[pgName]+'('
                                        valStr=pgTypes[pgName]+'('
                                        vals = []
                                        for nonPgKey in fromPgFields[pgName]:
                                                vals.append(str(params[nonPgKey]))
                                                finished.append(nonPgKey)
                                        valStr+=' '.join(vals)+')'
                                        i.addPostGIS(pgName,valStr)
        else:
                for key in params:
                        if type(params[key])==Decimal: i.add(key,float(params[key]))
                        else: i.add(key,params[key])

        if None != extraParams:
                for key in extraParams:
                        i.add(key,extraParams[key])

        return i

######################################################################
# LATEX SUPPORT
######################################################################

def latexDefinitionTable(outfile=sys.stdout
                ):
        """
        Return the LaTeX definition table for this message type
        @param outfile: file like object to print to.
        @type outfile: file obj
        @return: LaTeX table string via the outfile
        @rtype: str

        """
        o = outfile

        o.write("""
\\begin{table}%[htb]
\\centering
\\begin{tabular}{|l|c|l|}
\\hline
Parameter & Number of bits & Description
\\\\  \\hline\\hline
MessageID & 6 & AIS message number.  Must be 23 \\\\ \hline
RepeatIndicator & 2 & Indicated how many times a message has been repeated \\\\ \hline
UserID & 30 & Unique ship identification number (MMSI) \\\\ \hline
Spare & 2 & Not used.  Should be set to zero. \\\\ \hline
corner1\_lon & 18 & north-east corner of area for assignment  longitude of corner \\\\ \hline
corner1\_lat & 17 & north-east corner of area for assignment  latitude of corner \\\\ \hline
corner2\_lon & 18 & south-west corner of area for assignment  longitude of corner \\\\ \hline
corner2\_lat & 17 & south-west corner of area for assignment  latitude of corner \\\\ \hline
StationType & 4 & TODO \\\\ \hline
shipandcargo & 8 & Type of ship and cargo type.  FIX: need to verify that I got this lookup table right.  Also need to handle entryranges in the lookup table \\\\ \hline
Spare2 & 22 & Not used.  Should be set to zero. \\\\ \hline
TxRxMode & 4 & TODO \\\\ \hline
ReportingInterval & 4 & Command the stations to report as given in table 17 \\\\ \hline
QuietTime & 22 & How long to be quiet \\\\ \hline
Spare3 & 6 & Not used.  Should be set to zero.\\\\ \\hline \\hline
Total bits & 180 & Appears to take 2 slots with 244 pad bits to fill the last slot \\\\ \\hline
\\end{tabular}
\\caption{AIS message number 23: Group Assignment Command}
\\label{tab:ChanMngmt}
\\end{table}
""")

######################################################################
# Text Definition
######################################################################

def textDefinitionTable(outfile=sys.stdout ,delim='    '):
    """Return the text definition table for this message type

    @param outfile: file like object to print to.
    @type outfile: file obj
    @return: text table string via the outfile
    @rtype: str

    """
    o = outfile
    o.write('Parameter'+delim+'Number of bits'+delim+"""Description
MessageID"""+delim+'6'+delim+"""AIS message number.  Must be 23
RepeatIndicator"""+delim+'2'+delim+"""Indicated how many times a message has been repeated
UserID"""+delim+'30'+delim+"""Unique ship identification number (MMSI)
Spare"""+delim+'2'+delim+"""Not used.  Should be set to zero.
corner1_lon"""+delim+'18'+delim+"""north-east corner of area for assignment  longitude of corner
corner1_lat"""+delim+'17'+delim+"""north-east corner of area for assignment  latitude of corner
corner2_lon"""+delim+'18'+delim+"""south-west corner of area for assignment  longitude of corner
corner2_lat"""+delim+'17'+delim+"""south-west corner of area for assignment  latitude of corner
StationType"""+delim+'4'+delim+"""TODO
shipandcargo"""+delim+'8'+delim+"""Type of ship and cargo type.  FIX: need to verify that I got this lookup table right.  Also need to handle entryranges in the lookup table
Spare2"""+delim+'22'+delim+"""Not used.  Should be set to zero.
TxRxMode"""+delim+'4'+delim+"""TODO
ReportingInterval"""+delim+'4'+delim+"""Command the stations to report as given in table 17
QuietTime"""+delim+'22'+delim+"""How long to be quiet
Spare3"""+delim+'6'+delim+"""Not used.  Should be set to zero.
Total bits"""+delim+"""180"""+delim+"""Appears to take 2 slots with 244 pad bits to fill the last slot""")


######################################################################
# UNIT TESTING
######################################################################
def testParams():
    '''Return a params file base on the testvalue tags.
    @rtype: dict
    @return: params based on testvalue tags
    '''
    params = {}
    params['MessageID'] = 23
    params['RepeatIndicator'] = 1
    params['UserID'] = 1193046
    params['Spare'] = 0
    params['corner1_lon'] = Decimal('-122.16')
    params['corner1_lat'] = Decimal('37.42')
    params['corner2_lon'] = Decimal('-122.16')
    params['corner2_lat'] = Decimal('37.42')
    params['StationType'] = 3
    params['shipandcargo'] = 55
    params['Spare2'] = 0
    params['TxRxMode'] = 1
    params['ReportingInterval'] = 9
    params['QuietTime'] = 5
    params['Spare3'] = 0

    return params

class TestChanMngmt(unittest.TestCase):
    '''Use testvalue tag text from each type to build test case the ChanMngmt message'''
    def testEncodeDecode(self):

        params = testParams()
        bits   = encode(params)
        r      = decode(bits)

        # Check that each parameter came through ok.
        self.failUnlessEqual(r['MessageID'],params['MessageID'])
        self.failUnlessEqual(r['RepeatIndicator'],params['RepeatIndicator'])
        self.failUnlessEqual(r['UserID'],params['UserID'])
        self.failUnlessEqual(r['Spare'],params['Spare'])
        self.failUnlessAlmostEqual(r['corner1_lon'],params['corner1_lon'],2)
        self.failUnlessAlmostEqual(r['corner1_lat'],params['corner1_lat'],2)
        self.failUnlessAlmostEqual(r['corner2_lon'],params['corner2_lon'],2)
        self.failUnlessAlmostEqual(r['corner2_lat'],params['corner2_lat'],2)
        self.failUnlessEqual(r['StationType'],params['StationType'])
        self.failUnlessEqual(r['shipandcargo'],params['shipandcargo'])
        self.failUnlessEqual(r['Spare2'],params['Spare2'])
        self.failUnlessEqual(r['TxRxMode'],params['TxRxMode'])
        self.failUnlessEqual(r['ReportingInterval'],params['ReportingInterval'])
        self.failUnlessEqual(r['QuietTime'],params['QuietTime'])
        self.failUnlessEqual(r['Spare3'],params['Spare3'])

def addMsgOptions(parser):
    parser.add_option('-d','--decode',dest='doDecode',default=False,action='store_true',
                help='decode a "ChanMngmt" AIS message')
    parser.add_option('-e','--encode',dest='doEncode',default=False,action='store_true',
                help='encode a "ChanMngmt" AIS message')
    parser.add_option('--RepeatIndicator-field', dest='RepeatIndicatorField',default=0,metavar='uint',type='int'
        ,help='Field parameter value [default: %default]')
    parser.add_option('--UserID-field', dest='UserIDField',metavar='uint',type='int'
        ,help='Field parameter value [default: %default]')
    parser.add_option('--corner1_lon-field', dest='corner1_lonField',default=Decimal('181'),metavar='decimal',type='string'
        ,help='Field parameter value [default: %default]')
    parser.add_option('--corner1_lat-field', dest='corner1_latField',default=Decimal('181'),metavar='decimal',type='string'
        ,help='Field parameter value [default: %default]')
    parser.add_option('--corner2_lon-field', dest='corner2_lonField',default=Decimal('181'),metavar='decimal',type='string'
        ,help='Field parameter value [default: %default]')
    parser.add_option('--corner2_lat-field', dest='corner2_latField',default=Decimal('181'),metavar='decimal',type='string'
        ,help='Field parameter value [default: %default]')
    parser.add_option('--StationType-field', dest='StationTypeField',metavar='uint',type='int'
        ,help='Field parameter value [default: %default]')
    parser.add_option('--shipandcargo-field', dest='shipandcargoField',default=0,metavar='uint',type='int'
        ,help='Field parameter value [default: %default]')
    parser.add_option('--TxRxMode-field', dest='TxRxModeField',metavar='uint',type='int'
        ,help='Field parameter value [default: %default]')
    parser.add_option('--ReportingInterval-field', dest='ReportingIntervalField',metavar='uint',type='int'
        ,help='Field parameter value [default: %default]')
    parser.add_option('--QuietTime-field', dest='QuietTimeField',metavar='uint',type='int'
        ,help='Field parameter value [default: %default]')

def main():
    from optparse import OptionParser
    parser = OptionParser(usage="%prog [options]")

    parser.add_option('--unit-test',dest='unittest',default=False,action='store_true',
        help='run the unit tests')
    parser.add_option('-v','--verbose',dest='verbose',default=False,action='store_true',
        help='Make the test output verbose')

    # FIX: remove nmea from binary messages.  No way to build the whole packet?
    # FIX: or build the surrounding msg 8 for a broadcast?
    typeChoices = ('binary','nmeapayload','nmea') # FIX: what about a USCG type message?
    parser.add_option('-t', '--type', choices=typeChoices, type='choice',
        dest='ioType', default='nmeapayload',
        help='What kind of string to write for encoding ('+', '.join(typeChoices)+') [default: %default]')


    outputChoices = ('std','html','csv','sql' )
    parser.add_option('-T', '--output-type', choices=outputChoices,
        type='choice', dest='outputType', default='std',
        help='What kind of string to output ('+', '.join(outputChoices)+') '
        '[default: %default]')

    parser.add_option('-o','--output',dest='outputFileName',default=None,
        help='Name of the python file to write [default: stdout]')

    parser.add_option('-f', '--fields', dest='fieldList', default=None,
        action='append', choices=fieldList,
        help='Which fields to include in the output.  Currently only for csv '
        'output [default: all]')

    parser.add_option('-p', '--print-csv-field-list', dest='printCsvfieldList',
        default=False,action='store_true',
        help='Print the field name for csv')

    parser.add_option('-c', '--sql-create', dest='sqlCreate', default=False,
        action='store_true',
        help='Print out an sql create command for the table.')

    parser.add_option('--latex-table', dest='latexDefinitionTable',
        default=False,action='store_true',
        help='Print a LaTeX table of the type')

    parser.add_option('--text-table', dest='textDefinitionTable', default=False,
        action='store_true',
        help='Print delimited table of the type (for Word table importing)')

    parser.add_option('--delimt-text-table', dest='delimTextDefinitionTable',
        default='    ',
        help='Delimiter for text table [default: \'%default\'] '
        '(for Word table importing)')

    dbChoices = ('sqlite','postgres')
    parser.add_option('-D', '--db-type', dest='dbType', default='postgres',
        choices=dbChoices,type='choice',
        help='What kind of database ('+', '.join(dbChoices)+') '
        '[default: %default]')

    addMsgOptions(parser)

    options, args = parser.parse_args()

    if options.unittest:
            sys.argv = [sys.argv[0]]
            if options.verbose: sys.argv.append('-v')
            unittest.main()

    outfile = sys.stdout
    if None!=options.outputFileName:
            outfile = file(options.outputFileName,'w')


    if options.doEncode:
        # Make sure all non required options are specified.
        if None==options.RepeatIndicatorField: parser.error("missing value for RepeatIndicatorField")
        if None==options.UserIDField: parser.error("missing value for UserIDField")
        if None==options.corner1_lonField: parser.error("missing value for corner1_lonField")
        if None==options.corner1_latField: parser.error("missing value for corner1_latField")
        if None==options.corner2_lonField: parser.error("missing value for corner2_lonField")
        if None==options.corner2_latField: parser.error("missing value for corner2_latField")
        if None==options.StationTypeField: parser.error("missing value for StationTypeField")
        if None==options.shipandcargoField: parser.error("missing value for shipandcargoField")
        if None==options.TxRxModeField: parser.error("missing value for TxRxModeField")
        if None==options.ReportingIntervalField: parser.error("missing value for ReportingIntervalField")
        if None==options.QuietTimeField: parser.error("missing value for QuietTimeField")
    msgDict = {
        'MessageID': '23',
        'RepeatIndicator': options.RepeatIndicatorField,
        'UserID': options.UserIDField,
        'Spare': '0',
        'corner1_lon': options.corner1_lonField,
        'corner1_lat': options.corner1_latField,
        'corner2_lon': options.corner2_lonField,
        'corner2_lat': options.corner2_latField,
        'StationType': options.StationTypeField,
        'shipandcargo': options.shipandcargoField,
        'Spare2': '0',
        'TxRxMode': options.TxRxModeField,
        'ReportingInterval': options.ReportingIntervalField,
        'QuietTime': options.QuietTimeField,
        'Spare3': '0',
    }

    bits = encode(msgDict)
    if 'binary' == options.ioType:
        print str(bits)
    elif 'nmeapayload'==options.ioType:
        # FIX: figure out if this might be necessary at compile time
        bitLen=len(bits)
        if bitLen % 6 != 0:
            bits = bits + BitVector(size=(6 - (bitLen%6)))  # Pad out to multiple of 6
        print binary.bitvectoais6(bits)[0]

    # FIX: Do not emit this option for the binary message payloads.  Does not make sense.
    elif 'nmea' == options.ioType:
        nmea = uscg.create_nmea(bits)
        print nmea
    else:
        sys.exit('ERROR: unknown ioType.  Help!')


        if options.sqlCreate:
                sqlCreateStr(outfile,options.fieldList,dbType=options.dbType)

        if options.latexDefinitionTable:
                latexDefinitionTable(outfile)

        # For conversion to word tables
        if options.textDefinitionTable:
                textDefinitionTable(outfile,options.delimTextDefinitionTable)

        if options.printCsvfieldList:
                # Make a csv separated list of fields that will be displayed for csv
                if None == options.fieldList: options.fieldList = fieldList
                import StringIO
                buf = StringIO.StringIO()
                for field in options.fieldList:
                        buf.write(field+',')
                result = buf.getvalue()
                if result[-1] == ',': print result[:-1]
                else: print result

        if options.doDecode:
                if len(args)==0: args = sys.stdin
                for msg in args:
                        bv = None

                        if msg[0] in ('$','!') and msg[3:6] in ('VDM','VDO'):
                                # Found nmea
                                # FIX: do checksum
                                bv = binary.ais6tobitvec(msg.split(',')[5])
                        else: # either binary or nmeapayload... expect mostly nmeapayloads
                                # assumes that an all 0 and 1 string can not be a nmeapayload
                                binaryMsg=True
                                for c in msg:
                                        if c not in ('0','1'):
                                                binaryMsg=False
                                                break
                                if binaryMsg:
                                        bv = BitVector(bitstring=msg)
                                else: # nmeapayload
                                        bv = binary.ais6tobitvec(msg)

                        printFields(decode(bv)
                                    ,out=outfile
                                    ,format=options.outputType
                                    ,fieldList=options.fieldList
                                    ,dbType=options.dbType
                                    )

############################################################
if __name__=='__main__':
    main()
