import arcpy
from arcpy import env
from arcpy.sa import *
import os
import traceback
import sys
import LegalGeo_Biodiversity_Module
import LegalGeo_EnviroServices_Module
import LegalGeo_Landscape_Module
import LegalGeo_Legal_Module
import LegalGeo_Threat_Module
import LegalGeo_Routines_Module


class NoRemnantsError (Exception):
    pass

class LicenseError(Exception):
    pass

class DataMissing(Exception):
    pass

class WrongEdgeWidth(Exception):
    pass

class ModuleBombed(Exception):
    pass

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


try:
   	

    #Check for spatial analyst license
    if arcpy.CheckExtension("Spatial") == "Available":
        arcpy.CheckOutExtension("Spatial")
    else:
        raise LicenseError

        
    project_folder = arcpy.GetParameterAsText(0)
    if arcpy.Exists(project_folder+"\\lg_input.gdb"):
        inPath = project_folder+"\\lg_input.gdb\\"
        inWS = project_folder+"\\lg_input.gdb"
        DirToRemove = project_folder+os.sep+"lg_scratch.gdb"
        if not(arcpy.Exists(project_folder+"\\lg_scratch.gdb")):
            arcpy.CreateFileGDB_management(project_folder,"lg_scratch.gdb")
        env.workspace = project_folder+"\\lg_scratch.gdb"
        outPath = project_folder+"\\lg_output.gdb\\"
        outWS = project_folder+"\\lg_output.gdb" #For adding to map view if user in ArcMap
        
    elif arcpy.Exists(project_folder+"\\lg_input"):
        inPath = project_folder+"\\lg_input\\"
        inWS = project_folder+"\\lg_input"
        if not(arcpy.Exists(project_folder+"\\lg_scratch")):
            arcpy.CreateFolder_management(project_folder,"lg_scratch")
        env.workspace = project_folder+"\\lg_scratch"
        outPath = project_folder+"\\lg_output\\"
        outWS = project_folder+"\\lg_output" #For adding to map view if user in ArcMap
        DirToRemove = project_folder+os.sep+"lg_scratch"
    else:
        arcpy.AddError("The selected project folder:  " + project_folder+"  Does not have the required lg_input folder or ESRI file geodatabase.  Please select a different project folder or run Step 1 - Project Setup Tool.")
        raise DataMissing

    
    
    userParamfile = project_folder+"\\lg_user_defined_params.txt"
    paramUse = False
    if arcpy.Exists(userParamfile):
        pVals=[]
        params = open(userParamfile,"r")
        try:
            for l in params:
                if "=" in l:
                    vals = l.split("=")
                    val = vals[1]
                    val = int(val.strip())
                    pVals.append(val)
            
            if len(pVals)== 11:
                arcpy.AddMessage("Using input parameter file: "+userParamfile)
                paramUse = True 
            else:
              arcpy.AddWarning("User parameter has been modified. Application used default distances.")
              pVals = [2000,1,100,1,250,2500,100,1000,500,5000,0]               
        except:
            arcpy.AddWarning("User parameter file corrupt. Application used default distances.")
            pVals = [2000,1,100,1,250,2500,100,1000,500,5000,0]
            
    else:
        pVals = [2000,1,100,1,250,2500,100,1000,500,5000,0]
        
    
    #Default Settings for initial run, can be changed by users
    Rem_ZI_Dist = pVals[0]#2000
    Use_Guidos_when_available = pVals[1] #1
    distance4Edge = pVals[2] #100 Distance for LFT model run
    islandSize = pVals[3] * 10000 #10000 sq meters, for prioritizing converted islands to emphasize regeneration regen
    #Influence distance parameters (ie %%_ZI_Dist variables) rank lands higher within this distance 
    #of that particular legal land designation.     
    LR_Dist = pVals[4] #250 buffer zone for LR with ranking of 90 or higher
    LR_ZI_Dist = pVals[5] #2500 LR 
    PPA_Dist = pVals[6] #100 buffer zones for PPAs with ranking of 90 or higher
    PPA_ZI_Dist = pVals[7] #1000
    PA_Dist = pVals[8] #500 buffer zones for PAs with ranking 100
    PA_ZI_Dist = pVals[9] #5000
    Apply_100 = pVals[10]#0

 
    env.scratchWorkspace = env.workspace
    remRankName4Arcmap = arcpy.GetParameterAsText(1)
    regRankName4Arcmap = arcpy.GetParameterAsText(2)
    
    arcpy.AddMessage("Accessing data and setting up analysis environment...")
    #Setup for environment settings during analysis
    arcpy.env.overwriteOutput = 1
    wsDesc = arcpy.Describe(arcpy.env.workspace)
    nameShpExt =""
    imgExt = ""


    

    if wsDesc.workspaceType == "FileSystem":
        nameShpExt=".shp"
        #remnantsTab = "lg_rem_model_runs.dbf"
        imgExt =".img"

    outRemRankName = outPath+remRankName4Arcmap+imgExt
    outRegRankName = outPath+regRankName4Arcmap+imgExt
    requiredData = []
    requiredData.append("lg_REMs"+imgExt)
    requiredData.append("lg_REM_Ones"+imgExt)
    requiredData.append("lg_converted"+imgExt)
    #requiredData.append("lg_remLFTin"+imgExt)
    requiredData.append("lg_Bnd_Feats"+nameShpExt)

    for d in requiredData:
        if arcpy.Exists(inPath+d) == False:
            arcpy.AddError("Required data missing! Requires:  " + d + "  Re-run database setup.")
            raise DataMissing


    rastersToSumRemnants  = []
    rastersToSumConv = []
    
    paramsString4Tab = ""
    layersUsed = ""
    #Setup for environment variables
    remDesc = arcpy.Describe(inPath+"lg_REM_Ones"+imgExt)
    env.outputCoordinateSystem = remDesc.spatialReference

    cellSize = remDesc.meanCellWidth
    env.cellSize = cellSize
    remPolyExt = LegalGeo_Routines_Module.getPolyfromExt(remDesc.extent)
    bndDesc = arcpy.Describe(inPath+"lg_Bnd_Feats"+nameShpExt)
    bndPolyExt = LegalGeo_Routines_Module.getPolyfromExt(bndDesc.extent)
    
    combinePoly = remPolyExt.union(bndPolyExt)
    
    #May need to change per analysis
    env.extent = combinePoly.extent
    env.snapRaster = inPath+"lg_REM_Ones"+imgExt
    

    units = env.outputCoordinateSystem.linearUnitName


    if "Meter" in units:
        outUnit = "Meters"
    else:
        arcpy.AddError("lg_REM_Ones coordinate system has been changed.")
        raise DataMissing

    NumberOfCellsPerHA = 10000 /(cellSize*cellSize)

    if distance4Edge < cellSize:
        arcpy.AddError("Remnants Edge Width of "+str(distance4Edge)+ " must be greater than the raster cellsize of "+str(cellSize)+".")
        raise WrongEdgeWidth

    inputFN = os.path.join(project_folder+os.sep,"lg_analysis_log.txt")
    if arcpy.Exists(inputFN):
        crs = open(inputFN,'a')
    else:
        inputTxtFile = file(inputFN,'wt')
        crs = open(inputFN,'a')
    crs.write("\n")
    crs.write("Step 2 Prioritize Remnants and Regeneration using equal wieighting peformed on " +str(datetime.datetime.now())+"\n")
    crs.write("Data Output location:  "+outPath+"\n")
    crs.write("Equal Weighting Analysis \n")
    crs.write("Inputs an Parameters used for analysis: \n")
    if paramUse:
            crs.write("Used input parameter file: "+userParamfile+"\n")
    #Vegetation analysis
    if  arcpy.Exists(inPath+"lgBio_NatVeg"+imgExt):
        arcpy.AddMessage("Running Vegetation Analysis.........")
        crs.write("\n")
        crs.write("***Vegetation Inputs***\n")
        LegalGeo_Biodiversity_Module.BiodiversityRank(Rem_ZI_Dist,inPath,outPath,crs)
        #the module creates this file locally so you can get it
        if arcpy.Exists(outPath+"lgBioAll_RemRank"+imgExt):
            rastersToSumRemnants.append(outPath+"lgBioAll_RemRank"+imgExt)
            rastersToSumConv.append(outPath+"lgBioAll_ConvRank"+imgExt)
            arcpy.AddMessage("Biodiversity Analysis of Completed.........")
        else:
            arcpy.AddError("Ranking based on natural vegetation failed.")
            crs.write("Ranking based on natural vegetation failed.\n")
            raise ModuleBombed
            
    #Environmental Services
    esExists = LegalGeo_Routines_Module.testForExist(inWS,"lgES_*")
   
    if esExists: 
        crs.write("\n")
        crs.write("***Environmental Services Inputs***\n")     
        arcpy.AddMessage("Running Environmental Services Analysis........")
        LegalGeo_EnviroServices_Module.esRank(inPath,outPath,crs)
        if arcpy.Exists(outPath+"lgESAll_RemRank"+imgExt):

            rastersToSumRemnants.append(outPath+"lgESAll_RemRank"+imgExt)
            rastersToSumConv.append(outPath+"lgESAll_ConvRank"+imgExt)
            arcpy.AddMessage("Environmental Services Analysis Completed........")
        else:
            arcpy.AddError("Ranking based on Environmental Services failed.")
            crs.write("Ranking based on Environmental Services failed.\n")
            raise ModuleBombed           

    
    
    #Landscape

    arcpy.AddMessage("Calculating landscape metric ranking")
    crs.write("\n")
    crs.write("***Landscape Inputs***\n")
    LegalGeo_Landscape_Module.RunLandscapeMetrics(inPath,outPath,imgExt,nameShpExt,Use_Guidos_when_available,distance4Edge,islandSize,Rem_ZI_Dist,cellSize,crs  )
    if arcpy.Exists (outPath+"lgLandAll_RemRank"+imgExt):
        rastersToSumRemnants.append(outPath+"lgLandAll_RemRank"+imgExt)
        rastersToSumConv.append(outPath+"lgLandAll_ConvRank"+imgExt)           
    else:
        arcpy.AddError("Ranking based on landscape metrics failed.")
        crs.write("Ranking based on landscape metrics failed.\n")
        raise ModuleBombed 

    arcpy.AddMessage("Landscape metric ranking completed")


    
    #Legal 
    legalExists = LegalGeo_Routines_Module.testForExist(inWS,"lgLegal_*")
    if legalExists:
		arcpy.AddMessage("Calculating legal metric ranking")
		crs.write("\n")
		crs.write("***Legal Inputs***\n")
		LegalGeo_Legal_Module.legalRank(LR_Dist,LR_ZI_Dist,PPA_Dist,PPA_ZI_Dist,PA_Dist,PA_ZI_Dist,inPath,outPath,imgExt,crs)
		if arcpy.Exists(outPath+"lgLegalAll_RemRank"+imgExt):
			rastersToSumRemnants.append(outPath+"lgLegalAll_RemRank"+imgExt)
			if arcpy.Exists(outPath+"lgLegalAll_ConvRank"+imgExt):
				rastersToSumConv.append(outPath+"lgLegalAll_ConvRank"+imgExt)
			arcpy.AddMessage("Legal metric ranking completed.")
		else:
			arcpy.AddError("Ranking based on legal failed.")
			crs.write("Ranking based on legal metrics failed.\n")
			raise ModuleBombed         
		#Added 2016 
           
		

    #Threat analysis
    threatExists = LegalGeo_Routines_Module.testForExist(inWS,"lgThreat_*")
    if threatExists:
        arcpy.AddMessage("Running Threat Analysis of Remnants.........")
        crs.write("\n")
        crs.write("***Threat Inputs***\n")
        LegalGeo_Threat_Module.ThreatRank(inPath,outPath,imgExt,crs)
        if arcpy.Exists(outPath+"lgThreatAll_RemRank"+imgExt):
            rastersToSumRemnants.append(outPath+"lgThreatAll_RemRank"+imgExt)
            rastersToSumConv.append(outPath+"lgThreatAll_ConvRank"+imgExt)
            arcpy.AddMessage("Threat Analysis of Remnants Completed.........")
        else:
            arcpy.AddError("Ranking based on threats failed.")
            crs.write("Ranking based on threat metrics failed.\n")
            raise ModuleBombed
        


    #Final Ranking-----------------------------------------------------------------------------
    crs.write("****Final Equal-Weight Ranking****\n")
    arcpy.AddMessage("Combining and Ranking all categories of analysis and creating final output")
    sumRemRanks = CellStatistics(rastersToSumRemnants,"SUM","DATA")

    sumRemRanks.save("xxlg_FinalSumRemRanks"+imgExt)

