import json
from diraccfg import CFG

from WebAppDIRAC.Lib.WebHandler import WebSocketHandler, asyncGen
from DIRAC.ConfigurationSystem.Client.ConfigurationClient import ConfigurationClient
from DIRAC import gConfig, gLogger
from DIRAC.ConfigurationSystem.private.Modificator import Modificator


class RegistryManagerHandler(WebSocketHandler):

  AUTH_PROPS = "authenticated"

  def on_open(self):
    self.__configData = {}

  @asyncGen
  def on_message(self, msg):

    self.log.info("RECEIVED %s" % msg)
    try:
      params = json.loads(msg)
    except:
      gLogger.exception("No op defined")

    res = False
    if params["op"] == "init":
      res = self.__getRemoteConfiguration("init")
    elif params["op"] == "getData":
      res = self.__getData(params)
    elif params["op"] == "deleteItem":
      res = self.__deleteItem(params)
    elif params["op"] == "addItem":
      res = self.__addItem(params)
    elif params["op"] == "editItem":
      res = self.__editItem(params)
    elif params["op"] == "resetConfiguration":
      res = self.__getRemoteConfiguration("resetConfiguration")
    elif params["op"] == "commitChanges":
      res = self.__commitChanges()
    elif params["op"] == "getGroupList":
      res = self.__getGroupList()
    elif params["op"] == "getRegistryProperties":
      res = self.__getRegistryProperties()
    elif params["op"] == "saveRegistryProperties":
      res = self.__saveRegistryProperties(params)
    elif params["op"] == "getVomsMapping":
      res = self.__getVomsMapping()
    elif params["op"] == "saveVomsMapping":
      res = self.__saveVomsMapping(params)

    if res:
      self.write_message(res)

  def __getRemoteConfiguration(self, funcName):
    rpcClient = ConfigurationClient(url=gConfig.getValue("/DIRAC/Configuration/MasterServer", "Configuration/Server"))
    modCfg = Modificator(rpcClient)
    retVal = modCfg.loadFromRemote()

    if not retVal[ 'OK' ]:
      return {"success":0, "op":"getSubnodes", "message":"The configuration cannot be read from the remote !"}

    self.__configData[ 'cfgData' ] = modCfg
    self.__configData[ 'strCfgData' ] = str(modCfg)

    version = str(modCfg.getCFG()["DIRAC"]["Configuration"]["Version"])  # pylint: disable=unsubscriptable-object
    configName = str(modCfg.getCFG()["DIRAC"]["Configuration"]["Name"])  # pylint: disable=unsubscriptable-object
    return {"success":1, "op":funcName, "version":version, "name":configName}

  def __getData(self, params):
    data = []
    if params["type"] == "users":

      sectionPath = "/Registry/Users"
      sectionCfg = self.getSectionCfg(sectionPath)

      for username in sectionCfg.listAll():

        item = {}
        item["name"] = username
        props = sectionCfg[username]

        item["dn"] = self.getIfExists("DN", props)
        item["ca"] = self.getIfExists("CA", props)
        item["email"] = self.getIfExists("Email", props)

        data.append(item)

    elif params["type"] == "groups":
      sectionPath = "/Registry/Groups"
      sectionCfg = self.getSectionCfg(sectionPath)

      for group in sectionCfg.listAll():
        item = {}
        item["name"] = group
        props = sectionCfg[group]

        item["users"] = self.getIfExists("Users", props)
        item["properties"] = self.getIfExists("Properties", props)
        item["vomsrole"] = self.getIfExists("VOMSRole", props)

        item["autouploadproxy"] = self.getIfExists("AutoUploadProxy", props)
        item["autouploadpilotproxy"] = self.getIfExists("AutoUploadPilotProxy", props)
        item["autoaddvoms"] = self.getIfExists("AutoAddVOMS", props)
        item["jobshare"] = self.getIfExists("JobShare", props)

        data.append(item)

    elif params["type"] == "hosts":
      sectionPath = "/Registry/Hosts"
      sectionCfg = self.getSectionCfg(sectionPath)

      for host in sectionCfg.listAll():
        item = {}
        item["name"] = host
        props = sectionCfg[host]

        item["dn"] = self.getIfExists("DN", props)
        item["properties"] = self.getIfExists("Properties", props)

        data.append(item)

    elif params["type"] == "voms":
      sectionPath = "/Registry/VOMS/Servers"
      sectionCfg = self.getSectionCfg(sectionPath)

      for host in sectionCfg.listAll():
        item = {}
        item["name"] = host

        data.append(item)

    elif params["type"] == "servers":
      sectionPath = "/Registry/VOMS/Servers/" + params["vom"]
      sectionCfg = self.getSectionCfg(sectionPath)

      for serv in sectionCfg.listAll():
        item = {}
        item["name"] = serv
        props = sectionCfg[serv]

        item["dn"] = self.getIfExists("DN", props)
        item["ca"] = self.getIfExists("CA", props)
        item["port"] = self.getIfExists("Port", props)

        data.append(item)


    return {"op":"getData", "success":1, "type": params["type"], "data": data}

  def __getGroupList(self):
    data = []

    sectionPath = "/Registry/Groups"
    sectionCfg = self.getSectionCfg(sectionPath)

    for group in sectionCfg.listAll():
      data.append([group])

    return {"op":"getGroupList", "success":1, "data": data}

  def __getVomsMapping(self):
    data = []

    sectionPath = "/Registry/VOMS/Mapping"
    sectionCfg = self.getSectionCfg(sectionPath)

    for mapping in sectionCfg.listAll():
      data.append({"name": mapping, "value": sectionCfg[mapping]})

    return {"op":"getVomsMapping", "success":1, "data": data}

  def __getRegistryProperties(self):
    sectionPath = "/Registry"
    sectionCfg = self.getSectionCfg(sectionPath)

    data = {}
    for entryName in sectionCfg.listAll():
      if not sectionCfg.isSection(entryName):
        data[entryName] = sectionCfg[ entryName ]

    return {"op":"getRegistryProperties", "success":1, "data": data}

  def getSectionCfg(self, sectionPath):
    sectionCfg = None
    try:
      sectionCfg = self.__configData[ 'cfgData' ].getCFG()
      for section in [ section for section in sectionPath.split("/") if not section.strip() == "" ]:
        sectionCfg = sectionCfg[ section ]
    except Exception as v:
      return False
    return sectionCfg

  def getIfExists(self, elem, propsList):
    if elem in propsList.listAll():
      return propsList[elem]
    else:
      return ""

  def __addItem(self, params):

    sectionPath = "/Registry/"
    configText = ""
    params = {k: str(v).strip() if v else v for k, v in params.items()}
    if params["type"] == "users":

      sectionPath = sectionPath + "Users"
      if params["dn"]:
        configText = "DN = " + params["dn"] + "\n"

      if params["ca"]:
        configText = configText + "CA = " + params["ca"] + "\n"

      if params["email"]:
        configText = configText + "Email = " + params["email"]

    elif params["type"] == "groups":

      sectionPath = sectionPath + "Groups"
      if params["users"]:
        configText = "Users = " + params["users"] + "\n"

      if params["properties"]:
        configText = configText + "Properties = " + params["properties"] + "\n"

      if params["jobshare"]:
        configText = configText + "JobShare = " + params["jobshare"] + "\n"

      if params["autouploadproxy"]:
        configText = configText + "AutoUploadProxy = " + params["autouploadproxy"] + "\n"

      if params["autouploadpilotproxy"]:
        configText = configText + "AutoUploadPilotProxy = " + params["autouploadpilotproxy"] + "\n"

      if params["autoaddvoms"]:
        configText = configText + "AutoAddVOMS = " + params["autoaddvoms"]

    elif params["type"] == "hosts":

      sectionPath = sectionPath + "Hosts"
      if params["dn"]:
        configText = "DN = " + params["dn"] + "\n"

      if params["properties"]:
        configText = configText + "Properties = " + params["properties"]

    elif params["type"] == "voms":

      sectionPath = sectionPath + "VOMS/Servers"

    elif params["type"] == "servers":

      sectionPath = sectionPath + "VOMS/Servers/" + params["vom"]
      if params["dn"]:
        configText = "DN = " + params["dn"] + "\n"

      if params["port"]:
        configText = configText + "Port = " + params["port"] + "\n"

      if params["ca"]:
        configText = configText + "CA = " + params["ca"]

    sectionPath = sectionPath + "/" + params["name"]

    if self.__configData[ 'cfgData' ].createSection(sectionPath):
      cfgData = self.__configData[ 'cfgData' ].getCFG()
      newCFG = CFG()
      newCFG.loadFromBuffer(configText)
      self.__configData[ 'cfgData' ].mergeSectionFromCFG(sectionPath, newCFG)
      return {"success":1, "op": "addItem"}
    else:
      return {"success":0, "op":"addItem", "message":"Section can't be created. It already exists?"}

  def __editItem(self, params):

    ret = self.__deleteItem(params)
    if ret["success"] == 1:
      ret = self.__addItem(params)
      ret["op"] = "editItem"
      return ret
    ret["op"] = "editItem"
    return ret

    sectionPath = "/Registry/"
    configText = ""
    params = {k: str(v).strip() if v else v for k, v in params.items()}
    if params["type"] == "users":

      sectionPath = sectionPath + "Users"
      if params["dn"]:
        configText = "DN = " + params["dn"] + "\n"

      if params["ca"]:
        configText = configText + "CA = " + params["ca"] + "\n"

      if params["email"]:
        configText = configText + "Email = " + params["email"]

    elif params["type"] == "groups":

      sectionPath = sectionPath + "Groups"
      if params["users"]:
        configText = "Users = " + params["users"] + "\n"

      if params["properties"]:
        configText = configText + "Properties = " + params["properties"] + "\n"

      if params["jobshare"]:
        configText = configText + "JobShare = " + params["jobshare"] + "\n"

      if params["autouploadproxy"]:
        configText = configText + "AutoUploadProxy = " + params["autouploadproxy"] + "\n"

      if params["autouploadpilotproxy"]:
        configText = configText + "AutoUploadPilotProxy = " + params["autouploadpilotproxy"] + "\n"

      if params["autoaddvoms"]:
        configText = configText + "AutoAddVOMS = " + params["autoaddvoms"]

    elif params["type"] == "hosts":

      sectionPath = sectionPath + "Hosts"
      if params["dn"]:
        configText = "DN = " + params["dn"] + "\n"

      if params["properties"]:
        configText = configText + "Properties = " + params["properties"]

    sectionPath = sectionPath + "/" + params["name"]

