"""
Routine
=======

To group a set of rules into a routine, use the ``Routine`` verb. This takes
a name and a block containing rules::

    Routine {
        ...
    };

Note that in FEZ syntax you must not repeat the routine name at the end of
the block, as is required in AFDKO syntax. Instead, any routine flags are
added to the end of the block, and may be any combination of ``RightToLeft``;
``IgnoreBases`` (AFDKO users, note the changed name); ``IgnoreLigatures``;
``IgnoreMarks`` or ``UseMarkFilteringSet`` followed by a glyph selector.

For example, in AFDKO::

    lookup test {
        lookupflag IgnoreBaseGlyphs UseMarkFilteringSet @thing;
        # ... rules ...
    } test;

becomes::

    Routine test {
        # ... rules ...
    } IgnoreBases UseMarkFilteringSet @thing;

As in AFDKO, a ``Routine`` may appear within a ``Feature`` block or outside one,
in which case it defines a named routine to be accessed later. In simple cases,
you do not need to wrap rules in a routine inside of a feature block; however,
to combine rules with different flags, you must place the rules within a routine.

FEZ routines do not always correspond directly to OpenType lookups, although in
many cases they will. FEZ routines are more flexible, and may contain a mixture of
rule types and may even contain rules targetting different languages::

    Routine test {
        Substitute [four-arab five-arab] -> [four-urdu five-urdu] <<arab/URD>>;
        Substitute [four-arab five-arab] -> [four-farsi five-farsi] <<arab/FAR>>;
    };

FEZ will resolve these routines into one or more OpenType lookups and alter the
lookup references inside features accordingly when compiling to AFDKO syntax.

FEZ routines themselves may apply to certain script/language combinations, using
the language syntax:

    Routine test {
        Substitute [four-arab five-arab] -> [four-urdu five-urdu];
    } <<arab/URD>>;

As with AFDKO, this syntax can only be used when inside a feature block.
"""

PARSEOPTS = dict(use_helpers=True)

GRAMMAR = """
SIMPLE_FLAG: "RightToLeft" | "IgnoreBases" | "IgnoreLigatures" | "IgnoreMarks"
COMPLEX_FLAG: "MarkAttachmentType" | "UseMarkFilteringSet"
complexflag: COMPLEX_FLAG glyphselector
flag: SIMPLE_FLAG | complexflag
flags: flag*
ROUTINENAME: (LETTER|DIGIT|"_")+
"""

Routine_GRAMMAR = """
?start: action
action: ROUTINENAME? "{" statement+ "}" flags languages?
"""

Routine_beforebrace_GRAMMAR = """
?start: beforebrace
beforebrace: ROUTINENAME?
"""

Routine_afterbrace_GRAMMAR = """
?start: afterbrace
afterbrace: flags languages?
"""

VERBS = ["Routine"]

FLAGS = {
    "RightToLeft": 0x1,
    "IgnoreBases": 0x2,
    "IgnoreLigatures": 0x4,
    "IgnoreMarks": 0x8,
    "MarkAttachmentType": 0xFF00,
    "UseMarkFilteringSet": 0x10
}

import fontFeatures
from . import FEZVerb

class Routine(FEZVerb):
    def beforebrace(self, args):
        return args

    def languages(self, args):
        rv = []
        while args:
            rv.append(tuple(map((lambda x: "%-4s" % x),args[0:2])))
            args = args[2:]
        return rv

    def afterbrace(self, args):
        if len(args) < 2:
            args.append([])
        return [args[0], args[1]]

    flags = beforebrace

    def complexflag(self, args):
        return (FLAGS[args[0].value], args[1])

    def flag(self, args):
        (flag,) = args

        if isinstance(flag, str):
            return FLAGS[flag]
        elif isinstance(flag, tuple):
            return flag

    def action(self, args):
        (routinename, statements, flags_languages) = args
        routinename = self.parser.expand_statements(routinename)
        flags_languages = self.parser.expand_statements(flags_languages)

        flags, languages = flags_languages
        statements = self.parser.expand_statements(statements)

        if routinename is not None:
            routinename = routinename[0].value

        if flags is None: flags = []

        if not statements:
            rr = fontFeatures.RoutineReference(name = routinename)
            return [rr]

        r = fontFeatures.Routine()
        if routinename:
            r.name = routinename
        r.rules = []
        for res in self.parser.filterResults(statements):
            if isinstance(res, fontFeatures.Routine):
                r.rules.extend(res.rules)
            else:
                r.rules.append(res)
        r.flags = 0
        for f in flags:
            if isinstance(f, tuple):
                r.flags |= f[0]
                if f[0] == 0x10:
                    r.markFilteringSet = f[1].resolve(self.parser.fontfeatures, self.parser.font)
                elif f[0] == 0xFF00:
                    r.markAttachmentSet = f[1].resolve(self.parser.fontfeatures, self.parser.font)
            else:
                r.flags |= f
        r.languages = languages
        if not self.parser.current_feature:
            self.parser.fontfeatures.routines.append(r)
        return [r]