#HERE 
    #arcpy.CopyRaster_management("xxlg_FinalSumRemRanks"+imgExt,outPath+"test_FinalSumRemRanks.tif")

    FinalRemSlice = Slice("xxlg_FinalSumRemRanks"+imgExt,100,"NATURAL_BREAKS",1)
    FinalRemSlice.save("xxlg_FinalRemSlice"+imgExt) 
    FinalRemRanking = LegalGeo_Routines_Module.scaleUp("xxlg_FinalRemSlice"+imgExt,100)
    
    #default rem rank of 100 for LRs and PAs
    if Apply_100 == 1:
        dRemRank = []
        if arcpy.Exists(inPath+"lgLegal_LR_Ones"+imgExt):
            LR100s = Times(Times(inPath+"lgLegal_LR_Ones"+imgExt,100),inPath +"lg_REM_Ones"+imgExt)
            LR100s.save("LR100s"+imgExt)
            dRemRank.append("LR100s"+imgExt)
        if arcpy.Exists(inPath+"lgLegal_PA_ones"+imgExt):
            PA100s = Times(Times(inPath+"lgLegal_PA_Ones"+imgExt,100),inPath +"lg_REM_Ones"+imgExt)
            PA100s.save("PA100s"+imgExt)

            dRemRank.append("PA100s"+imgExt)
        if len(dRemRank) > 0:
            FinalRemRanking.save("xxFinalRemRank"+imgExt)
            dRemRank.append("xxFinalRemRank"+imgExt)
            TheFinal = CellStatistics(dRemRank,"MAXIMUM","DATA")
            TheFinal.save(outRemRankName)
        
        else:
            FinalRemRanking.save(outRemRankName)
    else:
        FinalRemRanking.save(outRemRankName)
    crs.write("Final Equal-Weight Ranking for Remnants: "+outRemRankName+"\n")
    
    #Regen
