import arcpy
from arcpy import env
from arcpy.sa import *
#One of these imports causes the error with raster calculations using system type items like + * ect
#Requires saving files and using Raster("name")*num
import os
import traceback
import sys
import math

class LicenseError(Exception):
    pass

class DataMissing(Exception):
    pass

class ArcMapOnlyError(Exception):
    pass

class AnalysisNotRequired(Exception):
    pass

class OneParcelOnlyError (Exception):
    pass

class NoOffsetAvailable (Exception):
    pass



def isArcMap():
	try:
		arcpy.mapping.MapDocument("CURRENT")
		return True
	except:
		return False

try:
    imgExt =""
    tabExt=""
    shpExt=""
    toDelete = []
    #layer_notes = ""

    if arcpy.CheckExtension("Spatial") == "Available":
        arcpy.CheckOutExtension("Spatial")
    else:
        raise LicenseError

    blnArcmap = isArcMap()
    if blnArcmap == "false":
        raise ArcMapOnlyError

    parcelLyrName = arcpy.GetParameterAsText(0)
    pIdField = arcpy.GetParameterAsText(1)
    haAvailFld = arcpy.GetParameterAsText(2)
    remRankingRaster = arcpy.GetParameterAsText(3)
    haRequired  = arcpy.GetParameterAsText(4)
    outWorkspace = arcpy.GetParameterAsText(5)


    env.workspace = outWorkspace
    env.scratchWorkspace = outWorkspace
    env.overwriteOutput = True
    env.overwriteOutput = 1
    env.outputCoordinateSystem = remRankingRaster
    
    wsDesc = arcpy.Describe(outWorkspace)  
    
    if wsDesc.workspaceType == "FileSystem":
        imgExt =".img"
        tabExt = ".dbf"
        shpExt=".shp"     
    else:
        imgExt =""
        tabExt = ""
        shpExt=""   
        
    totalCount = int(arcpy.GetCount_management(parcelLyrName).getOutput(0))

    if totalCount == 1:
        arcpy.CopyFeatures_management(parcelLyrName,"parcel2Offset"+shpExt)
        rows = arcpy.da.SearchCursor("parcel2Offset"+shpExt, (pIdField))
        toDelete.append("parcel2Offset"+shpExt)
        row = rows.next()
        parcelID = row[0]
        returnWhereClause = '"'+pIdField+'" = '+str(parcelID)
        
    else:
        if totalCount == 0:
            arcpy.AddWarning("No parcels are selected.")
        else:
            arcpy.AddWarning("Can only have one parcel selected.")
        raise OneParcelOnlyError
   
    
    whereClause = '"'+haAvailFld+'" > '+haRequired
    #arcpy.AddMessage(whereClause)
    arcpy.SelectLayerByAttribute_management(parcelLyrName,"NEW_SELECTION", whereClause)
    
    newCount = int(arcpy.GetCount_management(parcelLyrName).getOutput(0))
    if newCount> 0:
        haFieldName = arcpy.ValidateFieldName(haAvailFld,env.workspace)
        idFieldName = arcpy.ValidateFieldName(pIdField,env.workspace)
        
        
        outParcelsOff = "xxlg_ParcelsOffPot"+shpExt
        toDelete.append("xxlg_ParcelsOffPot"+shpExt)
        arcpy.CopyFeatures_management(parcelLyrName,outParcelsOff)
        arcpy.SelectLayerByAttribute_management(parcelLyrName,"CLEAR_SELECTION")
        #arcpy.AddField_management("xxlg_ParcelsOffPot","pru_pro_cd","LONG")
        arcpy.AddField_management(outParcelsOff,"offset_avg","DOUBLE")
        #arcpy.AddField_management("xxlg_ParcelsOffPot","avail_ha","DOUBLE")
        arcpy.AddField_management(outParcelsOff,"dist_away","DOUBLE")
        arcpy.Near_analysis(outParcelsOff,"parcel2Offset"+shpExt,"#","NO_LOCATION","NO_ANGLE")
        arcpy.CalculateField_management(outParcelsOff,"dist_away","!NEAR_DIST!","PYTHON")
        arcpy.DeleteField_management(outParcelsOff,["NEAR_FID", "NEAR_DIST"])
        fieldList = arcpy.ListFields(outParcelsOff,"","OID")      
     

      
      
        arcpy.sa.ZonalStatisticsAsTable(outParcelsOff,idFieldName,remRankingRaster,"xxZonal"+tabExt,"DATA", "MEAN")
        toDelete.append("xxZonal"+tabExt)
        outLayer = "xxlg_OutLayer"
        arcpy.MakeFeatureLayer_management(outParcelsOff,outLayer)
        toDelete.append(outLayer)
        arcpy.AddJoin_management(outLayer,idFieldName,"xxZonal"+tabExt,idFieldName)
        if tabExt == ".dbf":
            qString = 'Not("xxZonal.COUNT" is Null)'
            
        else:
            qString = 'Not("COUNT" is Null)'
        calcExp = "[xxZonal.MEAN]"
        arcpy.SelectLayerByAttribute_management(outLayer,"NEW_SELECTION",qString)
        
        arcpy.CalculateField_management(outLayer,"offset_avg",calcExp)
        try:
            arcpy.RemoveJoin_management(outLayer,"xxZonal")
        except:
            pass
              

        fname = "Parcel_"+str(parcelID)+"_Offsets"
        outFCName = outWorkspace+"\\"+fname+shpExt
        arcpy.CopyFeatures_management(outLayer,outFCName)
            
        exp = '"'+haFieldName+'"  > ' + haRequired
        AvailableRows = arcpy.da.SearchCursor(outParcelsOff, (idFieldName,"offset_avg",haFieldName,"dist_away"), exp)
        if (AvailableRows):
            i = 0
            for row in AvailableRows:
                dist  = row[3]
                if i == 0:
                    currentLowDist=dist
                    finalId = row[0]
                else:
                    if currentLowDist > dist:
                       currentLowDist=dist
                       finalId = row[0]
                i+=1        

            del AvailableRows,row
            qString = '"'+idFieldName+'"'+' = ' + str(finalId)
            #arcpy.AddMessage(qString)
            arcpy.SelectLayerByAttribute_management(outLayer,"NEW_SELECTION",qString)
            indvName = "Parcel_"+str(parcelID)+"_NearestOffset"
            indvFCName = outWorkspace+"\\"+indvName+shpExt
            arcpy.CopyFeatures_management(outLayer,indvFCName)
            layer2_notes = "This layer is the closest property which has enough remnant surplus to offset all of the property identified by id " +str(parcelID) +" which requires "+haRequired+" hectares."
            addLayers = True
    else:
        arcpy.AddWarning("There are no parcels in study area which have a surplus of " +haRequired+" hectares.  Required for "+str(parcelID))
        addLayers = False
    #Return Original Selection
    arcpy.SelectLayerByAttribute_management(parcelLyrName,"NEW_SELECTION", returnWhereClause)
    if addLayers:
        try:
        
            arcpy.MakeFeatureLayer_management(outFCName,"FinalLayer")

            mxd = arcpy.mapping.MapDocument('CURRENT')
            df = arcpy.mapping.ListDataFrames(mxd)[0]
            newlayer1 = arcpy.mapping.Layer("FinalLayer")
            newlayer1.name = fname
            #newlayer1.description = layer_notes

                           
            script_path=sys.argv[0]
            symb_dir = os.path.dirname(script_path) + '\\lyrfiles'
            lyr_symb = symb_dir + '\\PotentialOffsetAvgOffsetValVer2.lyr'
            arcpy.ApplySymbologyFromLayer_management (newlayer1, lyr_symb)
            arcpy.mapping.AddLayer(df, newlayer1, "TOP")

            arcpy.MakeFeatureLayer_management(indvFCName,"IndvLayer")
            newlayer2 = arcpy.mapping.Layer("IndvLayer")
            newlayer2.name = indvName                
            newlayer2.description = layer2_notes
            lyr_symb2 = symb_dir + '\\OffOneParcel.lyr'
            arcpy.ApplySymbologyFromLayer_management (newlayer2, lyr_symb2)
            arcpy.mapping.AddLayer(df, newlayer2, "TOP")
                       
            arcpy.RefreshActiveView()
            arcpy.RefreshTOC()

        except:
            arcpy.AddWarning("Could not create a layers for ArcMap")
            arcpy.AddWarning("You will need to add these data manually.  Add notes below to metadata or description of layer once added.")
            arcpy.AddMessage("Notes for feature class: " + outFCName)
            #arcpy.AddMessage(layer_notes)                
            arcpy.AddWarning("Notes for feature class: "+ indvFCName)
            #arcpy.AddWarning(layer_notes2)            

        
except LicenseError:
    arcpy.AddError ("Spatial Analyst license is unavailable") 	


except DataMissing:
    arcpy.AddError ("Missing Data Error.")

except ArcMapOnlyError:
    arcpy.AddError("Application runs only in ArcMap")

except OneParcelOnlyError:
    arcpy.AddError("Selection error.")

except AnalysisNotRequired:
    arcpy.AddWarning("Analysis not required.")

except NoOffsetAvailable:
    arcpy.AddWarning("No parcels in landscape can be used to offset for selected parcel.")

except:
    tb = sys.exc_info()[2]
    tbinfo = traceback.format_tb(tb)[0]
    pymsg = tbinfo + "\n" + str(sys.exc_type)+ ": " + str(sys.exc_value)
    arcpy.AddError(pymsg)
    
finally:
    arcpy.AddMessage("Removing Temporary Files.")
    for d in toDelete:
        #Comment out two lines below to remove deletion and remove comment from third line
        if arcpy.Exists(d):
            try:
                arcpy.Delete_management(d)
            except:
                arcpy.AddMessage("Could not delete "+d +".")
                continue
