# Copyright (C) 2019-2020 J.F.Dockes
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import conftree
from uprclutils import uplog


class MinimConfig(object):
    def __init__(self, fn=""):
        if fn:
            try:
                with open(fn, "rb") as f:
                    pass
            except Exception as ex:
                uplog(f"MinimConfig: could not open/read: {ex}")
                fn = "/dev/null"
            self.conf = conftree.ConfSimple(fn)
        else:
            self.conf = conftree.ConfSimple("/dev/null")
        self.quotes = "\"'"
        self.escape = ""
        self.whitespace = ", "

    def getsimplevalue(self, nm):
        s = self.conf.get(nm)
        if s:
            return s.strip()
        else:
            return s

    def getboolvalue(self, nm, dflt):
        val = self.getsimplevalue(nm)
        if val is None or val == "":
            return dflt
        if val == "0" or val.lower()[0] == "f" or val.lower()[0] == "n":
            return False
        else:
            return True

    # Split on commas and colons, a common minim format and return as
    # list of pairs
    def minimsplitsplit(self, str):
        out = []
        if not str:
            return out
        # For some reason, the active colons are backslash-escaped in
        # the file
        lst = str.replace("\\:", ":").split(",")
        for e in lst:
            l = e.split(":")
            if len(l) == 0:
                a = ""
                b = ""
            elif len(l) == 1:
                a = l[0]
                b = ""
            else:
                a = l[0]
                b = l[1]
            out.append((a.strip(), b.strip()))
        return out

    # Comma-separated list. Each element maybe a simple tagname.option
    # value or an \= assignement, with a comma-separated list of values in
    # braces. Returns a list of quadruplet: (tag, neg, optname, values)
    def minimsplitbraceslist(self, value):
        # Split everything on commas
        l1 = value.split(",")
        # Re-join parts inside braces, creating list of options
        inbraces = False
        accum = ""
        l2 = []
        for e in l1:
            if inbraces:
                accum += ", " + e
                if e.find("}"):
                    inbraces = False
                    l2.append(accum)
                    accum = ""
                continue
            if e.find("{") != -1 and e.find("}") == -1:
                inbraces = True
                accum = e
                continue
            l2.append(e)
        # Parse each option [-]tag.option={tag1,tag2} or [-]tag.option
        alloptions = []
        for e in l2:
            lhsrhs = e.split("=")
            if len(lhsrhs) == 2:
                values = [v.strip().lower() for v in lhsrhs[1].lstrip("{").rstrip("}").split(",")]
            else:
                values = []
            tagopt = lhsrhs[0].split(".")
            tag = tagopt[0].strip()
            if tag.startswith("-"):
                neg = True
                tag = tag[1:]
            else:
                neg = False
            opt = ".".join(tagopt[1:])
            alloptions.append((tag, neg, opt, values))
        return alloptions

    def getexcludepatterns(self):
        spats = self.conf.get("minimserver.excludePattern")
        if spats:
            lpats = conftree.stringToStrings(
                spats, quotes=self.quotes, escape=self.escape, whitespace=self.whitespace
            )
            spats = conftree.stringsToString(lpats)
        # uplog("skippedNames from Minim excludePattern: %s" % spats)
        return spats

    def gettagvalue(self):
        stagv = self.conf.get("minimserver.tagValue")
        tagvalue = None
        if stagv:
            tagvalue = self.minimsplitbraceslist(stagv)
        return tagvalue

    def getaliastags(self):
        aliases = []
        saliases = self.conf.get("minimserver.aliasTags")
        # uplog("Minim:getaliastags:in: [%s]" % saliases)
        lst = self.minimsplitsplit(saliases)
        for orig, target in lst:
            orig = orig.lower()
            target = target.lower()
            rep = False
            if target.startswith("-"):
                rep = True
                target = target[1:]
            aliases.append((orig, target, rep))
        # uplog("Minim:getaliastags:out: %s" % aliases)
        return aliases

    def getindextags(self):
        indextags = []
        sit = self.conf.get("minimserver.indexTags")
        # uplog("Minim:getindextags:in: [%s]" % sit)
        if sit:
            indextags = self.minimsplitsplit(sit)
        # uplog("Minim:getindextags:out: %s" % indextags)
        return indextags

    def getitemtags(self):
        itemtags = []
        sit = self.conf.get("minimserver.itemTags")
        # uplog("Minim:getitemtags:in: [%s]" % sit)
        if sit:
            itemtags = [i.strip() for i in sit.split(",")]
        # uplog("Minim:getitemtags:out: %s" % itemtags)
        return itemtags

    def getcontentdirs(self):
        # minim uses '\\n' as a separator for directories (actual
        # backslash then n), not newline. Weird...
        cdirs = []
        s = self.conf.get("minimserver.contentDir")
        if s:
            cdirs = s.replace("\\n", "\n").split("\n")
        return cdirs

    def gettranscodingspec(self):
        s = self.conf.get("stream.transcode")
        if not s:
            return None

        specs = self.minimsplitsplit(s)
        # each spec is a pair of (input,output)
        # TBD
        pass
