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

-- when we can resolve mpcolor at the lua end we will use metapost.graphic(....) directly

local tonumber = tonumber

moduledata.steps = moduledata.steps or { }

local context    = context
local variables  = interfaces.variables
local formatters = string.formatters
----- mpcolor    = attributes.colors.mpnamedcolor
local concat     = table.concat

local report     = logs.reporter("stepcharts")
local trace      = false

trackers.register("stepcharts",function(v) trace = v end)

local defaults = {
    chart = {
        dx              = 10*65436,
        dy              = 10*65436,
    },
    cell = {
        alternative     = 1,
        offset          = 2*65436,
        rulethickness   = 65436,
        framecolor      = "blue",
        backgroundcolor = "gray",
    },
    text = {
        alternative     = 1,
        offset          = 2*65436,
        distance        = 4*65436,
        rulethickness   = 65436,
        framecolor      = "red",
        backgroundcolor = "gray",
    },
    line = {
        alternative     = 1,
        rulethickness   = 65436,
        height          = 30*65436,
        distance        = 10*65436,
        offset          = 5*65436,
        color           = "green",
    },
}

-- todo : name (no name then direct)
-- maybe: includes
-- maybe: flush ranges

local charts = { } -- not used but we could support nesting
local chart  = nil
local steps  = { }
local count  = 0

local function step_start_chart(name,alternative)
    name = name or ""
    steps = table.setmetatableindex(function(t,k)
        local v = { -- could be metatable
            cell_top = false,
            cell_bot = false,
            text_top = false,
            text_mid = false,
            text_bot = false,
            start_t  = k,
            start_m  = k,
            start_b  = k,
            cell_ali = false,
        }
        t[k] = v
        return v
    end)
    count = 0
    chart = {
        steps       = steps,
        count       = count,
        alternative = alternative,
    }
    charts[name] = chart
end

local function step_stop_chart()
    chart.count = count
end

