from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

__RCSID__ = "$Id$"

from diraccfg import CFG
from DIRAC import S_OK, S_ERROR
from DIRAC.Core.Utilities import List


def loadJDLAsCFG(jdl):
    """
    Load a JDL as CFG
    """

    def cleanValue(value):
        value = value.strip()
        if value[0] == '"':
            entries = []
            iPos = 1
            current = ""
            state = "in"
            while iPos < len(value):
                if value[iPos] == '"':
                    if state == "in":
                        entries.append(current)
                        current = ""
                        state = "out"
                    elif state == "out":
                        current = current.strip()
                        if current not in (",",):
                            return S_ERROR("value seems a list but is not separated in commas")
                        current = ""
                        state = "in"
                else:
                    current += value[iPos]
                iPos += 1
            if state == "in":
                return S_ERROR('value is opened with " but is not closed')
            return S_OK(", ".join(entries))
        else:
            return S_OK(value.replace('"', ""))

    def assignValue(key, value, cfg):
        key = key.strip()
        if len(key) == 0:
            return S_ERROR("Invalid key name")
        value = value.strip()
        if not value:
            return S_ERROR("No value for key %s" % key)
        if value[0] == "{":
            if value[-1] != "}":
                return S_ERROR("Value '%s' seems a list but does not end in '}'" % (value))
            valList = List.fromChar(value[1:-1])
            for i in range(len(valList)):
                result = cleanValue(valList[i])
                if not result["OK"]:
                    return S_ERROR("Var %s : %s" % (key, result["Message"]))
                valList[i] = result["Value"]
                if valList[i] is None:
                    return S_ERROR("List value '%s' seems invalid for item %s" % (value, i))
            value = ", ".join(valList)
        else:
            result = cleanValue(value)
            if not result["OK"]:
                return S_ERROR("Var %s : %s" % (key, result["Message"]))
            nV = result["Value"]
            if nV is None:
                return S_ERROR("Value '%s seems invalid" % (value))
            value = nV
        cfg.setOption(key, value)
        return S_OK()

    if jdl[0] == "[":
        iPos = 1
    else:
        iPos = 0
    key = ""
    value = ""
    action = "key"
    insideLiteral = False
    cfg = CFG()
    while iPos < len(jdl):
        char = jdl[iPos]
        if char == ";" and not insideLiteral:
            if key.strip():
                result = assignValue(key, value, cfg)
                if not result["OK"]:
                    return result
            key = ""
            value = ""
            action = "key"
        elif char == "[" and not insideLiteral:
            key = key.strip()
            if not key:
                return S_ERROR("Invalid key in JDL")
            if value.strip():
                return S_ERROR("Key %s seems to have a value and open a sub JDL at the same time" % key)
            result = loadJDLAsCFG(jdl[iPos:])
            if not result["OK"]:
                return result
            subCfg, subPos = result["Value"]
            cfg.createNewSection(key, contents=subCfg)
            key = ""
            value = ""
            action = "key"
            insideLiteral = False
            iPos += subPos
        elif char == "=" and not insideLiteral:
            if action == "key":
                action = "value"
                insideLiteral = False
            else:
                value += char
        elif char == "]" and not insideLiteral:
            key = key.strip()
            if len(key) > 0:
                result = assignValue(key, value, cfg)
                if not result["OK"]:
                    return result
            return S_OK((cfg, iPos))
        else:
            if action == "key":
                key += char
            else:
                value += char
                if char == '"':
                    insideLiteral = not insideLiteral
        iPos += 1

    return S_OK((cfg, iPos))


def dumpCFGAsJDL(cfg, level=1, tab="  "):
    indent = tab * level
    contents = ["%s[" % (tab * (level - 1))]
    sections = cfg.listSections()

    for key in cfg:
        if key in sections:
            contents.append("%s%s =" % (indent, key))
            contents.append("%s;" % dumpCFGAsJDL(cfg[key], level + 1, tab))
        else:
            val = List.fromChar(cfg[key])
            # Some attributes are never lists
            if len(val) < 2 or key in ["Arguments", "Executable", "StdOutput", "StdError"]:
                value = cfg[key]
                try:
                    try_value = float(value)
                    contents.append("%s%s = %s;" % (tab * level, key, value))
                except Exception:
                    contents.append('%s%s = "%s";' % (tab * level, key, value))
            else:
                contents.append("%s%s =" % (indent, key))
                contents.append("%s{" % indent)
                for iPos in range(len(val)):
                    try:
                        value = float(val[iPos])
                    except Exception:
                        val[iPos] = '"%s"' % val[iPos]
                contents.append(",\n".join(["%s%s" % (tab * (level + 1), value) for value in val]))
                contents.append("%s};" % indent)
    contents.append("%s]" % (tab * (level - 1)))
    return "\n".join(contents)
