-- This should be the mod path to THIS FILE
local FILENAME = "MOD/shape_utils.lua"

if ClearKey then -- <script>
	local function voxscript( parameters )
		local size = ""
		local shapedata = ""
		local palettedata = ""
		if parameters.palette then
			local palette = {}
			for i = 1, #parameters.palette do
				local p = parameters.palette[i]
				palette[i] = string.format( "%d/%s/%d/%d/%d/%f/%f/%f/%f/%f", p.index, p.material or "none", math.floor( p.r * 255 ),
				                            math.floor( p.g * 255 ), math.floor( p.b * 255 ),
				                            p.a and p.a > 0 and p.a < 1 and 0.5 or 1, p.reflect, p.shiny, p.metal, p.emissive )
			end
			palettedata = string.format( "palette=\"%s\"", table.concat( palette, " " ) )
		end
		if parameters.shape then
			local content = {}
			for i = 1, #parameters.shape do
				local index = parameters.shape[i]
				content[i] = string.char( math.floor( index / 16 ) + 65, index % 16 + 65 )
			end
			shapedata = string.format( "shape=\"%s\"", table.concat( content, "" ) )
		end
		if parameters.size then
			size = string.format( "size=\"%d %d %d\"", unpack( parameters.size ) )
		end
		local xml = string.format( "<voxscript file=\"%s\"><parameters %s %s %s/></voxscript>", FILENAME, size, shapedata,
		                           palettedata )
		return Spawn( xml, Transform(), true, false )[1]
	end

	function CreatePalette( entries )
		return voxscript { palette = entries }
	end

	function SetShapePaletteContent( shape, entries )
		local palette = CreatePalette( entries )
		CopyShapePalette( palette, shape )
		Delete( palette )
	end

	function GetShapePaletteContent( shape )
		local entries = GetShapePalette( shape )
		for i = 1, #entries do
			local mat, r, g, b, a, re, sh, me, em = GetShapeMaterial( shape, entries[i] )
			entries[i] = {
				index = entries[i],
				material = mat,
				r = r,
				g = g,
				b = b,
				a = a,
				reflect = re,
				shiny = sh,
				metal = me,
				emissive = em,
			}
		end
		return entries
	end

	function GetShapesPaletteContent( shapes )
		local reverse = {}
		for i = 1, #shapes do
			local shape = shapes[i]
			local usedpalette = GetShapePalette( shape )
			for j = 1, #usedpalette do
				if not reverse[usedpalette[j]] then
					local material, r, g, b, a, re, sh, me, em = GetShapeMaterial( shape, usedpalette[j] )
					local t = {
						index = usedpalette[j],
						material = material,
						r = r,
						g = g,
						b = b,
						a = a,
						reflect = re,
						shiny = sh,
						metal = me,
						emissive = em,
					}
					reverse[usedpalette[j]] = t
				end
			end
		end
		local forward = {}
		for _, v in pairs( reverse ) do
			forward[#forward + 1] = v
		end
		return forward, reverse
	end

	function SetShapeContent( shape, content )
		local x2, y2, z2 = GetShapeSize( shape )
		local newdata = voxscript { shape = content, size = { x2, y2, z2 } }
		SetBrush( "cube", 1, content[1] )
		DrawShapeBox( newdata, 0, 0, 0, 0, 0, 0 )
		SetBrush( "cube", 1, content[#content] )
		DrawShapeBox( newdata, x2 - 1, y2 - 1, z2 - 1, x2 - 1, y2 - 1, z2 - 1 )
		CopyShapeContent( newdata, shape )
		Delete( newdata )
	end

	function GetShapeContent( shape )
		local content = {}
		local x2, y2, z2 = GetShapeSize( shape )
		for x = 0, x2 - 1 do
			for y = 0, y2 - 1 do
				for z = 0, z2 - 1 do
					local _, _, _, _, _, index = GetShapeMaterialAtIndex( shape, x, y, z )
					content[#content + 1] = index
				end
			end
		end
		return content
	end
else -- <voxscript>
	local sx, sy, sz = GetInt( "size", 1, 1, 1 )
	local shapedata = GetString( "shape" )
	local palettedata = GetString( "palette" )

	local function getbyte( str, offset )
		local a, b = string.byte( str, offset, offset + 1 )
		return (a - 65) * 16 + b - 65
	end

	function init()
		if palettedata and palettedata ~= "" then
			local colors = {}
			for index, m, r, g, b, a, re, sh, me, em in palettedata:gmatch(
				                                            "(%d+)/(%w+)/(%d+)/(%d+)/(%d+)/([%d.]+)/([%d.]+)/([%d.]+)/([%d.]+)/([%d.]+)" ) do
				colors[tonumber( index )] = {
					m,
					tonumber( r ) / 255,
					tonumber( g ) / 255,
					tonumber( b ) / 255,
					tonumber( a ),
					tonumber( re ),
					tonumber( sh ),
					tonumber( me ),
					tonumber( em ),
				}
			end
			for i = 1, 255 do
				if colors[i] then
					CreateMaterial( unpack( colors[i] ) )
				else
					CreateMaterial( "none" ) -- gaps in the palette can't be left out
				end
			end
			if not shapedata or shapedata == "" then
				Vox( 0, 0, 0, 0, 0, 0 )
				for index in pairs( colors ) do
					Material( index )
					Box( index - 1, 0, 0, index, 1, 1 )
				end
			end
		end
		if shapedata and shapedata ~= "" then
			Vox( 0, 0, 0, 0, 0, 0 )
			for i = 0, #shapedata / 2 - 1 do
				local index = getbyte( shapedata, i * 2 + 1 )
				if index > 0 then
					Material( index )
					local x, y, z = math.floor( i / sy / sz ) % sx, math.floor( i / sz ) % sy, i % sz
					Box( x, y, z, x + 1, y + 1, z + 1 )
				end
			end
			Material( 1 ) -- ensure the shape size is as requested
			Box( 0, 0, 0, 1, 1, 1 )
			Box( sx - 1, sy - 1, sz - 1, sx, sy, sz )
		end
	end
end
