# -*- coding: utf-8 -*-
import os
import sys
import sys, platform
import ctypes, ctypes.util
import enum
from ctypes import *
gdl_path = ctypes.util.find_library("C:/Users/hermesys/AppData/Roaming/QGIS/QGIS3/profiles/default/python/plugins/grm_20200618_2/grm/DLL/GRM.dll") 

if not gdl_path:
    print("Unable to find the specified library.")
    sys.exit() 

try:
     gdl = ctypes.CDLL(gdl_path)
except OSError:
    print("Unable to load the system C library")
    sys.exit()

class unSaturatedKType(enum.Enum):
    Constant=0
    Linear=1
    Exponential=2
    usKNone=3

class swsParameters(Structure):
    _fields_ = [("wsid", ctypes.c_int),
                ("iniSaturation", ctypes.c_double),
                ("minSlopeOF", ctypes.c_double),
                ("unSatKType", ctypes.c_int),
                ("coefUnsaturatedK", ctypes.c_double),
                ("minSlopeChBed", ctypes.c_double),
                ("minChBaseWidth", ctypes.c_double),
                ("chRoughness", ctypes.c_double),
                ("dryStreamOrder", ctypes.c_int),
                ("iniFlow", ctypes.c_double),
                ("ccLCRoughness", ctypes.c_double),
                ("ccPorosity", ctypes.c_double),
                ("ccWFSuctionHead", ctypes.c_double),
                ("ccHydraulicK", ctypes.c_double),
                ("ccSoilDepth", ctypes.c_double),
                ("userSet", ctypes.c_int)]