local function step_make_chart(settings)
    local chartsettings = settings.chart
    if not chartsettings then
        if trace then
            report("no chart")
        end
        return
    end
    local chartname = chartsettings.name
    if not chartname then
        if trace then
            report("no name given")
        end
        return
    end
    local chart = charts[chartname]
    if not chart then
        if trace then
            report("no such chart: %s",chartname)
        end
        return
    end
    local steps = chart.steps or { }
    --
    table.setmetatableindex(settings,defaults)
    --
    if trace then
        report(table.serialize(steps,"chartdata"))
    end
    --
    local textsettings = settings.text
    local cellsettings = settings.cell
    local linesettings = settings.line

    local start = nil
    local stop  = nil
    local flush = nil

    if false then

        -- some 2% faster at most, so neglectable as this kind of graphics
        -- is hardly used in quantity but it saves mem and tokens in tracing
        -- and we lose some aspects, like outer color and so (currently)

        local mpcode = false

        start = function()
            mpcode = { }
        end
        stop = function()
            local code = concat(mpcode,"\n")
         -- print(code)
            metapost.graphic {
             -- instance        = "metafun",
                instance        = "steps",
                format          = "metafun",
                data            = code,
             -- initializations = "",
             -- extensions      = "",
             -- inclusions      = "",
                definitions     = 'loadmodule "step" ;',
             -- figure          = "",
                method          = "double",
            }
            mpcode = false
        end
        flush = function(fmt,first,...)
            if first then
                mpcode[#mpcode+1] = formatters[fmt](first,...)
            else
                mpcode[#mpcode+1] = fmt
            end
        end

    else

        start = function() context.startMPcode("steps") end
        stop  = context.stopMPcode
        flush = context

    end
    --
    start()
    flush("step_begin_chart ;")
    --
    local alternative = chartsettings.alternative
    if not alternative or alternative == "" then
        alternative = chart.alternative
    end
    if not alternative or alternative == "" then
        alternative = variables.horizontal
    end
    local alternative = utilities.parsers.settings_to_hash(alternative)
    local vertical    = alternative[variables.vertical]
    local align       = alternative[variables.three]
    local category    = chartsettings.category
    --
    flush('chart_category := "%s" ;',category)
    --
    if vertical then
        flush("chart_vertical := true ;")
    end
    if align then
        flush("chart_align := true ;")
    end
    --
    flush("text_line_color   := %q ;", textsettings.framecolor)
    flush("text_line_width   := %p ;", textsettings.rulethickness)
    flush("text_fill_color   := %q ;", textsettings.backgroundcolor)
    flush("text_offset       := %p ;", textsettings.offset)
    flush("text_distance_set := %p ;", textsettings.distance)
    --
    flush("cell_line_color := %q ;", cellsettings.framecolor)
    flush("cell_line_width := %p ;", cellsettings.rulethickness)
    flush("cell_fill_color := %q ;", cellsettings.backgroundcolor)
    flush("cell_offset     := %p ;", cellsettings.offset)
    flush("cell_distance_x := %p ;", cellsettings.dx)
    flush("cell_distance_y := %p ;", cellsettings.dy)
    --
    flush("line_line_color := %q ;", linesettings.color)
    flush("line_line_width := %p ;", linesettings.rulethickness)
    flush("line_distance   := %p ;", linesettings.distance)
    flush("line_offset     := %p ;", linesettings.offset)
    flush("line_height     := %p ;", linesettings.height)
    --
    for i=1,chart.count do
        local step = steps[i]
        flush("step_begin_cell ;")
        local ali = step.cell_ali
        local top = step.cell_top
        local bot = step.cell_bot
        if ali then
            local text = ali.text
            local shape = ali.shape
            flush('step_cell_ali(%s,%s,%s,%q,%q,%p,%i) ;',
                tonumber(text.left) or 0,
                tonumber(text.middle) or 0,
                tonumber(text.right) or 0,
                shape.framecolor,
                shape.backgroundcolor,
                shape.rulethickness,
                tonumber(shape.alternative) or 24
            )
        end
        if top then
            local shape = top.shape
            flush('step_cell_top(%s,%q,%q,%p,%i) ;',
                tonumber(top.text.top) or 0,
                shape.framecolor,
                shape.backgroundcolor,
                shape.rulethickness,
                tonumber(shape.alternative) or 24
            )
        end
        if bot then
            local shape = bot.shape
            flush('step_cell_bot(%s,%q,%q,%p,%i) ;',
                tonumber(bot.text.bot) or 0,
                shape.framecolor,
                shape.backgroundcolor,
                shape.rulethickness,
                tonumber(shape.alternative) or 24
            )
        end
        local top = step.text_top
        local mid = step.text_mid
        local bot = step.text_bot
        local s_t = step.start_t
        local s_m = step.start_m
        local s_b = step.start_b
        if top then
            local shape = top.shape
            local line  = top.line
            flush('step_text_top(%s,%q,%q,%p,%i,%q,%p,%i) ;',
                tonumber(top.text.top) or 0,
                shape.framecolor,
                shape.backgroundcolor,
                shape.rulethickness,
                tonumber(shape.alternative) or 24,
                line.color,
                line.rulethickness,
                tonumber(line.alternative) or 1
            )
        end
        if mid then -- used ?
            local shape = mid.shape
            local line  = mid.line
            flush('step_text_mid(%s,%q,%q,%p,%i,%q,%p,%i) ;',
                tonumber(mid.text.mid) or 0,
                shape.framecolor,
                shape.backgroundcolor,
                shape.rulethickness,
                tonumber(shape.alternative) or 24,
                line.color,
                line.rulethickness,
                tonumber(line.alternative) or 1
            )
        end
        if bot then
            local shape = bot.shape
            local line  = bot.line
            flush('step_text_bot(%s,%q,%q,%p,%i,%q,%p,%i) ;',
                tonumber(bot.text.bot) or 0,
                shape.framecolor,
                shape.backgroundcolor,
                shape.rulethickness,
                tonumber(shape.alternative) or 24,
                line.color,
                line.rulethickness,
                tonumber(line.alternative) or 1
            )
        end
        flush('start_t[%i] := %i ;',i,s_t)
        flush('start_m[%i] := %i ;',i,s_m)
        flush('start_b[%i] := %i ;',i,s_b)
        flush("step_end_cell ;")
    end
    --
    flush("step_end_chart ;")
    stop()
end

local function step_cells(spec)
    count = count + 1
    local step = steps[count]
    step.cell_top = spec
    step.cell_bot = spec
end

local function step_cells_three(spec)
    count = count + 1
    local step = steps[count]
    step.cell_ali = spec
end

local function step_texts(spec)
    if count > 0 then
        local step = steps[count]
        step.text_top = spec
        step.text_bot = spec
    end
end

local function step_cell(spec)
    count = count + 1
    steps[count].cell_top = spec
end

local function step_text(spec)
    if count > 0 then
        local c = count
        while true do
            local step = steps[c]
            if step.text_top then
                c = c + 1
                step = steps[c]
            else
                step.text_top = spec
                step.start_b  = count
                break
            end
        end
    end
end

local function step_start_cell()
    count = count + 1
    local step = steps[count] -- creates
end

local function step_stop_cell()
end

local function step_text_top(spec)
    if count > 0 then
        steps[count].text_top = spec
    end
end

local function step_text_mid(spec)
    if count > 0 then
        steps[count].text_mid = spec
    end
end

local function step_text_bot(spec)
    if count > 0 then
        steps[count].text_bot = spec
    end
end

local function step_cell_top(spec)
    if count > 0 then
        steps[count].cell_top = spec
    end
end

local function step_cell_bot(spec)
    if count > 0 then
        steps[count].cell_bot = spec
    end
end

--

interfaces.implement {
    name      = "step_start_chart",
    arguments = "2 strings",
    actions   = step_start_chart,
}

interfaces.implement {
    name      = "step_stop_chart",
    actions   = step_stop_chart,
}

interfaces.implement {
    name      = "step_make_chart",
    actions   = step_make_chart,
    arguments = {
        {
            { "chart", {
                    { "category" },
                    { "name" },
                    { "alternative" },
                }
            },
            { "cell", {
                { "alternative" },
                { "offset", "dimension" },
                { "rulethickness", "dimension" },
                { "framecolor" },
                { "backgroundcolor" },
                { "dx", "dimension" },
                { "dy", "dimension" },
                }
            },
            { "text", {
                { "alternative" },
                { "offset", "dimension" },
                { "distance", "dimension" },
                { "rulethickness", "dimension" },
                { "framecolor" },
                { "backgroundcolor" },
                }
            },
            { "line", {
                { "alternative" },
                { "rulethickness", "dimension" },
                { "height", "dimension" },
                { "distance", "dimension" },
                { "offset", "dimension" },
                { "color" },
                }
            }
        }
    }
}

local step_spec = {
    {
        { "text", {
                { "top" },
                { "middle" },
                { "mid" },
                { "bot" },
                { "left" },
                { "right" },
            }
        },
        { "shape", {
                { "rulethickness", "dimension" },
                { "alternative" },
                { "framecolor" },
                { "backgroundcolor" },
            }
        },
        { "line", {
                { "alternative" },
                { "rulethickness", "dimension" },
                { "color" },
                { "offset", "dimension" },
            }
        }
    }
}

interfaces.implement {
    name      = "step_cell",
    arguments = step_spec,
    actions   = step_cell,
}

interfaces.implement {
    name      = "step_text",
    arguments = step_spec,
    actions   = step_text,
}

interfaces.implement {
    name      = "step_text_top",
    arguments = step_spec,
    actions   = step_text_top,
}

interfaces.implement {
    name      = "step_text_mid",
    arguments = step_spec,
    actions   = step_text_mid,
}

interfaces.implement {
    name      = "step_text_bot",
    arguments = step_spec,
    actions   = step_text_bot,
}

interfaces.implement {
    name      = "step_cell_top",
    arguments = step_spec,
    actions   = step_cell_top,
}

interfaces.implement {
    name      = "step_cell_bot",
    arguments = step_spec,
    actions   = step_cell_bot,
}

interfaces.implement {
    name      = "step_start_cell",
    actions   = step_start_cell,
}

interfaces.implement {
    name      = "step_stop_cell",
    actions   = step_stop_cell,
}

interfaces.implement {
    name      = "step_texts",
    arguments = step_spec,
    actions   = step_texts,
}

interfaces.implement {
    name      = "step_cells",
    arguments = step_spec,
    actions   = step_cells,
}

interfaces.implement {
    name      = "step_cells_three",
    arguments = step_spec,
    actions   = step_cells_three,
}
