def writeMessageFile() :
    
    global DEBUG_GEOMETRY_CONVERSION, appendFile, foundEmptySIDC, FORCE_UNIQUE_IDs

    try :
        arcpy.AddMessage("Starting: Write/Append Message File")

        # Get input feature class
        inputFC = arcpy.GetParameter(0)
        if (inputFC == "") or (inputFC is None):
            inputFC = os.path.join(MilitaryUtilities.geoDatabasePath, r"/test_inputs.gdb/FriendlyOperations/FriendlyUnits")
        desc = arcpy.Describe(inputFC)
        if desc == None :
            arcpy.AddError("Bad Input Feature Class")
            return

        shapeType = desc.shapeType
        
        # Get output filename
        outputFile = arcpy.GetParameterAsText(1)
        
        # Get standard
        standard = arcpy.GetParameterAsText(2)
        
        # Message Type Field
        messageTypeField = arcpy.GetParameterAsText(3)   
        
        # Sort Order 
        orderBy = arcpy.GetParameterAsText(4)       
        
        # Disable Geo Transformation and use default SIDC
        disableGeoTransform = arcpy.GetParameterAsText(5)
        if not ((disableGeoTransform == "") or (disableGeoTransform is None)) :
            DEBUG_GEOMETRY_CONVERSION = (disableGeoTransform.upper() == "TRUE")       

        arcpy.AddMessage("Running with Parameters:")
        arcpy.AddMessage("0 - Input FC: " + str(inputFC))
        arcpy.AddMessage("1 - outputXMLFile: " + str(outputFile))
        arcpy.AddMessage("2 - symbology standard: " + str(standard))        
        arcpy.AddMessage("3 - MessageTypeField: " + messageTypeField)
        arcpy.AddMessage("4 - orderBy: " + orderBy)
        arcpy.AddMessage("5 - disableGeoTransform: " + disableGeoTransform)
        
        # initialize the standard
        MilitaryUtilities.getGeometryConverterStandard(standard)
        
        if DEBUG_GEOMETRY_CONVERSION : 
            arcpy.AddWarning("Running in Debug Geo-Transformation Mode, symbol will use default/unknown SIDC for shape")
        
        if not ((messageTypeField == "") or (messageTypeField is None)) :
            # make sure the messageTypeField exists in the input
            if messageTypeField in [field.name for field in desc.Fields] :
                MilitaryUtilities.MessageTypeField = messageTypeField
            else :
                arcpy.AddWarning("MessageTypeField does not exist in input: " + messageTypeField + " , using default")
        
        # Check Output Filename & see handle case if we are appending
        if (outputFile == "") or (outputFile is None) :
            # For a standalone test (debug) if no output filename provided
            if DEBUG_GEOMETRY_CONVERSION : 
                defaultOutputName = "Mil2525CMessages-NoTransform.xml"
            else : 
                defaultOutputName = "Mil2525CMessages.xml"   
            outputFile = os.path.join(os.path.dirname(__file__), defaultOutputName)  
            messageFile=open(outputFile, "w")
            arcpy.AddWarning("No Output set, using default: " + str(outputFile))
        else:            
            arcpy.AddMessage("Append File set to " + str(appendFile))
            if (not appendFile) :
                messageFile = open(outputFile, "w")
            elif (not os.path.isfile(outputFile)) :
                arcpy.AddWarning("Can't Append: Output File does not exist, creating new file")
                messageFile = open(outputFile, "w")                
            else :
                arcpy.AddMessage("Appending Existing File...")
                
                # Appending the file is a bit more complicated because we have to remove the 
                # "</messages>" from the end of the original file therefore it can't just be 
                # opened as an append "a+"-we have to create a temp file, read the original file in,
                # except for the line "</messages>", and then write back out
                
                fileToAppend = open(outputFile, "r")
                # Workaround/Note: didn't work in ArcCatalog unless I opened temp file this way
                temporaryFile = tempfile.NamedTemporaryFile(mode="w", delete=False)

                # Copy the file line by line, but don't include last end tag ex. </messages>
                finalTag = "</%s>" % MilitaryUtilities.getMessageRootTag()
                finalTagFound = False
                while True:
                    line = fileToAppend.readline()
                    if line : 
                        if not finalTag in line :  # ex. "</messages>"
                            temporaryFile.write(line)
                        else :
                            finalTagFound = True
                    else :
                        break

                if (not finalTagFound) : 
                    arcpy.AddError("XML Append File will be corrupt: Could not find Tag: " + finalTag)
                    
                # now write those lines back
                fileToAppend.close()
                temporaryFile.close()
                messageFile = open(outputFile, "w")
                temporaryFile = open(temporaryFile.name, "r")
                while True:
                    line = temporaryFile.readline()
                    if line : 
                        messageFile.write(line)
                    else :
                        break

                temporaryFile.close()

        if (messageFile is None) : 
            arcpy.AddError("Output file can't be created, exiting")
            return
        
        ##################Setup for export############################

        # We need to set overwriteOutput=true or the tools below may fail
        previousOverwriteOutputSetting = arcpy.env.overwriteOutput
        arcpy.env.overwriteOutput = True
        
        # Densify if this is a polygon FC
        if ("Polygon" == shapeType):
            try : 
                densifiedFC = "in_memory/DensifiedFC"
                arcpy.CopyFeatures_management(inputFC, densifiedFC)
                arcpy.Densify_edit(densifiedFC, "ANGLE", "", "", 10)
                inputFC = densifiedFC
            except :
                arcpy.AddWarning("Could not densify polygons, skipping. Densify_edit tool failed - is Desktop Standard License available?")
              
        # Get fields and coded domains
        CODE_FIELD_NAME = "code"
        DESCRIPTION_FIELD_NAME = "description"
        fieldNameList = []
        fieldNameToDomainName = {}
        for field in desc.Fields:
            if not (field.name in DictionaryConstants.MILFEATURES_FIELD_EXCLUDE_LIST):
                fieldNameList.append(field.name)
                # Get domain if any
                if (field.domain is not None and field.domain != ""):
                    fieldNameToDomainName[field.name] = field.domain
                    dataPath = desc.path
                    gdbPath = dataPath.split(".gdb")[0]
                    gdbPath += ".gdb"
                    arcpy.DomainToTable_management(gdbPath, field.domain, "in_memory/" + field.domain, CODE_FIELD_NAME, DESCRIPTION_FIELD_NAME)

        # print fieldNameList

        # restore this setting (set above)
        arcpy.env.overwriteOutput = previousOverwriteOutputSetting
        
        # Projected or geographic?
        xname = "lon"
        yname = "lat"
        isProjected = desc.spatialReference.type == "Projected"
        if (isProjected):
            xname = "x"
            yname = "y"
        wkid = desc.spatialReference.factoryCode

        ################Begin Export ##########################

        # Open a search cursor (if possible)
        try :            
            rows = arcpy.SearchCursor(inputFC, "", "", "", orderBy)            
        except :            
            arcpy.AddError("Could not open Feature Class " + str(inputFC))
            if (not ((orderBy == "") and not (orderBy is None))) :
                arcpy.AddError("OrderBy Search Option: " + orderBy)
            raise Exception("Bad Feature Class Input")             

        # Dictionary to map unique designation to ID
        unitDesignationToId = dict()
        
        featureFields = desc.fields

        ###################### Write XML file #########################

        if not appendFile :
            # Ex: Next line writes: messageFile.write("<geomessages>\n") 
            messageFile.write("<%s>\n" % MilitaryUtilities.getMessageRootTag())            
            
        rowCount = 0

        # Iterate through the rows in the cursor
        for row in rows:
            shape = row.shape.getPart(0)
    
            arcpy.AddMessage("Processing row: " + str(rowCount))
            
            ##############################################
            # Map Unique Names to same Unique IDs
            # IMPORTANT: this section tries to keep Unique Designations mapped to the 
            #            same Message Unique ID (so they will move in Message Processor), so...
            # WARNING: if you have repeated Unique Designations,
            #            they are going to get mapped to the same Unique ID             
            uniqueId = "{%s}" % str(uuid.uuid4())
            uniqueDesignation = str(rowCount) # fallback value in case field does not exist            
            
            try :
                uniqueDesignation = row.getValue(MilitaryUtilities.UniqueDesignationField)
 
                if ((uniqueDesignation is None) or (uniqueDesignation == "")) :
                    arcpy.AddWarning("Unique Designation is Empty")                     
                elif (DEBUG_GEOMETRY_CONVERSION or FORCE_UNIQUE_IDs) :                   
                    pass 
                else :   
                    # Otherwise, see if we have seen this Designation before
                    if (uniqueDesignation in unitDesignationToId):
                        arcpy.AddMessage("Creating update message for repeated Unique Designation: " + uniqueDesignation)
                        uniqueId = unitDesignationToId[uniqueDesignation]
                    else:
                        unitDesignationToId[uniqueDesignation] = uniqueId
            except:
                arcpy.AddWarning("Could not find Unique Designation field in row: " + str(rowCount))                                    
            ##############################################

            # work with "sidc" or "sic"
            try : 
                SymbolIdCodeVal = row.getValue(MilitaryUtilities.SidcFieldChoice1) # "sic"
            except:
                try : 
                    SymbolIdCodeVal = row.getValue(MilitaryUtilities.SidcFieldChoice2) # "sidc"
                except:     
                    SymbolIdCodeVal = None                

            # Note/Important: attributes need to be set in converter so needs declared before geometrytoControlPoints
            attributes = { } 
            conversionNotes = None
            attributes[DictionaryConstants.Tag_Wkid] = wkid  # needed by conversion
                                  
            if (SymbolIdCodeVal is None) or (SymbolIdCodeVal == "") : 
                SymbolIdCodeVal = DictionaryConstants.getDefaultSidcForShapeType(shapeType)
                if not (DEBUG_GEOMETRY_CONVERSION) :
                    foundEmptySIDC = True
                    msg =  "SIDC is not set, using default: " + SymbolIdCodeVal
                    arcpy.AddWarning(msg)
            elif DEBUG_GEOMETRY_CONVERSION :
                print "Using Debug SIDC"
                conversionNotes = "Original SIDC: " + SymbolIdCodeVal
                uniqueDesignation = SymbolIdCodeVal # use this label for debugging
                SymbolIdCodeVal = DictionaryConstants.getDefaultSidcForShapeType(shapeType)

            controlPointsString = MilitaryUtilities.parseGeometryToControlPoints(shape)
            requiresConversion = MilitaryUtilities.geoConverter.requiresConversion(SymbolIdCodeVal)
            if requiresConversion and not DEBUG_GEOMETRY_CONVERSION :                
                msg = "SIC: " + SymbolIdCodeVal + " requires conversion/translation"
                print msg
                arcpy.AddMessage(msg)
                transformedPoints, conversionNotes = \
                    MilitaryUtilities.geoConverter.geometrytoControlPoints(SymbolIdCodeVal, controlPointsString, attributes)                
                if (conversionNotes == DictionaryConstants.CONVERSION_IGNORE_SECOND_LINE) : 
                    continue
                elif (transformedPoints is None) :
                    arcpy.AddWarning("Conversion FAILED for SIC: " + SymbolIdCodeVal + \
                                     ", Notes: " + conversionNotes + " (using original points)")
                else :
                    controlPointsString = transformedPoints

            # Write Output Message
            # Ex: Next line writes: ex. "\t<geomessage v=\"1.0\">\n"            
            messageFile.write("\t<%s v=\"%s\">\n" % (MilitaryUtilities.getMessageTag(), \
                                                     MilitaryUtilities.getMessageVersion()))
            
            messageFile.write("\t\t<sic>%s</sic>\n" % SymbolIdCodeVal) 

            # Try to get a message type if the field exists
            try :   
                messageTypeVal = row.getValue(MilitaryUtilities.MessageTypeField)           
                messageFile.write("\t\t<_type>%s</_type>\n" % messageTypeVal)
            except :             
                # if not default to position_report
                messageFile.write("\t\t<_type>%s</_type>\n" % DictionaryConstants.DefaultMessageType)       
                                 
            ##TODO: see if other actions are valid besides just "update"
            messageFile.write("\t\t<_action>%s</_action>\n" % DictionaryConstants.DefaultMessageAction) # = update
            
            messageFile.write("\t\t<_id>%s</_id>\n" % uniqueId) 
            messageFile.write("\t\t<_control_points>%s</_control_points>\n" % controlPointsString)  
            if not ((conversionNotes is None) or (conversionNotes == "")) : 
                messageFile.write("\t\t<ConversionNotes>%s</ConversionNotes>\n" % conversionNotes)

            # Note: written with attributes below: messageFile.write("\t\t<_wkid>%i</_wkid>\n" % wkid)
                     
            if not ((uniqueDesignation is None) or (uniqueDesignation == "")) : 
                messageFile.write("\t\t<%s>%s</%s>\n" % (DictionaryConstants.Tag_UniqueDesignation, \
                             uniqueDesignation, DictionaryConstants.Tag_UniqueDesignation))
                     

            # Check on Military Geometries for Lines/Areas
            if (shapeType is "Point"):
                messageFile.write("\t\t<altitude_depth>%d</altitude_depth>\n" % shape.Z)

            rowCount = rowCount + 1
            messageFile.write("\t\t<MessageCount>%s</MessageCount>\n" % str(rowCount))             

            for key in attributes :
                attrValAsString = str(attributes[key])
                messageFile.write("\t\t<"+key+">" + attrValAsString + "</" + key + ">\n")

            ###################Common Fields/Attributes#####################
            
            # Write out remaining table fields as Tag attributes
            for field in fieldNameList:
                try : 
                    # But don't repeat existing tags we've created
                    if field in DictionaryConstants.MESSAGES_TAG_LIST :
                        rowVal = None 
                    else :
                        rowVal = row.getValue(field)
                except :
                    print "Could not get row val for field" + field
                    rowVal = None
                    
                if rowVal is not None:
                    try:
						fieldValAsString = str(row.getValue(field))
						messageFile.write("\t\t<"+field+">" + fieldValAsString + "</" + field + ">\n")
                    except:
                        #fixed issue #19
						fieldValAsString = row.getValue(field)
						decodedstring = fieldValAsString.encode('ascii', 'ignore')
						arcpy.AddMessage("trying to fix unicode problem, changing " + fieldValAsString + " -> " + decodedstring)
						messageFile.write("\t\t<"+field+">" + decodedstring + "</" + field + ">\n")
						
            ###################Common Fields/Attributes#####################

            # Ex: messageFile.write("\t</geomessage>\n")
            messageFile.write("\t</%s>\n" % MilitaryUtilities.getMessageTag())

        # Ex: messageFile.write("</geomessages>")
        messageFile.write("</%s>\n" % MilitaryUtilities.getMessageRootTag())
            
        arcpy.AddMessage("Rows Processed: " + str(rowCount))   
        if foundEmptySIDC :
            arcpy.AddWarning("IMPORTANT: Some rows did not have SIDC set - you may need to run CalcSIDCField tool first.")
        arcpy.AddMessage("Write/Append Message File Complete")
        
    except: 
        print "Exception: " 
        tb = traceback.format_exc()
        print tb
        arcpy.AddError("Exception")
        arcpy.AddError(tb)
                    # affiliationChar = symbolname[-1:]
                    #     symbolname = symbolname[:-2]       # Trim the F, H, U, N from the symbol name
                    #else :
                    #    affiliationChar = ''
            if (EchelonField in updatefields and row[2] is not None):
            ## TODO - this needs more testing (and moved to SymbolDictionary)
                echelonString = row[2]
                if (EchelonField in fieldNameToDomainName):
                    domain = fieldNameToDomainName[EchelonField]
                    whereClause = "%s = %s" % (CODE_FIELD_NAME, row[2])
                    domainRows = arcpy.SearchCursor("in_memory/" + domain, whereClause)
                    for domainRow in domainRows:
                        echelonString = domainRow.getValue(DESCRIPTION_FIELD_NAME)
                        echelonString = echelonString.upper()

            expectedGeometry = DictionaryConstants.getGeometryStringFromShapeType(desc.shapeType)
                        