class grmWSinfo(object):
    def __init__(self,
                 fpnGMP_OR_fdirType,
                 fpnDomain="",
                 fpnSlope="",
                 fpnFdir="",
                 fpnFac="",
                 fpnStream = "",
                 fpnLandCover = "",
                 fpnSoilTexture = "",
                 fpnSoilDepth = "",
                 fpnIniSoilSaturationRatio = "",
                 pfnIniChannelFlow = "",
                 fpnChannelWidth = ""):

        gdl.grmWSinfo_new_inputFiles.argtypes =[
            ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p,
            ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p,
            ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p,
            ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p] 

        gdl.grmWSinfo_new_inputFiles.restype = ctypes.c_void_p
        gdl.grmWSinfo_new_gmpFile.argtypes =[ctypes.c_char_p]
        gdl.grmWSinfo_new_gmpFile.restype = ctypes.c_void_p
        gdl.isInWatershedArea.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int]
        gdl.isInWatershedArea.restype = ctypes.c_bool
        gdl.upStreamWSIDs.argtypes = [ctypes.c_void_p, ctypes.c_int]
        gdl.upStreamWSIDs.restype =   ctypes.POINTER(ctypes.c_int) 
        gdl.upStreamWSCount.argtypes = [ctypes.c_void_p, ctypes.c_int]
        gdl.upStreamWSCount.restype = ctypes.c_int
        gdl.downStreamWSIDs.argtypes = [ctypes.c_void_p, ctypes.c_int]
        gdl.downStreamWSIDs.restype = ctypes.POINTER(ctypes.c_int)
        gdl.downStreamWSCount.argtypes = [ctypes.c_void_p, ctypes.c_int]
        gdl.downStreamWSCount.restype = ctypes.c_int
        gdl.watershedID.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int]
        gdl.watershedID.restype = ctypes.c_int
        gdl.flowDirection.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int]
        gdl.flowDirection.restype = ctypes.c_char_p
        gdl.flowAccumulation.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int]
        gdl.flowAccumulation.restype = ctypes.c_int
        gdl.slope.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int]
        gdl.slope.restype = ctypes.c_double
        gdl.streamValue.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int]
        gdl.streamValue.restype = ctypes.c_int
        gdl.cellFlowTypeACell.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int]
        gdl.cellFlowTypeACell.restype = ctypes.c_char_p
        gdl.landCoverValue.argtypes =[ctypes.c_void_p, ctypes.c_int, ctypes.c_int]
        gdl.landCoverValue.restype = ctypes.c_int
        gdl.soilTextureValue.argtypes =[ctypes.c_void_p, ctypes.c_int, ctypes.c_int]
        gdl.soilTextureValue.restype = ctypes.c_int
        gdl.soilDepthValue.argtypes =[ctypes.c_void_p, ctypes.c_int, ctypes.c_int]
        gdl.soilDepthValue.restype = ctypes.c_int
        gdl.cellCountInUpstreamArea.argtypes =[ctypes.c_void_p, ctypes.c_int, ctypes.c_int]
        gdl.cellCountInUpstreamArea.restype =ctypes.c_int
        gdl.allCellsInUpstreamArea.argtypes =[ctypes.c_void_p, ctypes.c_int, ctypes.c_int]
        gdl.allCellsInUpstreamArea.restype = ctypes.POINTER(ctypes.c_char_p)
        gdl.setOneSWSParsAndUpdateAllSWSUsingNetwork.argtypes = [
            ctypes.c_void_p,ctypes.c_int,ctypes.c_double,ctypes.c_double,
            ctypes.c_int,ctypes.c_double,ctypes.c_double,ctypes.c_double,
            ctypes.c_double,ctypes.c_int,ctypes.c_double,ctypes.c_double, 
            ctypes.c_double,ctypes.c_double,ctypes.c_double,ctypes.c_double]

        gdl.setOneSWSParsAndUpdateAllSWSUsingNetwork.restype = ctypes.c_bool
        gdl.updateAllSubWatershedParametersUsingNetwork.argtypes =[ctypes.c_void_p]
        gdl.updateAllSubWatershedParametersUsingNetwork.restype = None
        gdl.subwatershedPars.argtypes =[ctypes.c_void_p, ctypes.c_int]
        gdl.subwatershedPars.restype = swsParameters
        gdl.removeUserParametersSetting.argtypes =[ctypes.c_void_p, ctypes.c_int]
        gdl.removeUserParametersSetting.restype = ctypes.c_bool
        gdl.facMaxCellxCol.argtypes= [ctypes.c_void_p]
        gdl.facMaxCellxCol.restype = ctypes.c_int
        gdl.facMaxCellyRow.argtypes= [ctypes.c_void_p]
        gdl.facMaxCellyRow.restype = ctypes.c_int
        gdl.WSIDsAll.argtypes= [ctypes.c_void_p]
        gdl.WSIDsAll.restype = ctypes.POINTER(ctypes.c_int)
        gdl.WScount.argtypes= [ctypes.c_void_p]
        gdl.WScount.restype = ctypes.c_int
        gdl.mostDownStreamWSIDs.argtypes= [ctypes.c_void_p]
        gdl.mostDownStreamWSIDs.restype =  ctypes.POINTER(ctypes.c_int)
        gdl.mostDownStreamWSCount.argtypes = [ctypes.c_void_p]
        gdl.mostDownStreamWSCount.restype = ctypes.c_int
        gdl.cellCountInWatershed.argtypes= [ctypes.c_void_p]
        gdl.cellCountInWatershed.restype = ctypes.c_int
        gdl.cellSize.argtypes= [ctypes.c_void_p]
        gdl.cellSize.restype = ctypes.c_double
        bfpnGmpORfdirType = fpnGMP_OR_fdirType.encode('utf-8')

        if fpnDomain=="":
            self.obj = gdl.grmWSinfo_new_gmpFile(bfpnGmpORfdirType)
        else :
            bfpnDomain =fpnDomain.encode('utf-8')
            bfpnSlope =fpnSlope.encode('utf-8')
            bfpnFdir = fpnFdir.encode('utf-8')
            bfpnFac = fpnFac.encode('utf-8')
            bfpnStream=fpnStream.encode('utf-8')
            bfpnLandCover = fpnLandCover.encode('utf-8')
            bfpnSoilTexture = fpnSoilTexture.encode('utf-8')
            bfpnSoilDepth = fpnSoilDepth.encode('utf-8')
            bfpnIniSoilSaturationRatio = fpnIniSoilSaturationRatio.encode('utf-8')
            bpfnIniChannelFlow = pfnIniChannelFlow.encode('utf-8')
            bfpnChannelWidth = fpnChannelWidth.encode('utf-8')
            self.obj = gdl.grmWSinfo_new_inputFiles(bfpnGmpORfdirType, bfpnDomain, bfpnSlope,
                                                    bfpnFdir, bfpnFac, bfpnStream, 
                                                    bfpnLandCover, bfpnSoilTexture, bfpnSoilDepth,
                                                    bfpnIniSoilSaturationRatio, bpfnIniChannelFlow, bfpnChannelWidth)

        self.facMaxCellxCol = gdl.facMaxCellxCol(self.obj)
        self.facMaxCellyRow = gdl.facMaxCellyRow(self.obj)
        self.WSIDsAll = gdl.WSIDsAll(self.obj)
        self.WScount = gdl.WScount(self.obj)
        self.mostDownStreamWSIDs = gdl.mostDownStreamWSIDs(self.obj)
        self.mostDownStreamWSCount = gdl.mostDownStreamWSCount(self.obj)
        self.cellCountInWatershed=gdl.cellCountInWatershed(self.obj)
        self.cellSize=gdl.cellSize(self.obj)

    def isInWatershedArea(self, colXAryidx, rowYAryidx):
        return gdl.isInWatershedArea(self.obj, colXAryidx, rowYAryidx)

    def upStreamWSIDs(self, currentWSID):
        return gdl.upStreamWSIDs(self.obj, currentWSID)

    def upStreamWSCount(self, currentWSID):
        return gdl.upStreamWSCount(self.obj, currentWSID)

    def downStreamWSIDs(self, currentWSID):
        return gdl.downStreamWSIDs(self.obj, currentWSID)

    def downStreamWSCount(self, currentWSID):
        return gdl.downStreamWSCount(self.obj, currentWSID)

    def watershedID(self,  colXAryidx,  rowYAryidx):
        return gdl.watershedID(self.obj,  colXAryidx,  rowYAryidx)

    def flowDirection(self, colXAryidx, rowYAryidx):
        return gdl.flowDirection(self.obj, colXAryidx, rowYAryidx)

    def flowAccumulation(self, colXAryidx, rowYAryidx):
        return gdl.flowAccumulation(self.obj, colXAryidx, rowYAryidx)

    def slope(self, colXAryidx, rowYAryidx):
        return gdl.slope(self.obj, colXAryidx, rowYAryidx)

    def streamValue(self, colXAryidx, rowYAryidx):
        return gdl.streamValue(self.obj, colXAryidx, rowYAryidx)

    def cellFlowTypeACell(self, colXAryidx, rowYAryidx):
        return gdl.cellFlowTypeACell(self.obj, colXAryidx, rowYAryidx)

    def landCoverValue(self, colXAryidx, rowYAryidx):
        return gdl.landCoverValue(self.obj, colXAryidx, rowYAryidx)

    def soilTextureValue(self, colXAryidx, rowYAryidx):
        return gdl.soilTextureValue(self.obj, colXAryidx, rowYAryidx)

    def soilDepthValue(self, colXAryidx, rowYAryidx):
        return gdl.soilDepthValue(self.obj, colXAryidx, rowYAryidx)

    def allCellsInUpstreamArea(self, colXAryidx, rowYAryidx):
        return gdl.allCellsInUpstreamArea(self.obj, colXAryidx, rowYAryidx)

    def cellCountInUpstreamArea(self, colXAryidx, rowYAryidx):
        return gdl.cellCountInUpstreamArea(self.obj, colXAryidx, rowYAryidx)

    def setOneSWSParsAndUpdateAllSWSUsingNetwork(self, wsid, iniSat,
		minSlopeLandSurface, unSKType, coefUnsK,
		minSlopeChannel, minChannelBaseWidth, roughnessChannel,
		dryStreamOrder, ccLCRoughness,
		ccSoilDepth, ccPorosity, ccWFSuctionHead,
		ccSoilHydraulicCond, iniFlow=0.0):
        return gdl.setOneSWSParsAndUpdateAllSWSUsingNetwork(self.obj, wsid, iniSat,
		minSlopeLandSurface, unSKType, coefUnsK,
		minSlopeChannel, minChannelBaseWidth, roughnessChannel,
		dryStreamOrder, ccLCRoughness,
		ccSoilDepth, ccPorosity, ccWFSuctionHead,
		ccSoilHydraulicCond, iniFlow)

    def updateAllSubWatershedParametersUsingNetwork(self):
        return gdl.updateAllSubWatershedParametersUsingNetwork(self.obj)

    def subwatershedPars(self, wsid):
        return gdl.subwatershedPars(self.obj, wsid)

    def removeUserParametersSetting(self, wsid):
        return gdl.removeUserParametersSetting(self.obj, wsid)

