if not table.merge then
    function table.merge( target, ... )
        for i=1, table.getn( arg ) do
            for k, v in pairs( arg[i] ) do
                target[k] = v
            end
        end

        return target
    end
end

function bresenham( v1, v2 )
    local ov = v1
    v1 = {0, 0, 0}
    v2 = {v2[1] - ov[1], v2[2] - ov[2], v2[3] - ov[3]}

    local x0, y0, z0, x1, y1, z1 = v1[1], v1[2], v1[3], v2[1], v2[2], v2[3]

    local dx, dy = math.abs( v2[1] )

--[[
function line(x0, y0, x1, y1)
   dx := abs(x1-x0)
   dy := abs(y1-y0) 
   if x0 < x1 then sx := 1 else sx := -1
   if y0 < y1 then sy := 1 else sy := -1
   err := dx-dy
 
   loop
     setPixel(x0,y0)
     if x0 = x1 and y0 = y1 exit loop
     e2 := 2*err
     if e2 > -dy then 
       err := err - dy
       x0 := x0 + sx
     end if
     if e2 <  dx then 
       err := err + dx
       y0 := y0 + sy 
     end if
   end loop
--]]

end

shape = {}

function shape.line( t, opts )
    opts = table.merge( {
        v1 = false,
        v2 = {0, 0, 0},
    }, opts )

    local state = t( 'getState' )

    if not opts.v1 then
        return true
    end
    if not opts.v2 then
        opts.v2 = v1
        opts.v1 = stateToVert( state )
    end
end

-- a plain line, only changing in one direction.
-- e.g. 0,0,0 to 0,10,0
function shape.straightline( t, opts )
    opts = table.merge( {
        v1 = false,
        dir = false,
        dist = 0,
        retrymove = nil,
        before = function() end,
        after = function() end,
        move = function() return t( 'forward' ) end,
    }, opts )

    if opts.v1 == false then
        opts.v1 = stateToVert( t( 'getState' ) )
    end
    if opts.dir == false then
        opts.dir = opts.v1[4]
    end


    retrymove( t, opts.v1, { retry = opts.retrymove } )
    faceDirection( t, opts.dir )

    --starting at 1 so that if they say go 1, I get one call of the move callbacks
    for i=1, opts.dist do
        if opts.before() == false then return false end
        if opts.move( t ) == false then return false end
        if opts.after() == false then return false end
    end

    return true
end

function shape.rect( t, opts )
    opts = table.merge( {
        v1 = false,
        v2 = false,
        filled = false,
        onrect = function() end,
    }, opts )

    if opts.v2 == false then return true end
    if opts.v1 == false then opts.v1 = stateToVert( t( 'getState' ) ) end

    local samex = false
    local ret = true

    if opts.v1[1] >= opts.v2[1] then
        samex = true
        opts.v1 = table.merge( {}, opts.v1, {opts.v2[1]} )
    end

    if opts.v1[2] >= opts.v2[2] then
        --if samex then return true end
        if samex then
            --special case to handle center block
            ret = ret and shape.straightline( t, table.merge( {}, opts, {
                v1 = opts.v1,
                dir = 0,
                dist = 1,
            }))

            if ret and opts.onrect() == false then return false end
            return ret

        end
        opts.v2 = table.merge( {}, opts.v1, {[2] = opts.v2[2]} )
    end

    ret = ret and shape.straightline( t, table.merge( {}, opts, {
        v1 = opts.v1,
        dir = 0,
        dist = opts.v2[2] - opts.v1[2],
    }))
    ret = ret and shape.straightline( t, table.merge( {}, opts, {
        v1 = false,
        dir = 1,
        dist = opts.v2[1] - opts.v1[1],
    }))
    ret = ret and shape.straightline( t, table.merge( {}, opts, {
        v1 = false,
        dir = 2,
        dist = opts.v2[2] - opts.v1[2],
    }))
    ret = ret and shape.straightline( t, table.merge( {}, opts, {
        v1 = false,
        dir = 3,
        dist = opts.v2[1] - opts.v1[1],
    }))

    if ret and opts.filled then
        t( 'turnRight' )
        if opts.onrect() == false then return false end
        local curstate = t( 'getState' )

        opts.v1 = {opts.v1[1] + 1, opts.v1[2] + 1, curstate.z, opts.v1[4]}
        opts.v2 = {opts.v2[1] - 1, opts.v2[2] - 1, curstate.z, opts.v2[4]}
        return shape.rect( t, opts )
    end

    return ret
end

function shape.pyramid( t, opts )
    t( 'up' )
    return shape.rect( t, table.merge( {
        filled = true,
        after = function()
            t( 'placeDown' )
        end,
        onrect = function()
            t( 'up' )
        end
    }, opts))

end

-- point a to point b with the fewest turns manhattan path
-- E.g. to do 0,0,0 to 3,5,7, it would
-- drive to 3,0,0 -> 3,5,0 -> 3,5,7
function shape.manline( t, opts )
end

--ctx may contain turtle settings, location of chests, inventory, etc.
--step is a callback to call on each step
--v1 and v2 define the volume of the cuboid
function shape.cuboid( t, ctx, step, v1, v2 )
end