local function checkCopy(t)
	if type(t)=="table" and t.nocopy then 
		return nil 
	end
	return t 
end

local function procFrame(item)
	if type(item)=="table" and item.line then 
		-- return lume.merge(item,{line=bitser.dumps(item.line)})
	end
	return item
end

function editor.stackSheet(panel)
	local time = os.time()
	-- ESTIMATE SPRITESHEET SIZE
	setVSync( false )
	local texsize = 0
	local widest = 0
	local tallest = 0

	for i,anim in pairs(panel.anims) do 
		for l,layer in ipairs(anim.layers) do 
			for f,frame in ipairs(layer.frames) do 
				if not panel.object.splitFrames then 
					frame.w 	= frame.canvas and frame.canvas:getWidth()    or frame.w
					frame.h 	= frame.canvas and frame.canvas:getHeight()   or frame.h
					frame.w 	= frame.w>widest and frame.w or widest
					frame.h 	= frame.h>tallest and frame.h or tallest
					texsize 	= texsize + frame.w*frame.h
				end
				frame.index = f
			end
		end
	end
	
	local newSheet
	local axis 	= math.sqrt(texsize)
	texsize 		=  math.pow(2, math.ceil(math.log(axis)/math.log(2))+2)
	texw 				= texsize 
	texh 				= texsize

	gfx.push("all")

	if panel.object.splitFrames then 
		
	else 
		newSheet = newCanvas(math.max(widest,texw),math.max(tallest,texh),{format="srgba8"})
		gfx.setCanvas(newSheet)
		gfx.setBlendMode('replace','premultiplied')
	end

	print("model1")
	if panel.object.models then 
		for m, model in pairs(panel.object.models) do 
			local filename = (ZIP_MODE and LINK_DIR or GAME_DIR)..panel.object.dir..panel.object.name.."/.models/"..model.id
			local data = inspect(model,{process=checkCopy})
			loader:writeFile(filename,--[[ love.data.compress( "string", "deflate", --]] "return "..data--[[ , 9 )--]] )
		end
	end
	print("model2")
	gfx.setColor(1,1,1,1)

	local stack = {x=1,y=1,t=0}

	local splitFrames = {}

	if  panel.object.splitFrames then 
		mkdir((ZIP_MODE and LINK_DIR or GAME_DIR).."images/"..panel.object.name)
	end

	local chunkSize = 0 
	local maxChunksize=100000*1.38
	local chunks={{}}
	local c=1
	local n=1
	local map = {}

	for a,anim in pairs(panel.anims) do 
		local newAnim 		= false
		local animBounds 	= {t=nil,b=nil,l=nil,r=nil}
		local animDims	 	= {w=0,h=0}

		panel.object.dateCreated = panel.object.dateCreated  or os.time()

		if panel.object.animations[anim.key] == nil then 
			panel.object.animations[anim.key] = { fps=anim.fps, name=anim.name , layers={}}
			newAnim = true
		end

		panel.object.animations[anim.key].fps  = anim.fps
		panel.object.animations[anim.key].name = anim.name
		panel.object.animations[anim.key].audio = anim.audio
		panel.object.animations[anim.key].layers = {}

		splitFrames[anim.key] = {}

		for l,layer in ipairs(anim.layers) do 

			panel.object.animations[anim.key].layers[l] = {
				name 				= layer.name,
				frames 			= {},
				type    		= layer.type,
				obj 				= layer.obj,
				iqm 				= layer.iqm,
				smooth  		= layer.smooth,
				format  		= layer.format,
				alpha   		= layer.alpha,
				center  		= layer.center,
				data 				= layer.data and layer.data.id,
				clips  			= layer.clips,
				visible 	 	= layer.visible,
				resolution 	= layer.resolution,
				skeleton 		= layer.skeleton,
				catmull 		= layer.catmull,
				lineWidth 	= layer.lineWidth,
				lineWidthOverride = layer.lineWidthOverride,
				onePixel    = layer.onePixel,
				wobble      = layer.wobble,
				loop 				= layer.loop,
				length 			= layer.length,
				vector  		= layer.vector,
				line 				= layer.line,
				depths 			= layer.depths,
				fill 				= layer.fill,
				palette 		= layer.palette,
			}

			for f,frame in ipairs(layer.frames) do 
				panel.anims[a].layers[l].frames[frame.index].id = panel.anims[a].layers[l].frames[frame.index].id or uuid()
				panel.object.animations[anim.key].layers[l].frames[frame.index] = panel.anims[a].layers[l].frames[frame.index].id

				animBounds.l 	=  (animBounds.l==nil or frame.ox-frame.w/2 < animBounds.l) and frame.ox-frame.w/2 or animBounds.l
				animBounds.r 	=  (animBounds.r==nil or frame.ox+frame.w/2 > animBounds.r) and frame.ox+frame.w/2 or animBounds.r
				animBounds.t 	=  (animBounds.t==nil or frame.oy-frame.h/2 < animBounds.t) and frame.oy-frame.h/2 or animBounds.t
				animBounds.b 	=  (animBounds.b==nil or frame.oy+frame.h/2 > animBounds.b) and frame.oy+frame.h/2 or animBounds.b
				animBounds.ox = (animBounds.l+animBounds.r)/2
				animBounds.oy = (animBounds.t+animBounds.b)/2
				animDims.w 		= animBounds.r-animBounds.l
				animDims.h 		= animBounds.b-animBounds.t

				
			end
		end

		panel.object.animations[anim.key].bounds 	= animBounds
		panel.object.animations[anim.key].size 		= animDims
		panel.object.animations[anim.key].length 	= anim.length

		if newAnim then
			panel.object.animations[anim.key].shapes = anim.shapes
		end
	end

	local symbolPath = (ZIP_MODE and LINK_DIR or GAME_DIR).."images/"..panel.object.name.."/."..panel.object.key
	local symbolData = "local t = "..inspect(panel.object.animations,{newline='',indent=''}).." return t"

	if ZIP_MODE then 
		lfs.write(symbolPath,symbolData)
	else 
		loader:writeFile(symbolPath,symbolData)
	end

	for a,anim in pairs(panel.anims) do
		for l,layer in ipairs(anim.layers) do 
			splitFrames[anim.key][l] = {}

			for f,frame in ipairs(layer.frames) do 
				if stack.x+frame.w > texw then 
					stack.x = 1 
					stack.y = stack.y + stack.t + panel.padding
					stack.t = 0 
				end
				stack.t = frame.h > stack.t and frame.h or stack.t

				local frameDir = string.format(
							"%simages/%s/frames/%s",
							(ZIP_MODE and LINK_DIR or GAME_DIR),
							tostring(panel.object.name),
							frame.id
						)

				local skipFrame =  (frame.lastDrawn and frame.lastDrawn==frame.lastSave) 

				if not lfs.exists(frameDir) then 
					skipFrame=false
				end
				if layer.format=="normal" and not lfs.exists(frameDir..".png") then 
					skipFrame=false
				end

				panel.attemptedSaveTime = time
				
				panel.anims[a].layers[l].frames[frame.index].preSaveTime = panel.anims[a].layers[l].frames[frame.index].lastSave
				panel.anims[a].layers[l].frames[frame.index].lastDrawn=time
				panel.anims[a].layers[l].frames[frame.index].lastSave =time
				
				
				local frameData = {
					blank 			= frame.blank, 
					x						= stack.x, 
					y						= stack.y, 
					w						= frame.w, 
					h						= frame.h, 
					anim 				= frame.anim,
					abs 				= frame.abs,
					tween 			= frame.tween,
					isKey  			= frame.isKey,
					position 		= frame.position,
					orientation = frame.orientation ,
					pose  			= frame.pose,
					scale 	 		= frame.scale,
					ox			 		= frame.ox, 
					oy			 		= frame.oy, 
					l				 		= frame.l,
					strokes  		= level.isAnim and frame.strokes or deepcopy(frame.strokes),
					fills  	 		= frame.fills,
					id          = frame.id,
					lastDrawn   = os.time(),
					lastSave    = os.time(),
					lastPosition= f,
				}

				panel.object.animations[anim.key].layers[l].frames[frame.index] = frameData 

				if panel.object.splitFrames and not skipFrame then 
					print("save frame "..frame.id)
					table.insert(splitFrames,{
						data  = frameData,
						size  = frame.canvas:getWidth()*frame.canvas:getHeight(),
						canvas=frame.canvas,
						dir   = frameDir..".png"
					})
				end

				map[frame.id] = true
				map[frame.id..".png"] = true
				stack.x = stack.x  + frame.w + panel.padding 
			end
		end
	end

	local dir = string.format("%simages/%s/frames/", (ZIP_MODE and LINK_DIR or GAME_DIR), tostring(panel.object.name))
	for f, frame in ipairs(lfs.getDirectoryItems(dir)) do 
		if not map[frame] then
			lfs.remove(dir..frame)
		end
	end

	gfx.pop()

	panel.splitFrames = splitFrames

	panel.saveThread = [[
		require "love.image"
		require "love.math"
		function UnmultiplyGammaPixel(x, y, r, g, b, a)
		   r, g, b = love.math.gammaToLinear(r, g, b)
		   r = (r / a)
		   g = (g / a)
		   b = (b / a)
		   r, g, b = love.math.linearToGamma(r, g, b)
		   return r, g, b, a
		end

		local dir,data1,data2,zip,map = ...

		if map then 
			data1:mapPixel (UnmultiplyGammaPixel)
		end
		if data1 then 
			data1 = data1:encode("png")
		end
		local dir2 = dir:gsub(".png","")

		if zip then 
			local lfs = require "love.filesystem"
			if data1 then 
				lfs.write(dir, data1:getString())
			end

			lfs.write(dir2, "local t = "..(data2).." return t")
		else
			if data1 then 
				local file,e 		= io.open(dir,"w")
				 if not file then file,e 		= io.open("\""..dir.."\"","w") end
			 	file:write(data1:getString())
			 	file:close()
			 end

		 	local file,e 		= io.open(dir2,"w")
		 	 if not file then file,e 		= io.open("\""..dir2.."\"","w") end
		 	file:write("local t = "..(data2).." return t")
		 	file:close()
		end
		data1=nil -- :release()
		data2=nil -- :release()
		love.thread.getChannel("saving"):push("next")
	]]


	if not panel.anims.default then 
		panel.object.animations.default=nil 
		if panel.setDefault then 
			panel.object.default = panel.setDefault
		end
	end


	panel.chunksSaved = 0
	panel.chunks = chunks
	
	if ZIP_MODE then 
		-- mkdir((LINK_DIR.."/export"):gsub("//","/"))
		local str = ""..(LINK_DIR.."/export/sequence/"):gsub("//","/")
		recursivelyDelete( str )
		print(str)
		-- mkdir(LINK_DIR.."/export/sequence")
	end



	panel.saving=true
	panel.saveFrame = 1
	saveFrame(true)

	level.stageWidth = panel.stageWidth
	level.stageHeight = panel.stageHeight
	level.exportScale=panel.exportScale
	
	objects[panel.key].animations = panel.object.animations