#  class grmWSinfo(object) end =========== 



# sample code to use grmWSinfo class




#fpn_gmp = "‪C:\mekong\1_GRM\GRM_Project\mekong.gmp"

#wsi=grmWSinfo(fpn_gmp) 

fdType = "StartsFromE_TauDEM"

fpn_domain = "C:/Mekong/1_GRM/watershed/mk_DEM_GRM_32648_WS.asc"

fpn_slope = "C:/Mekong/1_GRM/watershed/mk_DEM_GRM_32648_Slope.asc"

fpn_fd = "C:/Mekong/1_GRM/watershed/mk_DEM_GRM_32648_Fdr.asc"

fpn_fa = "C:/Mekong/1_GRM/watershed/mk_DEM_GRM_32648_Fac.asc"

fpn_stream = "C:/Mekong/1_GRM/watershed/mk_DEM_GRM_32648_Stream.asc"

fpn_lc="C:/Mekong/1_GRM/watershed/mk_GMLC_32648.asc"

fpn_st="C:/Mekong/1_GRM/watershed/mk_HWSD_texture_32648.asc"

fpn_sd="C:/Mekong/1_GRM/watershed/mk_HWSD_depth_32648.asc"

fpn_ssi=''

fpn_iniCF=''

fpn_CW=''