# sidc = MilitaryUtilities.symbolDictionary.SymbolNametoSymbolIDExt(symbolname, echelonString, affiliation, expectedGeometry)
            sidc = symbolDictionary.SymbolNametoSymbolIDExt(symbolname, echelonString, affiliation, expectedGeometry)
            
# validSic = MilitaryUtilities.symbolDictionary.isValidSidc(sidc)
            validSic = symbolDictionary.isValidSidc(sidc)

            if not validSic :
                # this should not happen, but final check
                defaultSidc = DictionaryConstants.getDefaultSidcForShapeType(desc.shapeType)
                print "Invalid Sic Code: " + sidc + ", using default: " + defaultSidc
                sidc = defaultSidc

            #if len(affiliationChar) == 1 :
            #    row[0] = val[0] + affiliationChar + val[2:15]
def writeFeaturesFromMessageFile() :

    foundEmptyRuleId = False  # used to detect if we can not set a RuleID for any rows

    # Get the input message file
    inputFileName = arcpy.GetParameterAsText(0)
    if (inputFileName == "") or (inputFileName is None):
        inputFileName = os.path.join(MilitaryUtilities.dataPath, r"/messages/Mil2525CMessages.xml")
                
    if not os.path.isfile(inputFileName) :
        arcpy.AddError("Bad Input File: " + inputFileName)
        return

    inputFile=open(inputFileName, "r")
    if (inputFile is None) : 
        arcpy.AddError("Input file can't be opened, exiting")
        return
        
    # Get the output feature class
    outputFC = arcpy.GetParameter(1)
    if (outputFC == "") or (outputFC is None):
        outputFC = os.path.join(MilitaryUtilities.dataPath, r"/test_outputs.gdb/FriendlyOperations/FriendlyUnits")
        
    desc = arcpy.Describe(outputFC)
    if desc is None :
        arcpy.AddError("Can't open Output Dataset: " + str(outputFC)) 
        return

    shapeType = desc.shapeType

    # Get standard
    standard = arcpy.GetParameterAsText(2)
        
    # Message Type Field
    messageTypeField = arcpy.GetParameterAsText(3)            

    arcpy.AddMessage("Running with Parameters:")
    arcpy.AddMessage("0 - input XML File: " + str(inputFileName))
    arcpy.AddMessage("1 - output FC: " + str(outputFC))
    arcpy.AddMessage("2 - symbology standard: " + str(standard))        
    arcpy.AddMessage("3 - MessageTypeField: " + messageTypeField)
        
    if not ((messageTypeField == "") or (messageTypeField is None)) :
        if desc.Fields.contains(messageTypeField) :
            MilitaryUtilities.MessageTypeField = messageTypeField
        else :
            arcpy.AddWarning("MessageTypeField does not exist in output: " + MessageTypeField + " , using default")

    print "Exporting message objects from: " + str(inputFileName)
    print "To Feature Class: " + str(outputFC)
    print "That match shape type: " + shapeType

    # initialize the standard
    MilitaryUtilities.getGeometryConverterStandard(standard)
        
    ruleFieldName = MilitaryUtilities.symbolDictionary.initializeRulesByMilitaryFeatures(outputFC) 

    if (ruleFieldName == "") or (ruleFieldName is None) :
        arcpy.AddError("RuleFieldName not found, exiting")
        return

    # Projected or geographic?
    xname = "lon"
    yname = "lat"
    isProjected = desc.spatialReference.type == "Projected"
    if (isProjected):
        xname = "x"
        yname = "y"
    outputWkid = desc.spatialReference.factoryCode

    ################Begin Export ##########################
    
    featureFields = desc.fields

    # Iterate through the messages and check the shape
    WRITE_OUTPUT = True # debug switch when output not needed
    newRow = None
    newRows = None

    try : 

        if WRITE_OUTPUT : 
            newRows = arcpy.InsertCursor(outputFC)
        messageCount = 0

        # for each message in the message file, get its attributes and copy to the output FeatureClass
        for sic, controlPoints, attributes in MessageIterator.MessageIterator(inputFileName) :
            print sic, controlPoints, attributes

            geoType = MilitaryUtilities.geoConverter.expectedGeometryType(sic)
            if not DictionaryConstants.isCorrectShapeTypeForFeature(geoType, shapeType) : 
                skipMsg = "Skipping SIC: " + sic + " - does not match feature type" + shapeType
                arcpy.AddMessage(skipMsg)
                continue

            # Used for those SICs that map to 2 lines (ex. Task Screen/Guard/Cover)
            repeatForPairFeatures = True
            repeatCount = 0

            while repeatForPairFeatures :

                outputPointList, conversionNotes = MilitaryUtilities.geoConverter.controlPointsToGeometry(sic, controlPoints, attributes)
                if outputPointList is None :
                    msg = "Failed to Convert Points from Military to MilFeature format for SIDC: " + sic
                    arcpy.AddError(msg)
                    arcpy.AddError("Conversion Notes: " + conversionNotes)
                    repeatForPairFeatures = False
                    continue

                inputWkid = 0
                if attributes.has_key(DictionaryConstants.Tag_Wkid) :
                    inputWkid = int(attributes[DictionaryConstants.Tag_Wkid])

                if outputWkid != inputWkid :
                    msg = "ERROR: Input Message and Output Feature WKIDs do not match (InsertFeature will fail)"
                    arcpy.AddError(msg)
                    msg = "Output WKID = " + str(outputWkid) + " , Input WKID = " + str(inputWkid)
                    arcpy.AddError(msg)

                ruleId, symbolName = MilitaryUtilities.symbolDictionary.symbolIdToRuleId(sic)

                if ruleId < 0 :
                    foundEmptyRuleId = True
                    # arcpy.AddWarning("WARNING: Could not map ruleId to SIDC: " + sic)

                # For those SIC that map to 2 lines (ex. Task Screen/Guard/Cover)
                # will need to clone/repeat the message here for Left/Right Upper/Lower pair
                repeatForPairFeatures = False 
                geoConversion = MilitaryUtilities.symbolDictionary.symbolIdToGeometryConversionType(sic)
                if (geoConversion == DictionaryConstants.GCT_TWOLINE) or \
                    (geoConversion == DictionaryConstants.GCT_TWOLINE3OR4PT) :
                    if repeatCount > 0 : 
                        repeatForPairFeatures = False # Only do once
                        ## TODO: find better way to set rule Id for 2nd line (Left/Right) version
                        # This is quite kludgy, and relies on the 2nd ruleid code being the 1st + 1
                        # and this may not always be the case
                        ruleId = ruleId + 1
                    else : 
                        repeatForPairFeatures = True 
                        attributes[DictionaryConstants.Tag_TwoLinesNeeded] = "True"
                        # don't let id get repeated, so append "_2"
                        if attributes.has_key(DictionaryConstants.Tag_Id) : 
                            attributes[DictionaryConstants.Tag_Id] = attributes[DictionaryConstants.Tag_Id] + "_2"
                repeatCount = repeatCount + 1

                arcpy.AddMessage("Adding feature #" + str(messageCount) + " with SIDC: " + sic)
                if WRITE_OUTPUT : 
                    try : 
                        shape = MilitaryUtilities.pointsToArcPyGeometry(outputPointList, shapeType)
                        newRow = newRows.newRow()
                        newRow.setValue(desc.shapeFieldName, shape)
                        newRow.setValue(ruleFieldName, ruleId)
                        
                        # both "sic" and "sidc" used
                        try : 
                            newRow.setValue("sic", sic)
                        except :
                            try :                             
                                newRow.setValue("sidc", sic)
                            except : 
                                arcpy.AddWarning("Failed to set SIDC field in output")
                            
                        # add any extra fields
                        for field in featureFields :  
                            if not (field.name in DictionaryConstants.MILFEATURES_FIELD_EXCLUDE_LIST) :
                                lowerFieldName = field.name.lower()
                                # we don't the case of the attribute so have to search
                                for key in attributes.keys() :                                     
                                    lowerKey = key.lower() 
                                    if (lowerKey == lowerFieldName) :
                                        try : 
                                            newRow.setValue(field.name, attributes[key])
                                        except : 
                                            print "Could not add: Field: " + field.name + ", Value: " + str(attributes[key])

                        newRows.insertRow(newRow) 
                        arcpy.AddMessage("Message successfully added: " + str(messageCount))
                    except : 
                        arcpy.AddError("ERROR: Exception while adding new feature (does Spatial Ref match?)")
                        tb = traceback.format_exc()
                        print tb
                else :
                    print "WRITING OUTPUT:"
                    print "SIC: " + sic + ", Name: " + symbolName                
                    print "Adding geometry to feature, with points: "
                    for point in outputPointList : 
                        x = point.split(',')[0]
                        y = point.split(',')[1]
                        print "(", x, ",", y, ")"                                     
                
            messageCount += 1
            
        if messageCount == 0 :
            arcpy.AddWarning("No Messages Found in Input")

        if foundEmptyRuleId :
            arcpy.AddWarning("IMPORTANT: Some rows do not have Symbol RuleId set - you may need to run CalcRepRuleField tool.")            
           
    except :
        tb = traceback.format_exc()
        arcpy.AddError("Exception:")
        arcpy.AddError(tb)        

    finally :
        # Delete cursor and row objects to remove locks on the data 
        if not newRow is None : 
            del newRow 
        if not newRows is None : 
            del newRows
