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

local concat = table.concat
local format, gmatch, gsub, lower, match = string.format, string.gmatch, string.gsub, string.lower, string.match
local texsprint = tex.sprint
local ctxcatcodes = tex.ctxcatcodes

local settings_to_hash_strict = aux.settings_to_hash_strict

colors         = colors         or { }
transparencies = transparencies or { }

local registrations = backends.registrations

local a_color        = attributes.private('color')
local a_transparency = attributes.private('transparency')
local a_colorspace   = attributes.private('colormodel')
local a_background   = attributes.private('background')

local a_l_c_template = "\\setevalue{(ca:%s)}{%s}" ..
                       "\\setevalue{(cs:%s)}{\\dosetattribute{color}{%s}}"
local a_g_c_template = "\\setxvalue{(ca:%s)}{%s}" ..
                       "\\setxvalue{(cs:%s)}{\\dosetattribute{color}{%s}}"
local f_l_c_template = "\\setvalue {(ca:%s)}{\\doinheritca{%s}}" ..
                       "\\setvalue {(cs:%s)}{\\doinheritcs{%s}}"
local f_g_c_template = "\\setgvalue{(ca:%s)}{\\doinheritca{%s}}" ..
                       "\\setgvalue{(cs:%s)}{\\doinheritcs{%s}}"
local r_l_c_template = "\\localundefine{(ca:%s)}" ..
                       "\\localundefine{(cs:%s)}"
local r_g_c_template = "\\globalundefine{(ca:%s)}" ..
                       "\\globalundefine{(cs:%s)}"

local a_l_t_template = "\\setevalue{(ta:%s)}{%s}" ..
                       "\\setevalue{(ts:%s)}{\\dosetattribute{transparency}{%s}}"
local a_g_t_template = "\\setxvalue{(ta:%s)}{%s}" ..
                       "\\setxvalue{(ts:%s)}{\\dosetattribute{transparency}{%s}}"
local f_l_t_template = "\\setvalue {(ta:%s)}{\\doinheritta{%s}}" ..
                       "\\setvalue {(ts:%s)}{\\doinheritts{%s}}"
local f_g_t_template = "\\setgvalue{(ta:%s)}{\\doinheritta{%s}}" ..
                       "\\setgvalue{(ts:%s)}{\\doinheritts{%s}}"
local r_l_t_template = "\\localundefine{(ta:%s)}" ..
                       "\\localundefine{(ts:%s)}"
local r_g_t_template = "\\globalundefine{(ta:%s)}" ..
                       "\\globalundefine{(ts:%s)}"

local function definecolor(name, ca, global)
    if ca and ca > 0 then
        if global then
            texsprint(ctxcatcodes,format(a_g_c_template, name, ca, name, ca))
        else
            texsprint(ctxcatcodes,format(a_l_c_template, name, ca, name, ca))
        end
    else
        if global then
            texsprint(ctxcatcodes,format(r_g_c_template, name, name))
        else
            texsprint(ctxcatcodes,format(r_l_c_template, name, name))
        end
    end
end
local function inheritcolor(name, ca, global)
    if ca and ca ~= "" then
        if global then
            texsprint(ctxcatcodes,format(f_g_c_template, name, ca, name, ca))
        else
            texsprint(ctxcatcodes,format(f_l_c_template, name, ca, name, ca))
        end
    else
        if global then
            texsprint(ctxcatcodes,format(r_g_c_template, name, name))
        else
            texsprint(ctxcatcodes,format(r_l_c_template, name, name))
        end
    end
end
local function definetransparent(name, ta, global)
    if ta and ta > 0 then
        if global then
            texsprint(ctxcatcodes,format(a_g_t_template, name, ta, name, ta))
        else
            texsprint(ctxcatcodes,format(a_l_t_template, name, ta, name, ta))
        end
    else
        if global then
            texsprint(ctxcatcodes,format(r_g_t_template, name, name))
        else
            texsprint(ctxcatcodes,format(r_l_t_template, name, name))
        end
    end