end

function saveFrame(start)
		waitFor(function()
			local panel=animationPanel
			if lthread.getChannel("saving"):pop() or start then 
				local frame = panel.splitFrames[panel.saveFrame]
 
				if frame then 

					local data1,data2,thread
					local map
					if frame.canvas and frame.canvas~=panel.blankCanvas then
						if frame.canvas:type() == "Canvas" then 
							data1 = frame.canvas:newImageData()
							map = true
							print("pngdat1")
						else
							data1 = frame.canvas
							print("pngdat2")
						end
					end
					data2  = inspect(frame.data,{newline='',indent=''})

					thread = lthread.newThread(panel.saveThread)

					thread:start(
						frame.dir,
						data1,
						data2,
						ZIP_MODE,
						map
					)
				end

				if panel.saveFrame<#panel.splitFrames then 
					panel.saveFrame = panel.saveFrame + 1
					saveFrame()
				else
					panel.saving=false
					editor.save()
					
					if ZIP_MODE then 
					
						local zipName = config.currentProject..".project"
						panel.zipName = zipName
						
						panel.zipThread = lthread.newThread([[
							local proj,name,path,save = ...
							loveZip 			= require("source/libs/love-zip")
							loveZip.writeZip("projects/"..proj,name)
							local dest = (path.."/"..name):gsub("//","/")
							local remmed = os.remove(dest)
							os.rename(save..name,dest)
							love.thread.getChannel( "zipped" ):push("done")
						]])

						panel.zipThread:start( config.currentProject,zipName,config.projects[CURRENT_PROJECT].dir,SAVE_DIR )
					
						
					end

					-- editor.tempTip 		("Save Complete")
					unlockKeys()
					unlockMouse()
					setVSync( true )
					waiting = {}
				end
				return true 
			end
		end)
	end