#Added to make sure no areas are unranked
    rastersToSumConv.append(inPath+"lg_ConvProjOnly"+imgExt)

    sumConvRanks = CellStatistics(rastersToSumConv,"SUM","DATA")


    sumConvRanks.save("xxlg_FinalSumConvRanks"+imgExt)
#Here     
    #arcpy.CopyRaster_management("xxlg_FinalSumConvRanks"+imgExt,outPath+"test_FinalSumConvRanks.tif")  
  
    FinalConvSlice = Slice("xxlg_FinalSumConvRanks"+imgExt,100,"NATURAL_BREAKS",1)
    FinalConvSlice.save("xxlg_FinalConvSlice"+imgExt) 
    FinalConvRanking = LegalGeo_Routines_Module.scaleUp("xxlg_FinalConvSlice"+imgExt,100)
    FinalConvRanking.save(outRegRankName)
    crs.write("Final Equal-Weight Ranking for Regeneration of Converted Lands: "+outRegRankName+"\n")
    
    
    crs.write("*********Step 2: Equal-weighting Priortization End************\n")
    crs.write("\n")
    crs.close()

    arcpy.AddMessage("Ranking completed.")

    blnArcmap = isArcMap()
    if blnArcmap:

        descWorkspace = arcpy.Describe(outWS)
        if descWorkspace.workspaceType == "FileSystem":
            type = "RASTER_WORKSPACE"
        else:
            type = "FILEGDB_WORKSPACE"
        try:
            mxd = arcpy.mapping.MapDocument('CURRENT')
            df = arcpy.mapping.ListDataFrames(mxd)[0] 
            script_path=sys.argv[0]
            symb_dir = os.path.dirname(script_path) + '\\lyrfiles'
            #Rem Ranking
            lyr_symb = symb_dir + '\\Remnants_Rank.lyr'
            newlayer1 = arcpy.mapping.Layer(lyr_symb)
            newlayer1.name = remRankName4Arcmap
            newlayer1.replaceDataSource(outWS,type,remRankName4Arcmap)
            arcpy.mapping.AddLayer(df, newlayer1, "TOP")
            #Regen
            lyr_symbReg = symb_dir + '\\Regeneration.lyr'
            newlayerReg = arcpy.mapping.Layer(lyr_symbReg)
            newlayerReg.name = regRankName4Arcmap
            newlayerReg.replaceDataSource(outWS,type,regRankName4Arcmap)
            arcpy.mapping.AddLayer(df, newlayerReg, "TOP")
            arcpy.RefreshActiveView()
            arcpy.RefreshTOC()
        except:
            #nameLoc = arcpy.env.workspace+"\\"+outName
            arcpy.AddWarning("Could not create a layers for ArcMap.")
            arcpy.AddWarning("You will need to add these data manually.")
            arcpy.AddWarning("Remnants ranking: " +outRemRankName)
            arcpy.AddWarning("Regeneration ranking: " +outRegRankName)

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