end
local function inherittransparent(name, ta, global)
    if ta and ta ~= "" then
        if global then
            texsprint(ctxcatcodes,format(f_g_t_template, name, ta, name, ta))
        else
            texsprint(ctxcatcodes,format(f_l_t_template, name, ta, name, ta))
        end
    else
        if global then
            texsprint(ctxcatcodes,format(r_g_t_template, name, name))
        else
            texsprint(ctxcatcodes,format(r_l_t_template, name, name))
        end
    end
end

local transparent = {
    none       =  0,
    normal     =  1,
    multiply   =  2,
    screen     =  3,
    overlay    =  4,
    softlight  =  5,
    hardlight  =  6,
    colordodge =  7,
    colorburn  =  8,
    darken     =  9,
    lighten    = 10,
    difference = 11,
    exclusion  = 12,
}

-- By coupling we are downward compatible. When we decouple we need to do more tricky
-- housekeeping (e.g. persist color independent transparencies when color bound ones
-- are nil.)

colors.couple = true

function colors.definetransparency(name,n)
    transparent[name] = n
end

local registered = { }

local function do_registerspotcolor(parent,name,parentnumber,e,f,d,p)
    if not registered[parentnumber] then
        local v = colors.values[parentnumber]
        if v then
            local kind = colors.default -- else problems with shading etc
            if kind == 1 then kind = v[1] end
            if     kind == 2 then -- name noffractions names p's r g b
                registrations.grayspotcolor(parent,f,d,p,v[2])
            elseif kind == 3 then
                registrations.rgbspotcolor (parent,f,d,p,v[3],v[4],v[5])
            elseif kind == 4 then
                registrations.cmykspotcolor(parent,f,d,p,v[6],v[7],v[8],v[9])
            end
            if e and e ~= "" then
                registrations.spotcolorname(parent,e)
            end
        end
        registered[parentnumber] = true
    end
end

local function do_registermultitonecolor(parent,name,parentnumber,e,f,d,p) -- same as spot but different template
    if not registered[parentnumber] then
        local v = colors.values[parentnumber]
        if v then
            local kind = colors.default -- else problems with shading etc
            if kind == 1 then kind = v[1] end
            if     kind == 2 then
                registrations.grayindexcolor(parent,f,d,p,v[2])
            elseif kind == 3 then
                registrations.rgbindexcolor (parent,f,d,p,v[3],v[4],v[5])
            elseif kind == 4 then
                registrations.cmykindexcolor(parent,f,d,p,v[6],v[7],v[8],v[9])
            end
        end
        registered[parentnumber] = true
    end
end

function colors.definesimplegray(name,s)
    return colors.register(name,'gray',s) -- we still need to get rid of 'color'
end