#   deleting the options underneath
    sectionCfg = self.getSectionCfg(sectionPath)

    for opt in sectionCfg.listAll():
      self.__configData[ 'cfgData' ].removeOption(sectionPath + "/" + opt)

    newCFG = CFG()
    newCFG.loadFromBuffer(configText)
    self.__configData[ 'cfgData' ].mergeSectionFromCFG(sectionPath, newCFG)
    return {"success":1, "op": "editItem"}

  def __deleteItem(self, params):
    sectionPath = "/Registry/"

    if params["type"] == "users":
      sectionPath = sectionPath + "Users"
    elif params["type"] == "groups":
      sectionPath = sectionPath + "Groups"
    elif params["type"] == "hosts":
      sectionPath = sectionPath + "Hosts"
    elif params["type"] == "voms":
      sectionPath = sectionPath + "VOMS/Servers"
    elif params["type"] == "servers":
      sectionPath = sectionPath + "VOMS/Servers/" + params["vom"]

    sectionPath = sectionPath + "/" + params["name"]
    if self.__configData[ 'cfgData' ].removeOption(sectionPath) or self.__configData[ 'cfgData' ].removeSection(sectionPath):
      return {"success":1, "op":"deleteItem"}
    else:
      return {"success":0, "op":"deleteItem", "message":"Entity doesn't exist"}

  def __commitChanges(self):
    if "CSAdministrator" not in self.getProperties():
      return {"success":0, "op":"commitChanges", "message":"You are not authorized to commit changes!!"}
    gLogger.always("User %s is commiting a new configuration version" % self.getUserDN())
    retDict = self.__configData[ 'cfgData' ].commit()
    if not retDict[ 'OK' ]:
      return {"success":0, "op":"commitChanges", "message":retDict[ 'Message' ]}
    return {"success":1, "op":"commitChanges"}

  def __saveRegistryProperties(self, params):
    sectionPath = "/Registry"
    sectionCfg = self.getSectionCfg(sectionPath)

    for opt in sectionCfg.listAll():
      if not sectionCfg.isSection(opt):
        self.__configData[ 'cfgData' ].removeOption(sectionPath + "/" + opt)

    configText = ""

    for newOpt in params:
      if newOpt != "op":
        if configText == "":
          configText = newOpt + "=" + params[newOpt] + "\n"
        else:
          configText = configText + newOpt + "=" + params[newOpt] + "\n"

    newCFG = CFG()
    newCFG.loadFromBuffer(configText)
    self.__configData[ 'cfgData' ].mergeSectionFromCFG(sectionPath, newCFG)

    return {"op":"saveRegistryProperties", "success": 1}

  def __saveVomsMapping(self, params):
    sectionPath = "/Registry/VOMS/Mapping"
    sectionCfg = self.getSectionCfg(sectionPath)

    for opt in sectionCfg.listAll():
      if not sectionCfg.isSection(opt):
        self.__configData[ 'cfgData' ].removeOption(sectionPath + "/" + opt)

    configText = ""

    for newOpt in params:
      if newOpt != "op":
        if configText == "":
          configText = newOpt + "=" + params[newOpt] + "\n"
        else:
          configText = configText + newOpt + "=" + params[newOpt] + "\n"

    newCFG = CFG()
    newCFG.loadFromBuffer(configText)
    self.__configData[ 'cfgData' ].mergeSectionFromCFG(sectionPath, newCFG)

    return {"op":"saveVomsMapping", "success": 1}