except NoRemnantsError:
    if arcpy.Exists("lg_PrjBnd" + nameShpExt):
        try:
            arcpy.Delete_management("lg_PrjBnd" + nameShpExt)
        except:
            arcpy.AddWarning("Could not delete lg_PrjBnd" + nameShpExt)
        
    arcpy.AddError ("No remnant features are found within project area.  Analysis reguires remnants at minimum be present.")

except DataMissing:
    arcpy.AddError ("Select a different workspace or rerun LRSetup tool.")

except WrongEdgeWidth:
    arcpy.AddError ("Input a larger edge width for remnants.")

except ModuleBombed:
    arcpy.AddError("Error in module.")

except:
    #arcpy.AddMessage("exiting")
    tb = sys.exc_info()[2]
    tbinfo = traceback.format_tb(tb)[0]
    #arcpy.AddMessage("exiting2")
    pymsg = tbinfo + "\n" + str(sys.exc_type)+ ": " + str(sys.exc_value)
    #crs.write("*********Ranking Failed************\n")
    #crs.write(pymsg)
    #crs.write("\n")
    #crs.close()

    arcpy.AddError(pymsg)
finally:
   
    arcpy.AddMessage("Cleaning up temporary files")
    LegalGeo_Routines_Module.deleteLGScratchFiles()