function colors.defineprocesscolor(name,str,global,freeze) -- still inconsistent color vs transparent
    local r = match(str,"^#(.+)$") -- for old times sake (if we need to feed from xml or so)
    local t = (r and { h = r }) or settings_to_hash_strict(str)
    if t then
        if t.h then
            local r, g, b = match(t.h .. "000000","(..)(..)(..)") -- watch the 255
            definecolor(name, colors.register(name,'rgb',(tonumber(r,16) or 0)/255,(tonumber(g,16) or 0)/255,(tonumber(b,16) or 0)/255               ), global)
        elseif t.r or t.g or t.b then
            definecolor(name, colors.register(name,'rgb', tonumber(t.r)  or 0,      tonumber(t.g)  or 0,      tonumber(t.b)  or 0                    ), global)
        elseif t.c or t.m or t.y or t.k then
            definecolor(name, colors.register(name,'cmyk',tonumber(t.c)  or 0,      tonumber(t.m)  or 0,      tonumber(t.y)  or 0, tonumber(t.k) or 0), global)
        else
            definecolor(name, colors.register(name,'gray',tonumber(t.s)  or 0), global)
        end
        if t.a and t.t then
            definetransparent(name, transparencies.register(name,transparent[t.a] or tonumber(t.a) or 1,tonumber(t.t) or 1), global)
        elseif colors.couple then
        --  definetransparent(name, transparencies.register(nil, 1, 1), global) -- can be sped up
            definetransparent(name, 0, global) -- can be sped up
        end
    elseif freeze then
        local ca = attributes.list[a_color]       [str]
        local ta = attributes.list[a_transparency][str]
        if ca then
            definecolor(name, ca, global)
        end
        if ta then
            definetransparent(name, ta, global)
        end
    else
        inheritcolor(name, str, global)
        inherittransparent(name, str, global)
    --  if global and str ~= "" then -- For Peter Rolf who wants access to the numbers in Lua. (Currently only global is supported.)
    --      attributes.list[a_color]       [name] = attributes.list[a_color]       [str] or attributes.unsetvalue  -- reset
    --      attributes.list[a_transparency][name] = attributes.list[a_transparency][str] or attributes.unsetvalue
    --  end
    end
end

function colors.isblack(ca) -- maybe commands
    local cv = ca > 0 and colors.value(ca)
    return (cv and cv[2] == 0) or false
end

function colors.definespotcolor(name,parent,str,global)
    if parent == "" or parent:find("=") then
        colors.registerspotcolor(name, parent)
    elseif name ~= parent then
        local cp = attributes.list[a_color][parent]
        if cp then
            local t = settings_to_hash_strict(str)
            if t then
                t.p = tonumber(t.p) or 1
                do_registerspotcolor(parent, name, cp, t.e, 1, "", t.p) -- p not really needed, only diagnostics
                if name and name ~= "" then
                    definecolor(name, colors.register(name,'spot', parent, 1, "", t.p), true)
                    if t.a and t.t then
                        definetransparent(name, transparencies.register(name,transparent[t.a] or tonumber(t.a) or 1,tonumber(t.t) or 1), global)
                    elseif colors.couple then
                    --~ definetransparent(name, transparencies.register(nil, 1, 1), global) -- can be sped up
                        definetransparent(name, 0, global) -- can be sped up
                    end
                end
            end
        end
    end
end

function colors.registerspotcolor(parent, str)
    local cp = attributes.list[a_color][parent]
    if cp then
        local e = ""
        if str then
            local t = settings_to_hash_strict(str)
            e = (t and t.e) or ""
        end
        do_registerspotcolor(parent, "dummy", cp, e, 1, "", 1) -- p not really needed, only diagnostics
    end
end