wsi=grmWSinfo(fdType,  

    fpn_domain,

    fpn_slope,

    fpn_fd,

    fpn_fa,

    fpn_stream, 

    fpn_lc,

    fpn_st,

    fpn_sd, fpn_ssi, fpn_iniCF, fpn_CW)

#================================================================





xCol = 21 

yRow = 49 

wsid = 1   



a = wsi.isInWatershedArea(xCol, yRow) # cell position(x, y) / [ctypes.c_int, ctypes.c_int] -> ctypes.c_bool

print("isInWatershedArea :", a)



a = wsi.upStreamWSCount(wsid) # current ws id / [ctypes.c_int] -> ctypes.c_int

print("upStreamWSCount :", a)



a = wsi.upStreamWSIDs(wsid) # current ws id / [ctypes.c_int] -> ctypes.POINTER(ctypes.c_int)

for i in range(wsi.upStreamWSCount(wsid)): # Because 'a' is pointer, it have to be iterated by using wsi.upStreamWSCount(wsid)

    print("  upStreamWSIDs :", a[i]) # if -1, there is no upstream watershed.



a = wsi.downStreamWSCount(wsid) # current ws id / [ctypes.c_int] -> ctypes.c_int

print("downStreamWSCount :", a)



a = wsi.downStreamWSIDs(wsid) # current ws id / [ctypes.c_int] -> types.POINTER(ctypes.c_int) 

for i in range(wsi.downStreamWSCount(wsid)):  # Because 'a' is pointer, it have to be iterated by using wsi.downStreamWSCount(wsid)

    print("  downStreamWSIDs :", a[i]) # if -1, there is no downstream watershed.



a = wsi.watershedID(xCol, yRow) # cell position(x, y) / [ctypes.c_int, ctypes.c_int] -> ctypes.c_int

print("watershedID :", a)   # if -1, the cell is out of the simulation domain bound



a = wsi.flowDirection(xCol, yRow) # cell position(x, y) / [ctypes.c_int, ctypes.c_int] -> ctypes.c_char_p

