-- concatenates fields (deep copy) of t2 to t1
function tconcat( t1, t2 )

  for k,v in pairs( t2 ) do
    if( type(v) == "table" ) then
      v = tcopy( v )
    end
    
    if( type(k) == "number" ) then
      table.insert( t1, v )
    else
      t1[k] = v
    end
  end

end



-- returns a deep copy of the table parameter
function tcopy( tt )

    local copy = {}
    
    for k,v in pairs( tt ) do
    
	if( type(v) == "table" ) then
	    copy[k] = tcopy( v )
	else
	    copy[k] = v
	end
    end
    
    return copy
end


-- "inherits" a table (i.e. im too lazy to explain, read the code!)
function inherit( tbase )

    local function inherit_table( t1, t2 )
    
	-- recursively check all fields
	for k,v in pairs( t2 ) do
        
	    -- if no field, inherit directly
	    if( t1[k] == nil ) then
		--
		if( type(v) == "table" ) then
		    t1[k] = tcopy( v )
		else
		    t1[k] = v
		end

	    -- type mismatch
            elseif( type(t1[k]) ~= type(v) ) then
		--
		error( "Field " ..k.. " has type " ..type(t1[k]).. " but inherits from type " ..type(v))

	    elseif( type(t1[k]) == "table" ) then
		--
		inherit_table( t1[k], v )
	    end
	end
    
    end
    
    local internal_inherit = function( tt )
    
	inherit_table( tt, tbase )
	
	return tt
    
    end
    
    return internal_inherit

end


-- validates the type of a required parameter, boring
function req( param, paramname, typestr )

  if type( param ) ~= typestr then
    error( "required parameter " .. paramname .. " is not of type " .. typestr )
  end
  
end


-- validates the type of an optional parameter.  Options rule.
function opt( param, paramname, typestr )

  if param ~= nil and type( param ) ~= typestr then
    error( "optional parameter " .. paramname .. " is not of type " .. typestr )
  end
  
end