function colors.definemultitonecolor(name,multispec,colorspec,selfspec)
    local dd, pp, nn = { }, { }, { }
    for k,v in gmatch(multispec,"(%a+)=([^%,]*)") do
        dd[#dd+1] = k
        pp[#pp+1] = v
        nn[#nn+1] = k
        nn[#nn+1] = format("%1.3g",tonumber(v) or 0) -- 0 can't happen
    end
--~ v = tonumber(v) * p
    local nof = #dd
    if nof > 0 then
        dd, pp, nn = concat(dd,','), concat(pp,','), concat(nn,'_')
        local parent = gsub(lower(nn),"[^%d%a%.]+","_")
        colors.defineprocesscolor(parent,colorspec..","..selfspec,true,true)
        local cp = attributes.list[a_color][parent]
        if cp then
            do_registerspotcolor(parent, name, cp, "", nof, dd, pp)
            do_registermultitonecolor(parent, name, cp, "", nof, dd, pp)
            definecolor(name, colors.register(name, 'spot', parent, nof, dd, pp), true)
            local t = settings_to_hash_strict(selfspec)
            if t and t.a and t.t then
                definetransparent(name, transparencies.register(name,transparent[t.a] or tonumber(t.a) or 1,tonumber(t.t) or 1), global)
            elseif colors.couple then
            --  definetransparent(name, transparencies.register(nil, 1, 1), global) -- can be sped up
                definetransparent(name, 0, global) -- can be sped up
            end
        end
    end
end

function colors.mp(model,ca,ta,default)
    local cv = colors.value(ca) -- faster when direct colors.values[ca]
    if cv then
        local tv = transparencies.value(ta)
        if model == 1 then
            model = cv[1]
        end
        if tv then
            if model == 2 then
                return format("transparent(%s,%s,(%s,%s,%s))",tv[1],tv[2],cv[3],cv[4],cv[5])
            elseif model == 3 then
                return format("transparent(%s,%s,(%s,%s,%s))",tv[1],tv[2],cv[3],cv[4],cv[5])
            elseif model == 4 then
                return format("transparent(%s,%s,cmyk(%s,%s,%s,%s))",tv[1],tv[2],cv[6],cv[7],cv[8],cv[9])
            else
                return format("transparent(%s,%s,multitonecolor(\"%s\",%s,\"%s\",\"%s\"))",tv[1],tv[2],cv[10],cv[11],cv[12],cv[13])
            end
        else
            if model == 2 then
                return format("(%s,%s,%s)",cv[3],cv[4],cv[5])
            elseif model == 3 then
                return format("(%s,%s,%s)",cv[3],cv[4],cv[5])
            elseif model == 4 then
                return format("cmyk(%s,%s,%s,%s)",cv[6],cv[7],cv[8],cv[9])
            else
                return format("multitonecolor(\"%s\",%s,\"%s\",\"%s\")",cv[10],cv[11],cv[12],cv[13])
            end
        end
    else
        default = default or 0 -- rgb !
        return format("(%s,%s,%s)",default,default,default)
    end
end

function colors.formatcolor(ca,separator)
    local cv = colors.value(ca)
    if cv then
        local c, f, t, model = { }, 13, 13, cv[1]
        if model == 2 then
            f, t = 2, 2
        elseif model == 3 then
            f, t = 3, 5
        elseif model == 4 then
            f, t = 6, 9
        end
        for i=f,t do
            c[#c+1] = format("%0.3f",cv[i])
        end
        return concat(c,separator)
    else
        return format("%0.3f",0)
    end
end

function colors.formatgray(ca,separator)
    local cv = colors.value(ca)
    return format("%0.3f",(cv and cv[2]) or 0)
end

function colors.colorcomponents(ca)
    local cv = colors.value(ca)
    if cv then
        local model = cv[1]
        if model == 2 then
            return format("s=%1.3f",cv[2])
        elseif model == 3 then
            return format("r=%1.3f g=%1.3f b=%1.3f",cv[3],cv[4],cv[5])
        elseif model == 4 then
            return format("c=%1.3f m=%1.3f y=%1.3f k=%1.3f",cv[6],cv[7],cv[8],cv[9])
        elseif type(cv[13]) == "string" then
            return format("p=%s",cv[13])
        else
            return format("p=%1.3f",cv[13])
        end
    else
        return ""
    end
end

function colors.transparencycomponents(ta)
    local tv = transparencies.value(ta)
    if tv then
        return format("a=%1.3f t=%1.3f",tv[1],tv[2])
    else
        return ""
    end
end

function colors.spotcolorname(ca,default)
    local cv, v = colors.value(ca), "unknown"
    if cv and cv[1] == 5 then
        v = cv[10]
    end
    return tostring(v)
end

function colors.spotcolorparent(ca,default)
    local cv, v = colors.value(ca), "unknown"
    if cv and cv[1] == 5 then
        v = cv[12]
        if v == "" then
            v = cv[10]
        end
    end
    return tostring(v)
end

function colors.spotcolorvalue(ca,default)
    local cv, v = colors.value(ca), 0
    if cv and cv[1] == 5 then
       v = cv[13]
    end
    return tostring(v)
end