Beispiel #4
0
def writeMessageFile():

    global DEBUG_GEOMETRY_CONVERSION, appendFile, foundEmptySIDC, FORCE_UNIQUE_IDs

    try:
        arcpy.AddMessage("Starting: Write/Append Message File")

        # Get input feature class
        inputFC = arcpy.GetParameter(0)
        if (inputFC == "") or (inputFC is None):
            inputFC = os.path.join(
                MilitaryUtilities.dataPath,
                r"/test_inputs.gdb/FriendlyOperations/FriendlyUnits")
        desc = arcpy.Describe(inputFC)
        if desc is None:
            arcpy.AddError("Bad Input Feature Class")
            return

        shapeType = desc.shapeType

        # Get output filename
        outputFile = arcpy.GetParameterAsText(1)

        # Get standard
        standard = arcpy.GetParameterAsText(2)

        # Message Type Field
        messageTypeField = arcpy.GetParameterAsText(3)

        # Sort Order
        orderBy = arcpy.GetParameterAsText(4)

        # Disable Geo Transformation and use default SIDC
        disableGeoTransform = arcpy.GetParameterAsText(5)
        if not ((disableGeoTransform == "") or (disableGeoTransform is None)):
            DEBUG_GEOMETRY_CONVERSION = (disableGeoTransform.upper() == "TRUE")

        arcpy.AddMessage("Running with Parameters:")
        arcpy.AddMessage("0 - Input FC: " + str(inputFC))
        arcpy.AddMessage("1 - outputXMLFile: " + str(outputFile))
        arcpy.AddMessage("2 - symbology standard: " + str(standard))
        arcpy.AddMessage("3 - MessageTypeField: " + messageTypeField)
        arcpy.AddMessage("4 - orderBy: " + orderBy)
        arcpy.AddMessage("5 - disableGeoTransform: " + disableGeoTransform)

        # initialize the standard
        MilitaryUtilities.getGeometryConverterStandard(standard)

        if DEBUG_GEOMETRY_CONVERSION:
            arcpy.AddWarning(
                "Running in Debug Geo-Transformation Mode, symbol will use default/unknown SIDC for shape"
            )

        if not ((messageTypeField == "") or (messageTypeField is None)):
            # make sure the messageTypeField exists in the input
            if messageTypeField in [field.name for field in desc.Fields]:
                MilitaryUtilities.MessageTypeField = messageTypeField
            else:
                arcpy.AddWarning("MessageTypeField does not exist in input: " +
                                 messageTypeField + " , using default")

        # Check Output Filename & see handle case if we are appending
        if (outputFile == "") or (outputFile is None):
            # For a standalone test (debug) if no output filename provided
            if DEBUG_GEOMETRY_CONVERSION:
                defaultOutputName = "Mil2525CMessages-NoTransform.xml"
            else:
                defaultOutputName = "Mil2525CMessages.xml"
            outputFile = os.path.join(os.path.dirname(__file__),
                                      defaultOutputName)
            messageFile = open(outputFile, "w")
            arcpy.AddWarning("No Output set, using default: " +
                             str(outputFile))
        else:
            arcpy.AddMessage("Append File set to " + str(appendFile))
            if (not appendFile):
                messageFile = open(outputFile, "w")
            elif (not os.path.isfile(outputFile)):
                arcpy.AddWarning(
                    "Can't Append: Output File does not exist, creating new file"
                )
                messageFile = open(outputFile, "w")
            else:
                arcpy.AddMessage("Appending Existing File...")

                # Appending the file is a bit more complicated because we have to remove the
                # "</messages>" from the end of the original file therefore it can't just be
                # opened as an append "a+"-we have to create a temp file, read the original file in,
                # except for the line "</messages>", and then write back out

                fileToAppend = open(outputFile, "r")
                # Workaround/Note: didn't work in ArcCatalog unless I opened temp file this way
                temporaryFile = tempfile.NamedTemporaryFile(mode="w",
                                                            delete=False)

                # Copy the file line by line, but don't include last end tag ex. </messages>
                finalTag = "</%s>" % MilitaryUtilities.getMessageRootTag()
                finalTagFound = False
                while True:
                    line = fileToAppend.readline()
                    if line:
                        if not finalTag in line:  # ex. "</messages>"
                            temporaryFile.write(line)
                        else:
                            finalTagFound = True
                    else:
                        break

                if (not finalTagFound):
                    arcpy.AddError(
                        "XML Append File will be corrupt: Could not find Tag: "
                        + finalTag)

                # now write those lines back
                fileToAppend.close()
                temporaryFile.close()
                messageFile = open(outputFile, "w")
                temporaryFile = open(temporaryFile.name, "r")
                while True:
                    line = temporaryFile.readline()
                    if line:
                        messageFile.write(line)
                    else:
                        break

                temporaryFile.close()

        if (messageFile is None):
            arcpy.AddError("Output file can't be created, exiting")
            return

        ##################Setup for export############################

        # We need to set overwriteOutput=true or the tools below may fail
        previousOverwriteOutputSetting = arcpy.env.overwriteOutput
        arcpy.env.overwriteOutput = True

        # Densify if this is a polygon FC
        if (shapeType == "Polygon"):
            try:
                densifiedFC = "in_memory/DensifiedFC"
                arcpy.CopyFeatures_management(inputFC, densifiedFC)
                arcpy.Densify_edit(densifiedFC, "ANGLE", "", "", 10)
                inputFC = densifiedFC
            except:
                arcpy.AddWarning(
                    "Could not densify polygons, skipping. Densify_edit tool failed - is Desktop Standard License available?"
                )

        # Get fields and coded domains
        CODE_FIELD_NAME = "code"
        DESCRIPTION_FIELD_NAME = "description"
        fieldNameList = []
        fieldNameToDomainName = {}
        for field in desc.Fields:
            if not (field.name
                    in DictionaryConstants.MILFEATURES_FIELD_EXCLUDE_LIST):
                fieldNameList.append(field.name)
                # Get domain if any
                if (field.domain is not None and field.domain != ""):
                    fieldNameToDomainName[field.name] = field.domain
                    dataPath = desc.path
                    gdbPath = dataPath.split(".gdb")[0]
                    gdbPath += ".gdb"
                    arcpy.DomainToTable_management(gdbPath, field.domain,
                                                   "in_memory/" + field.domain,
                                                   CODE_FIELD_NAME,
                                                   DESCRIPTION_FIELD_NAME)

        # print fieldNameList

        # restore this setting (set above)
        arcpy.env.overwriteOutput = previousOverwriteOutputSetting

        # Projected or geographic?
        xname = "lon"
        yname = "lat"
        isProjected = desc.spatialReference.type == "Projected"
        if (isProjected):
            xname = "x"
            yname = "y"
        wkid = desc.spatialReference.factoryCode

        ################Begin Export ##########################

        # Open a search cursor (if possible)
        try:
            rows = arcpy.SearchCursor(inputFC, "", "", "", orderBy)
        except:
            arcpy.AddError("Could not open Feature Class " + str(inputFC))
            if (not ((orderBy == "") and not (orderBy is None))):
                arcpy.AddError("OrderBy Search Option: " + orderBy)
            raise Exception("Bad Feature Class Input")

        # Dictionary to map unique designation to ID
        unitDesignationToId = dict()

        featureFields = desc.fields

        ###################### Write XML file #########################

        if not appendFile:
            # Ex: Next line writes: messageFile.write("<geomessages>\n")
            messageFile.write("<%s>\n" % MilitaryUtilities.getMessageRootTag())

        rowCount = 0

        # Iterate through the rows in the cursor
        for row in rows:
            shape = row.shape.getPart(0)

            arcpy.AddMessage("Processing row: " + str(rowCount))

            ##############################################
            # Map Unique Names to same Unique IDs
            # IMPORTANT: this section tries to keep Unique Designations mapped to the
            #            same Message Unique ID (so they will move in Message Processor), so...
            # WARNING: if you have repeated Unique Designations,
            #            they are going to get mapped to the same Unique ID
            uniqueId = "{%s}" % str(uuid.uuid4())
            uniqueDesignation = str(
                rowCount)  # fallback value in case field does not exist

            try:
                uniqueDesignation = row.getValue(
                    MilitaryUtilities.UniqueDesignationField)

                if ((uniqueDesignation is None) or (uniqueDesignation == "")):
                    arcpy.AddWarning("Unique Designation is Empty")
                elif (DEBUG_GEOMETRY_CONVERSION or FORCE_UNIQUE_IDs):
                    pass
                else:
                    # Otherwise, see if we have seen this Designation before
                    if (uniqueDesignation in unitDesignationToId):
                        arcpy.AddMessage(
                            "Creating update message for repeated Unique Designation: "
                            + uniqueDesignation)
                        uniqueId = unitDesignationToId[uniqueDesignation]
                    else:
                        unitDesignationToId[uniqueDesignation] = uniqueId
            except:
                arcpy.AddWarning(
                    "Could not find Unique Designation field in row: " +
                    str(rowCount))
            ##############################################

            # work with "sidc" or "sic"
            try:
                SymbolIdCodeVal = row.getValue(
                    MilitaryUtilities.SidcFieldChoice1)  # "sic"
            except:
                try:
                    SymbolIdCodeVal = row.getValue(
                        MilitaryUtilities.SidcFieldChoice2)  # "sidc"
                except:
                    SymbolIdCodeVal = None

            # Note/Important: attributes need to be set in converter so needs declared before geometrytoControlPoints
            attributes = {}
            conversionNotes = None
            attributes[
                DictionaryConstants.Tag_Wkid] = wkid  # needed by conversion

            if (SymbolIdCodeVal is None) or (SymbolIdCodeVal == ""):
                SymbolIdCodeVal = DictionaryConstants.getDefaultSidcForShapeType(
                    shapeType)
                if not (DEBUG_GEOMETRY_CONVERSION):
                    foundEmptySIDC = True
                    msg = "SIDC is not set, using default: " + SymbolIdCodeVal
                    arcpy.AddWarning(msg)
            # TODO: we may need to add an option to Disable the geometry conversion
            # *but* not to change the SIDC to the default one, if you don't want the SIDC to change
            # when "Disable Geometry Conversion" is checked, comment/uncomment thses lines to
            # set this to false/disable this behavior:
            # elif False :
            elif DEBUG_GEOMETRY_CONVERSION:
                print "Using Debug SIDC"
                conversionNotes = "Original SIDC: " + SymbolIdCodeVal
                uniqueDesignation = SymbolIdCodeVal  # use this label for debugging
                SymbolIdCodeVal = DictionaryConstants.getDefaultSidcForShapeType(
                    shapeType)

            controlPointsString = MilitaryUtilities.parseGeometryToControlPoints(
                shape)
            requiresConversion = MilitaryUtilities.geoConverter.requiresConversion(
                SymbolIdCodeVal)
            if requiresConversion and not DEBUG_GEOMETRY_CONVERSION:
                msg = "SIC: " + SymbolIdCodeVal + " requires conversion/translation"
                print msg
                arcpy.AddMessage(msg)
                transformedPoints, conversionNotes = \
                    MilitaryUtilities.geoConverter.geometrytoControlPoints(SymbolIdCodeVal, controlPointsString, attributes)
                if (conversionNotes ==
                        DictionaryConstants.CONVERSION_IGNORE_SECOND_LINE):
                    continue
                elif (transformedPoints is None):
                    arcpy.AddWarning("Conversion FAILED for SIC: " + SymbolIdCodeVal + \
                                     ", Notes: " + conversionNotes + " (using original points)")
                else:
                    controlPointsString = transformedPoints

            # Write Output Message
            # Ex: Next line writes: ex. "\t<geomessage v=\"1.0\">\n"
            messageFile.write("\t<%s v=\"%s\">\n" % (MilitaryUtilities.getMessageTag(), \
                                                     MilitaryUtilities.getMessageVersion()))

            messageFile.write("\t\t<sic>%s</sic>\n" % SymbolIdCodeVal)

            # Try to get a message type if the field exists
            try:
                messageTypeVal = row.getValue(
                    MilitaryUtilities.MessageTypeField)
                messageFile.write("\t\t<_type>%s</_type>\n" % messageTypeVal)
            except:
                # if not default to position_report
                messageFile.write("\t\t<_type>%s</_type>\n" %
                                  DictionaryConstants.DefaultMessageType)

            ##TODO: see if other actions are valid besides just "update"
            messageFile.write(
                "\t\t<_action>%s</_action>\n" %
                DictionaryConstants.DefaultMessageAction)  # = update

            messageFile.write("\t\t<_id>%s</_id>\n" % uniqueId)
            messageFile.write("\t\t<_control_points>%s</_control_points>\n" %
                              controlPointsString)
            if not ((conversionNotes is None) or (conversionNotes == "")):
                messageFile.write(
                    "\t\t<ConversionNotes>%s</ConversionNotes>\n" %
                    conversionNotes)

            # Note: written with attributes below: messageFile.write("\t\t<_wkid>%i</_wkid>\n" % wkid)

            if not ((uniqueDesignation is None) or (uniqueDesignation == "")):
                messageFile.write("\t\t<%s>%s</%s>\n" % (DictionaryConstants.Tag_UniqueDesignation, \
                             uniqueDesignation, DictionaryConstants.Tag_UniqueDesignation))

            # Check on Military Geometries for Lines/Areas
            if (shapeType is "Point"):
                messageFile.write("\t\t<altitude_depth>%d</altitude_depth>\n" %
                                  shape.Z)

            rowCount = rowCount + 1
            messageFile.write("\t\t<MessageCount>%s</MessageCount>\n" %
                              str(rowCount))

            for key in attributes:
                attrValAsString = str(attributes[key])
                messageFile.write("\t\t<" + key + ">" + attrValAsString +
                                  "</" + key + ">\n")

            ###################Common Fields/Attributes#####################

            # Write out remaining table fields as Tag attributes
            for field in fieldNameList:
                try:
                    # But don't repeat existing tags we've created
                    if field in DictionaryConstants.MESSAGES_TAG_LIST:
                        rowVal = None
                    else:
                        rowVal = row.getValue(field)
                except:
                    print "Could not get row val for field" + field
                    rowVal = None

                if (rowVal is not None) and (rowVal != ''):
                    try:
                        fieldValAsString = str(row.getValue(field))
                        messageFile.write("\t\t<" + field + ">" +
                                          fieldValAsString + "</" + field +
                                          ">\n")
                    except:
                        #fixed issue #19
                        fieldValAsString = row.getValue(field)
                        decodedstring = fieldValAsString.encode(
                            'ascii', 'ignore')
                        arcpy.AddMessage(
                            "trying to fix unicode problem, changing " +
                            fieldValAsString + " -> " + decodedstring)
                        messageFile.write("\t\t<" + field + ">" +
                                          decodedstring + "</" + field + ">\n")

            ###################Common Fields/Attributes#####################

            # Ex: messageFile.write("\t</geomessage>\n")
            messageFile.write("\t</%s>\n" % MilitaryUtilities.getMessageTag())

        # Ex: messageFile.write("</geomessages>")
        messageFile.write("</%s>\n" % MilitaryUtilities.getMessageRootTag())

        arcpy.AddMessage("Rows Processed: " + str(rowCount))
        if foundEmptySIDC:
            arcpy.AddWarning(
                "IMPORTANT: Some rows did not have SIDC set - you may need to run CalcSIDCField tool first."
            )
        arcpy.AddMessage("Write/Append Message File Complete")

    except:
        print "Exception: "
        tb = traceback.format_exc()
        print tb
        arcpy.AddError("Exception")
        arcpy.AddError(tb)