print("flowDirection :", a.decode('utf-8')) #if 'OFWB', the cell is out of the simulation domain bound

#enum class flowDirection8 of GRM.dll : E8 = 1, SE8 = 2, S8 = 3, SW8 = 4, W8 = 5, NW8 = 6, N8 = 7, NE8 = 8, None8 = 0



a = wsi.flowAccumulation(xCol, yRow) # cell position(x, y) / [ctypes.c_int, ctypes.c_int] -> ctypes.c_int

print("flowAccumulation :", a)  # if -1, the cell is out of the simulation domain bound



a = wsi.slope(xCol, yRow) # cell position(x, y) / [ctypes.c_int, ctypes.c_int] -> ctypes.c_double

print("slope :", a)  # if -1, the cell is out of the simulation domain bound



a = wsi.streamValue(xCol, yRow) # cell position(x, y) / [ctypes.c_int, ctypes.c_int] -> ctypes.c_int

print("streamValue :", a) # if -1, the cell is out of the simulation domain bound



a = wsi.cellFlowTypeACell(xCol, yRow) # cell position(x, y) / [ctypes.c_int, ctypes.c_int] -> ctypes.c_char_p

print("cellFlowTypeACell :", a.decode('utf-8')) #if 'OFWB', the cell is out of the simulation domain bound



a = wsi.landCoverValue(xCol, yRow) # cell position(x, y) / [ctypes.c_int, ctypes.c_int] -> ctypes.c_int

print("landCoverValue :", a)  # if -1, the cell is out of the simulation domain bound



a = wsi.soilTextureValue(xCol, yRow) # cell position(x, y) / [ctypes.c_int, ctypes.c_int] -> ctypes.c_int

print("soilTextureValue :", a)  # if -1, the cell is out of the simulation domain bound



a = wsi.soilDepthValue(xCol, yRow) # cell position(x, y) / [ctypes.c_int, ctypes.c_int] -> ctypes.c_int

print("soilDepthValue :", a)  # if -1, the cell is out of the simulation domain bound



a = wsi.cellCountInUpstreamArea(xCol, yRow) # cell position(x, y) / [ctypes.c_int, ctypes.c_int] -> ctypes.c_int

print("cellCountInUpstreamArea :", a)  



a= wsi.allCellsInUpstreamArea(xCol, yRow) # cell position(x, y) / [ctypes.c_int, ctypes.c_int] -> ctypes.POINTER(ctypes.c_char_p)

for i in range(wsi.cellCountInUpstreamArea(xCol, yRow)):  # Because 'a' is pointer, it have to be iterated by using wsi.cellCountInUpstreamArea(xCol, yRow)

    print("  allCellsInUpstreamArea :", a[i].decode('utf-8')) # if -1, there is no upstream cell.



swp=swsParameters()


swp = wsi.subwatershedPars(wsid) # current ws id / [ctypes.c_int] -> swsParameters

print("subwatershedPars. wsid :", swp.wsid)

print("subwatershedPars. iniSaturation :", swp.iniSaturation)

print("subwatershedPars. minSlopeOF :", swp.minSlopeOF)

print("subwatershedPars. unSatKType :", swp.unSatKType, "  Name :", unSaturatedKType(swp.unSatKType).name)  # 	Constant=0, Linear=1, Exponential=2, usKNone=3

print("subwatershedPars. coefUnsaturatedK :", swp.coefUnsaturatedK)

print("subwatershedPars. minSlopeChBed :", swp.minSlopeChBed)

print("subwatershedPars. minChBaseWidth :", swp.minChBaseWidth)

print("subwatershedPars. chRoughness :", swp.chRoughness)

print("subwatershedPars. dryStreamOrder :", swp.dryStreamOrder)

print("subwatershedPars. iniFlow :", swp.iniFlow)

print("subwatershedPars. ccLCRoughness :", swp.ccLCRoughness)

print("subwatershedPars. ccPorosity :", swp.ccPorosity)

print("subwatershedPars. ccWFSuctionHead :", swp.ccWFSuctionHead)

print("subwatershedPars. ccHydraulicK :", swp.ccHydraulicK)

