# -*- coding: utf-8 -*-
import os
import sys
import sys, platform
import ctypes, ctypes.util
import enum
from ctypes import *

dll_path=os.path.dirname(os.path.realpath(__file__)).replace("lib","")+"\DLL\GRM.dll"
gdl_path = ctypes.util.find_library(dll_path) 

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)