Beispiel #5
0
                    #else :
                    #    affiliationChar = ''
            if (EchelonField in updatefields and row[2] is not None):
                ## TODO - this needs more testing (and moved to SymbolDictionary)
                echelonString = row[2]
                if (EchelonField in fieldNameToDomainName):
                    domain = fieldNameToDomainName[EchelonField]
                    whereClause = "%s = %s" % (CODE_FIELD_NAME, row[2])
                    domainRows = arcpy.SearchCursor("in_memory/" + domain,
                                                    whereClause)
                    for domainRow in domainRows:
                        echelonString = domainRow.getValue(
                            DESCRIPTION_FIELD_NAME)
                        echelonString = echelonString.upper()

            expectedGeometry = DictionaryConstants.getGeometryStringFromShapeType(
                desc.shapeType)

            # sidc = MilitaryUtilities.symbolDictionary.SymbolNametoSymbolIDExt(symbolname, echelonString, affiliation, expectedGeometry)
            sidc = symbolDictionary.SymbolNametoSymbolIDExt(
                symbolname, echelonString, affiliation, expectedGeometry)

            # validSic = MilitaryUtilities.symbolDictionary.isValidSidc(sidc)
            validSic = symbolDictionary.isValidSidc(sidc)

            if not validSic:
                # this should not happen, but final check
                defaultSidc = DictionaryConstants.getDefaultSidcForShapeType(
                    desc.shapeType)
                print "Invalid Sic Code: " + sidc + ", using default: " + defaultSidc
                sidc = defaultSidc
    def SymbolNametoSymbolIDExt(self, symbolName, echelonString, affiliation, expectedGeometry) :

        # Attempts to handle the many name cases that show up in Military Features
        # A straight Dictionary Name to SIDC case should always work, but the names
        # don't always show up in that form, use SymbolNametoSymbolID for simple case
         
        foundSIC = False
        add2Map  = False
        symbolNameUpper = symbolName.upper()
        
        # Tricky: the Append Features Tools adds to the base name with "~" so remove all after "~"
        # see SymbolCreator.cs/GetRuleNameFromSidc for separator character/format
        symbolNameUpper = symbolNameUpper.split("~")[0].strip()

        # print ("Using Symbol " + sidc)
        if (symbolNameUpper in self.nameToSIC):
            # Skip the SQL query, because we have already found this one (or it is hardcoded)
            sidc = self.nameToSIC[symbolNameUpper]
            foundSIC = True
        else:
            sqliteConn = None
            sqliteCursor = None
            symboldictionary = self.getDictionaryPath()
            sqliteConn = sqlite3.connect(symboldictionary)
            sqliteCursor = sqliteConn.cursor()
            # SQL query (or two) to find SIC
            sqliteCursor.execute("SELECT SymbolId FROM SymbolInfo WHERE UPPER(Name) = ?", (symbolNameUpper,))
            sqliteRow = sqliteCursor.fetchone()

            if (sqliteRow == None):
                # if it is not found with the supplied name, we need to try a few more cases:
                # remove 1) affilition 2) "Left" / "Right" 
                if self.endsInAffilationString(symbolNameUpper) :
                    symbolNameUpper = symbolNameUpper[0:-2] 
                elif self.endsInLeft(symbolNameUpper) : 
                    symbolNameUpper = symbolNameUpper[0:-5]
                elif self.endsInRight(symbolNameUpper) : 
                    symbolNameUpper = symbolNameUpper[0:-6]

                if (symbolNameUpper in self.nameToSIC):
                    # Check again with modfied name
                    sidc = self.nameToSIC[symbolNameUpper]
                    foundSIC = True
                else :
                    queryval = symbolNameUpper + "%"
                    sqliteCursor.execute("SELECT SymbolId FROM SymbolInfo WHERE UPPER(Name) like ?", (queryval,))
                    sqliteRow = sqliteCursor.fetchone()

                    # Yet another failing case "some have '-' some don't, ex. "Task - Screen" <-> "Task Screen"
                    if (sqliteRow == None):
                        queryval = '%' + symbolNameUpper + '%'
                        sqliteCursor.execute("SELECT SymbolId FROM SymbolInfo WHERE (UPPER(Name) like ?)", (queryval,))
                        sqliteRow = sqliteCursor.fetchone()

            if (sqliteRow != None):
                foundSIC = True
                sidc = sqliteRow[0].replace("*", "-")
                add2Map = True

        if (foundSIC) and self.isValidSidc(sidc):
            # If it is now a valid SIDC, replace chars 11 and 12 (in Python that's 10 and 11) with the echelon code
            if (echelonString in self.echelonToSIC1112):
                sidc = sidc[0:10] + self.echelonToSIC1112[echelonString] + sidc[12:]

            # Then check affiliation char (the correct one is not always returned)
            if not ((affiliation is None) or (affiliation is "")) :  
                affiliationChar = sidc[1]
                expectedAffiliationChar = DictionaryConstants.affiliationToAffiliationChar[affiliation]
    
                if affiliationChar != expectedAffiliationChar :
                    print "Unexpected Affiliation Char: " + affiliationChar + " != " + expectedAffiliationChar
                    sidc = sidc[0] + expectedAffiliationChar + sidc[2:]

            if add2Map : 
                # add the query results to the map (if valid)
                self.nameToSIC[symbolNameUpper] = sidc            
                print "Adding to Map: [" + symbolNameUpper + ", " + sidc + "]"
        else:
            defaultSidc = DictionaryConstants.getDefaultSidcForGeometryString(expectedGeometry)
            sidc = defaultSidc
            warningMsg = "Warning: Could not map " + symbolNameUpper + " to valid SIDC - returning default: " + sidc
            arcpy.AddWarning(warningMsg)

        return sidc            
