if not modules then modules = { } end modules ['math-ali'] = {
    version   = 1.001,
    comment   = "companion to math-ali.mkiv",
    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
    copyright = "PRAGMA ADE / ConTeXt Development Team",
    license   = "see context related readme files"
}

local unpack = unpack
local gsub = string.gsub
local sort, keys = table.sort, table.keys
local settings_to_array = utilities.parsers.settings_to_array
local P, R, S, C, Cc, Ct, Cs = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Cc, lpeg.Ct, lpeg.Cs
local lpegmatch = lpeg.match

local context = context

do

    local rows = utilities.parsers.groupedsplitat(";")
    local cols = utilities.parsers.groupedsplitat(",")

    local actions = {
        transpose = function(m)
            local t = { }
            for j=1,#m[1] do
                local r = { }
                for i=1,#m do
                    r[i] = m[i][j]
                end
                t[j] = r
            end
            return t
        end,
        negate = function(m)
            for i=1,#m do
                local mi = m[i]
                for j=1,#mi do
                    mi[j] = - mi[j]
                end
            end
            return m
        end,
        scale = function(m,s)
            s = tonumber(s)
            if s then
                for i=1,#m do
                    local mi = m[i]
                    for j=1,#mi do
                        mi[j] = s*mi[j]
                    end
                end
            end
            return m
        end,
    }

    local useractions = {
    }

    interfaces.implement {
        name      = "simplematrix",
        arguments = "2 strings",
        actions   = function(method,data)
            local m = lpegmatch(rows,(gsub(data,"%s+"," ")))
            for i=1,#m do
                m[i] = lpegmatch(cols,m[i])
            end
            local methods = settings_to_array(method)
            for i=1,#methods do
                local detail = settings_to_array(methods[i])
                local method = detail[1]
                local action = actions[method] or useractions[method]
                if action then
                    m = action(m,unpack(detail,2)) or m
                end
            end
            for i=1,#m do
                context("\\NC %{ \\NC }t \\NR",m[i])
            end
        end
    }

    function mathematics.registersimplematrix(name,action)
        if type(action) == "function" then
            useractions[name] = action
        end
    end

    -- \cases{1, x>0 ; -1, x<0 }

    interfaces.implement {
        name      = "simplecases",
        arguments = "2 strings",
        actions   = function(method,data)
            -- no methods yet
            local m = lpegmatch(rows,(gsub(data,"%s+"," ")))
            for i=1,#m do
                m[i] = lpegmatch(cols,m[i])
            end
            for i=1,#m do
                context("\\NC %{ \\NC }t \\NR",m[i])
            end
        end
    }

end

do

    local relations = {
        ["<"]   = "<", [">"]   = ">",
        ["!<"]  = "≮", ["!>"]  = "≯",
        ["<<"]  = "≪", [">>"] = "≫",
        ["="]   = "=", ["=="]  = "=",
        ["<>"]  = "≠", ["!="]  = "≠",
        ["<="]  = "≤", [">="]  = "≥",
        ["=<"]  = "≦", ["=>"]  = "≧",
        ["!=<"] = "≰", ["!=>"] = "≱",
        ["~"]   = "≈", ["~~"]  = "≈",
    }

    for k, v in next, table.copy(relations) do relations[v] = v end

 -- local binaries = {
 --     ["+"] = "+",
 --     ["-"] = "-",
 --     ["/"] = "/",
 --     ["*"] = "",
 -- }

    local separators = {
        [","] = true,
        [";"] = true,
    }

    local alternatives = {
        -- not that many
    }

    local p_sign     = S("-+")
    local p_script   = S("^")^1
    local p_number   = R("09","..")^1 + lpeg.patterns.nestedbraces
    local p_alpha    = R("az","AZ")^1
    local p_variable = p_alpha * (P("_") * (p_number + p_alpha))^-1

    local spacing    = P(" ")^0
    local script     = Cs(p_script * Cc("{") * p_sign^0 * (p_number + p_variable) * Cc("}"))
    local sign       = C(p_sign) + Cc("+")
    local number     = C(p_number)
    local variable   = C(p_variable)
 -- local binary     = lpeg.utfchartabletopattern(binaries) / binaries
    local relation   = lpeg.utfchartabletopattern(relations) / relations
    local separator  = lpeg.utfchartabletopattern(separators)

    local snippet = Ct (
        (
              spacing * sign * spacing * number    * spacing * variable
            + spacing * sign * spacing * number    * spacing * Cc(false)
            + spacing * sign * spacing * Cc(false) * spacing * variable
        ) * (script + Cc(false))
    )

    local parser = Ct ( Ct (
        ( Ct ( snippet^1 ) * spacing * relation    )^1
      * ( Ct ( snippet^1 ) * spacing * separator^0 )
    )^1 )

    local num = "!"

    local ctx_NC, ctx_NR = context.NC, context.NR
    local ctx_typ = context.typ
    local ctx_ord, ctx_rel = context.mathord, context.mathrel

    local clean = table.setmetatableindex(function(t,k)
        local v = gsub(k,"[{}]","")
        t[k] = v
        return v
    end)

    alternatives.equationsystem = function(action,str)
        local rows = lpegmatch(parser,str)
        if not rows then
            ctx_typ("bad system, case 1: %s",1,str)
            return
        end
        local nrow = #rows
        local all = table.setmetatableindex("table")
        for r=1,nrow do
            local row = rows[r]
            for s=1,#row,2 do
                local set = row[s]
                for v=1,#set do
                    local vvv = set[v]
                    local var = vvv[3]
                    if not var then
                        var = num
                    end
                    if set[var] then
                        print("bad system, two constants")
                    end
                    set[var] = set[v]
                    all[s][var] = true
                    set[v] = nil
                end
            end
        end
        --
        local cnt = #rows[1]
        for r=1,nrow do
            if #rows[r] ~= cnt then
                ctx_typ("bad system, case %i: %s",2,str)
                return
            end
        end
        for r=1,#rows[1] do
            local a = keys(all[r])
            sort(a,function(a,b)
                return clean[a] < clean[b]
            end)
            all[r] = a
        end
        --
        for r=1,nrow do
            local row = rows[r]
            for r=1,#row do
                local set = row[r]
                local how = all[r]
                if #how > 0 then
                 -- local done = false
                    for i=1,#how do
                        local k = how[i]
                        local e = set[k]
                        if e then
                            ctx_NC()
                         -- if not done and e[1] == "+" then
                            if i == 1 and e[1] == "+" then
                             -- ctx_ord("")
                             -- ctx_hphantom(e[1])
                             -- ctx_ord("")
                            else
                                ctx_ord("")
                                context(e[1])
                                ctx_ord("")
                             -- done = true
                            end
                            ctx_NC()
                            if e[2] then
                                context(e[2])
                             -- done = true
                            end
                            if e[3] then
                                context(e[3])
                             -- done = true
                            end
                            if e[4] then
                                context(e[4])
                             -- done = true
                            end
                        else
                            ctx_NC()
                         -- ctx_mathord("")
                            ctx_NC()
                        end
                    end
                else
                    ctx_NC()
                    ctx_ord("")
                    context(set)
                    ctx_ord("")
                end
            end
            ctx_NR()
        end
    end

    interfaces.implement {
        name      = "simplealign",
     -- public    = true,
        protected = true,
        arguments = "3 strings",
        actions   = function(alternative,action,str)
            local a = alternatives[alternative]
            if a then
                a(action,str)
            else
                context(str)
            end
        end
    }

end