print("subwatershedPars. ccSoilDepth :", swp.ccSoilDepth)

print("subwatershedPars. userSet :", swp.userSet)    # 1 : true, 0: false




a = wsi.setOneSWSParsAndUpdateAllSWSUsingNetwork(swp.wsid,  swp.iniSaturation #  setOneSWSParsAndUpdateAllSWSUsingNetwork -> ctypes.c_bool

                           , swp.minSlopeOF, swp.unSatKType, swp.coefUnsaturatedK

                           , swp.minSlopeChBed, swp.minChBaseWidth, swp.chRoughness

                           , swp.dryStreamOrder, swp.ccLCRoughness

                           , swp.ccSoilDepth, swp.ccPorosity, swp.ccWFSuctionHead

                           , swp.ccHydraulicK, swp.iniFlow) 

wsid = 1 
swp = wsi.subwatershedPars(wsid) # current ws id / [ctypes.c_int] -> swsParameters

print("subwatershedPars. wsid :", swp.wsid)

print("subwatershedPars. iniSaturation :", swp.iniSaturation)

print("subwatershedPars. minSlopeOF :", swp.minSlopeOF)

print("subwatershedPars. unSatKType :", swp.unSatKType, "  Name :", unSaturatedKType(swp.unSatKType).name)  # 	Constant=0, Linear=1, Exponential=2, usKNone=3

print("subwatershedPars. coefUnsaturatedK :", swp.coefUnsaturatedK)

print("subwatershedPars. minSlopeChBed :", swp.minSlopeChBed)

print("subwatershedPars. minChBaseWidth :", swp.minChBaseWidth)

print("subwatershedPars. chRoughness :", swp.chRoughness)

print("subwatershedPars. dryStreamOrder :", swp.dryStreamOrder)

print("subwatershedPars. iniFlow :", swp.iniFlow)

print("subwatershedPars. ccLCRoughness :", swp.ccLCRoughness)

print("subwatershedPars. ccPorosity :", swp.ccPorosity)

print("subwatershedPars. ccWFSuctionHead :", swp.ccWFSuctionHead)

print("subwatershedPars. ccHydraulicK :", swp.ccHydraulicK)

print("subwatershedPars. ccSoilDepth :", swp.ccSoilDepth)

print("subwatershedPars. userSet :", swp.userSet)   # 1 : true, 0: false



print("setOneSWSParsAndUpdateAllSWSUsingNetwork :", a)



a = wsi.updateAllSubWatershedParametersUsingNetwork() # A funtion with no parameter. -> void

print("updateAllSubWatershedParametersUsingNetwork :", a)



a = wsi.removeUserParametersSetting(wsid) # current ws id / [ctypes.c_int] -> ctypes.c_bool

print("removeUserParametersSetting :", a)         



a = wsi.facMaxCellxCol # property -> ctypes.c_int

print("facMaxCellxCol :", a)



a = wsi.facMaxCellyRow # property -> ctypes.c_int

print("facMaxCellyRow :", a)





a = wsi.WScount #  property -> ctypes.c_int

print("WScount :", a)



a = wsi.WSIDsAll #  property ->  ctypes.POINTER(ctypes.c_int)

for i in range(wsi.WScount):   # Because 'a' is pointer, it have to be iterated by using wsi.WScount

    print("  WSIDsAll :", a[i]) # if -1, there is no downstream watershed.



a = wsi.mostDownStreamWSCount #  property ->  ctypes.POINTER(ctypes.c_int)

print("mostDownStreamWSCount :", a)



a = wsi.mostDownStreamWSIDs #  property ->  ctypes.POINTER(ctypes.c_int)

for i in range(wsi.mostDownStreamWSCount): # Because 'a' is pointer, it have to be iterated by using wsi.mostDownStreamWSCount 

    print("  mostDownStreamWSIDs :", a[i]) # if -1, there is no downstream watershed.



a = wsi.cellCountInWatershed #  property -> ctypes.c_int

print("cellCountInWatershed :", a)



a = wsi.cellSize #  property -> ctypes.c_double

print("cellSize :", a)