Beispiel #7
0
    def SymbolNametoSymbolIDExt(self, symbolName, echelonString, affiliation,
                                expectedGeometry):

        # Attempts to handle the many name cases that show up in Military Features
        # A straight Dictionary Name to SIDC case should always work, but the names
        # don't always show up in that form, use SymbolNametoSymbolID for simple case

        foundSIC = False
        add2Map = False
        symbolNameUpper = symbolName.upper()

        # Tricky: the Append Features Tools adds to the base name with "~" so remove all after "~"
        # see SymbolCreator.cs/GetRuleNameFromSidc for separator character/format
        symbolNameUpper = symbolNameUpper.split("~")[0].strip()

        # print ("Using Symbol " + sidc)
        if (symbolNameUpper in self.nameToSIC):
            # Skip the SQL query, because we have already found this one (or it is hardcoded)
            sidc = self.nameToSIC[symbolNameUpper]
            foundSIC = True
        else:
            sqliteConn = None
            sqliteCursor = None
            symboldictionary = self.getDictionaryPath()
            sqliteConn = sqlite3.connect(symboldictionary)
            sqliteCursor = sqliteConn.cursor()
            # SQL query (or two) to find SIC
            sqliteCursor.execute(
                "SELECT SymbolId FROM SymbolInfo WHERE UPPER(Name) = ?",
                (symbolNameUpper, ))
            sqliteRow = sqliteCursor.fetchone()

            if (sqliteRow is None):
                # if it is not found with the supplied name, we need to try a few more cases:
                # remove 1) affilition 2) "Left" / "Right"
                if self.endsInAffilationString(symbolNameUpper):
                    symbolNameUpper = symbolNameUpper[0:-2]
                elif self.endsInLeft(symbolNameUpper):
                    symbolNameUpper = symbolNameUpper[0:-5]
                elif self.endsInRight(symbolNameUpper):
                    symbolNameUpper = symbolNameUpper[0:-6]

                if (symbolNameUpper in self.nameToSIC):
                    # Check again with modfied name
                    sidc = self.nameToSIC[symbolNameUpper]
                    foundSIC = True
                else:
                    queryval = symbolNameUpper + "%"
                    sqliteCursor.execute(
                        "SELECT SymbolId FROM SymbolInfo WHERE UPPER(Name) like ?",
                        (queryval, ))
                    sqliteRow = sqliteCursor.fetchone()

                    # Yet another failing case "some have '-' some don't, ex. "Task - Screen" <-> "Task Screen"
                    if (sqliteRow is None):
                        queryval = '%' + symbolNameUpper + '%'
                        sqliteCursor.execute(
                            "SELECT SymbolId FROM SymbolInfo WHERE (UPPER(Name) like ?)",
                            (queryval, ))
                        sqliteRow = sqliteCursor.fetchone()

            if (sqliteRow != None):
                foundSIC = True
                sidc = sqliteRow[0].replace("*", "-")
                add2Map = True

        if (foundSIC) and self.isValidSidc(sidc):
            # If it is now a valid SIDC, replace chars 11 and 12 (in Python that's 10 and 11) with the echelon code
            if (echelonString in self.echelonToSIC1112):
                sidc = sidc[0:10] + self.echelonToSIC1112[
                    echelonString] + sidc[12:]

            # Then check affiliation char (the correct one is not always returned)
            if not ((affiliation is None) or (affiliation is "")):
                affiliationChar = sidc[1]
                expectedAffiliationChar = DictionaryConstants.affiliationToAffiliationChar[
                    affiliation]

                if affiliationChar != expectedAffiliationChar:
                    print "Unexpected Affiliation Char: " + affiliationChar + " != " + expectedAffiliationChar
                    sidc = sidc[0] + expectedAffiliationChar + sidc[2:]

            if add2Map:
                # add the query results to the map (if valid)
                self.nameToSIC[symbolNameUpper] = sidc
                print "Adding to Map: [" + symbolNameUpper + ", " + sidc + "]"
        else:
            defaultSidc = DictionaryConstants.getDefaultSidcForGeometryString(
                expectedGeometry)
            sidc = defaultSidc
            warningMsg = "Warning: Could not map " + symbolNameUpper + " to valid SIDC - returning default: " + sidc
            arcpy.AddWarning(warningMsg)

        return sidc
def writeFeaturesFromMessageFile() :

    foundEmptyRuleId = False  # used to detect if we can not set a RuleID for any rows

    # Get the input message file
    inputFileName = arcpy.GetParameterAsText(0)
    if (inputFileName == "") or (inputFileName is None):
        inputFileName = os.path.join(MilitaryUtilities.dataPath, r"/messages/Mil2525CMessages.xml")
                
    if not os.path.isfile(inputFileName) :
        arcpy.AddError("Bad Input File: " + inputFileName)
        return

    inputFile=open(inputFileName, "r")
    if (inputFile is None) : 
        arcpy.AddError("Input file can't be opened, exiting")
        return
        
    # Get the output feature class
    outputFC = arcpy.GetParameter(1)
    if (outputFC == "") or (outputFC is None):
        outputFC = os.path.join(MilitaryUtilities.geoDatabasePath, r"/test_outputs.gdb/FriendlyOperations/FriendlyUnits")
        
    desc = arcpy.Describe(outputFC)
    if desc == None :
        arcpy.AddError("Can't open Output Dataset: " + str(outputFC)) 
        return

    shapeType = desc.shapeType;

    # Get standard
    standard = arcpy.GetParameterAsText(2)
        
    # Message Type Field
    messageTypeField = arcpy.GetParameterAsText(3)            

    arcpy.AddMessage("Running with Parameters:")
    arcpy.AddMessage("0 - input XML File: " + str(inputFileName))
    arcpy.AddMessage("1 - output FC: " + str(outputFC))
    arcpy.AddMessage("2 - symbology standard: " + str(standard))        
    arcpy.AddMessage("3 - MessageTypeField: " + messageTypeField)
        
    if not ((messageTypeField == "") or (messageTypeField is None)) :
        if desc.Fields.contains(field) :
            MilitaryUtilities.MessageTypeField = messageTypeField
        else :
            arcpy.AddWarning("MessageTypeField does not exist in output: " + MessageTypeField + " , using default")

    print "Exporting message objects from: " + str(inputFileName)
    print "To Feature Class: " + str(outputFC)
    print "That match shape type: " + shapeType

    # initialize the standard
    MilitaryUtilities.getGeometryConverterStandard(standard)
        
    ruleFieldName = MilitaryUtilities.symbolDictionary.initializeRulesByMilitaryFeatures(outputFC) 

    if (ruleFieldName == "") or (ruleFieldName is None) :
        arcpy.AddError("RuleFieldName not found, exiting")
        return

    # Projected or geographic?
    xname = "lon"
    yname = "lat"
    isProjected = desc.spatialReference.type == "Projected"
    if (isProjected):
        xname = "x"
        yname = "y"
    outputWkid = desc.spatialReference.factoryCode

    ################Begin Export ##########################
    
    featureFields = desc.fields

    # Iterate through the messages and check the shape
    WRITE_OUTPUT = True # debug switch when output not needed
    newRow = None
    newRows = None

    try : 

        if WRITE_OUTPUT : 
            newRows = arcpy.InsertCursor(outputFC)
        messageCount = 0

        # for each message in the message file, get its attributes and copy to the output FeatureClass
        for sic, controlPoints, attributes in MessageIterator.MessageIterator(inputFileName) :
            print sic, controlPoints, attributes

            geoType = MilitaryUtilities.geoConverter.expectedGeometryType(sic)
            if not DictionaryConstants.isCorrectShapeTypeForFeature(geoType, shapeType) : 
                skipMsg = "Skipping SIC: " + sic + " - does not match feature type" + shapeType
                arcpy.AddMessage(skipMsg)
                continue

            # Used for those SICs that map to 2 lines (ex. Task Screen/Guard/Cover)
            repeatForPairFeatures = True
            repeatCount = 0

            while repeatForPairFeatures :

                outputPointList, conversionNotes = MilitaryUtilities.geoConverter.controlPointsToGeometry(sic, controlPoints, attributes)
                if outputPointList == None :
                    msg = "Failed to Convert Points from Military to MilFeature format for SIDC: " + sic
                    arcpy.AddError(msg)
                    arcpy.AddError("Conversion Notes: " + conversionNotes)
                    repeatForPairFeatures = False
                    continue

                inputWkid = 0
                if attributes.has_key(DictionaryConstants.Tag_Wkid) :
                    inputWkid = int(attributes[DictionaryConstants.Tag_Wkid])

                if outputWkid != inputWkid :
                    msg = "ERROR: Input Message and Output Feature WKIDs do not match (InsertFeature will fail)"
                    arcpy.AddError(msg)
                    msg = "Output WKID = " + str(outputWkid) + " , Input WKID = " + str(inputWkid)
                    arcpy.AddError(msg)

                ruleId, symbolName = MilitaryUtilities.symbolDictionary.symbolIdToRuleId(sic)

                if ruleId < 0 :
                    foundEmptyRuleId = True
                    # arcpy.AddWarning("WARNING: Could not map ruleId to SIDC: " + sic)

                # For those SIC that map to 2 lines (ex. Task Screen/Guard/Cover)
                # will need to clone/repeat the message here for Left/Right Upper/Lower pair
                repeatForPairFeatures = False 
                geoConversion = MilitaryUtilities.symbolDictionary.symbolIdToGeometryConversionType(sic)
                if (geoConversion == DictionaryConstants.GCT_TWOLINE) or \
                    (geoConversion == DictionaryConstants.GCT_TWOLINE3OR4PT) :
                    if repeatCount > 0 : 
                        repeatForPairFeatures = False # Only do once
                        ## TODO: find better way to set rule Id for 2nd line (Left/Right) version
                        # This is quite kludgy, and relies on the 2nd ruleid code being the 1st + 1
                        # and this may not always be the case
                        ruleId = ruleId + 1
                    else : 
                        repeatForPairFeatures = True 
                        attributes[DictionaryConstants.Tag_TwoLinesNeeded] = "True"
                        # don't let id get repeated, so append "_2"
                        if attributes.has_key(DictionaryConstants.Tag_Id) : 
                            attributes[DictionaryConstants.Tag_Id] = attributes[DictionaryConstants.Tag_Id] + "_2"
                repeatCount = repeatCount + 1

                arcpy.AddMessage("Adding feature #" + str(messageCount) + " with SIDC: " + sic)
                if WRITE_OUTPUT : 
                    try : 
                        shape = MilitaryUtilities.pointsToArcPyGeometry(outputPointList, shapeType)
                        newRow = newRows.newRow()
                        newRow.setValue(desc.shapeFieldName, shape)
                        newRow.setValue(ruleFieldName, ruleId)
                        
                        # both "sic" and "sidc" used
                        try : 
                            newRow.setValue("sic", sic)
                        except :
                            try :                             
                                newRow.setValue("sidc", sic)
                            except : 
                                arcpy.AddWarning("Failed to set SIDC field in output")
                            
                        # add any extra fields
                        for field in featureFields :  
                            if not (field.name in DictionaryConstants.MILFEATURES_FIELD_EXCLUDE_LIST) :
                                lowerFieldName = field.name.lower()
                                # we don't the case of the attribute so have to search
                                for key in attributes.keys() :                                     
                                    lowerKey = key.lower() 
                                    if (lowerKey == lowerFieldName) :
                                        try : 
                                            newRow.setValue(field.name, attributes[key])
                                        except : 
                                            print "Could not add: Field: " + field.name + ", Value: " + str(attributes[key])

                        newRows.insertRow(newRow) 
                        arcpy.AddMessage("Message successfully added: " + str(messageCount))
                    except : 
                        arcpy.AddError("ERROR: Exception while adding new feature (does Spatial Ref match?)")
                        tb = traceback.format_exc()
                        print tb
                else :
                    print "WRITING OUTPUT:"
                    print "SIC: " + sic + ", Name: " + symbolName                
                    print "Adding geometry to feature, with points: "
                    for point in outputPointList : 
                        x = point.split(',')[0]
                        y = point.split(',')[1]
                        print "(", x, ",", y, ")"                                     
                
            messageCount += 1
            
        if messageCount == 0 :
            arcpy.AddWarning("No Messages Found in Input")

        if foundEmptyRuleId :
            arcpy.AddWarning("IMPORTANT: Some rows do not have Symbol RuleId set - you may need to run CalcRepRuleField tool.")            
           
    except :
        tb = traceback.format_exc()
        arcpy.AddError("Exception:")
        arcpy.AddError(tb)        

    finally :
        # Delete cursor and row objects to remove locks on the data 
        if not newRow is None : 
            del newRow 
        if not newRows is None : 
            del newRows