frt = Timer.new()
frt:start()
fnt = Font.createProportional()
fnt:setPixelSizes(0, 14)
cl1=Color.new(0,0,0)
cl2=Color.new(127,127,127,127)
cl3=Color.new(255,255,255)
cl4=Color.new(128,128,128)
cl5=Color.new(64,64,64)
pro=Image.load("res/pro.png")
pla=Image.load("res/pla.png")
pau=Image.load("res/pau.png")
sto=Image.load("res/sto.png")

ld=Image.createEmpty(480,272)
txtl=0
function loadtxt(str)
	txtl=txtl+1
	if txtl==18 then txtl=1 ld:clear() end
	ld:fontPrint(fnt, 0, 14*txtl, str, cl3)
	screen:clear()
	screen:blit(0,0,ld)
	screen.waitVblankStart()
	screen:flip()
end

loadtxt("TruFlow for PSP version 1.0")
loadtxt("by Da MerV")
loadtxt("Now Loading...")
tex={}

menu=false
meno=128
mens=1

function readart(mf)
	local file = io.open(mf)
	local str = file:read(131072)
	file:close()

	local strt = string.find(str, "JFIF")
	if strt then
		image = Image.loadFromMemory(string.sub(str,strt-6,string.find(str, string.char(255,217))+1))
	else
		strt = string.find(str, "PNG")
		if strt then
			image = Image.loadFromMemory(string.sub(str,strt,string.find(str,"IEND")+7))
		else
			image = nil
		end
	end
end

function drawTex(image,album,artist,mfl)
	screen:fillRect(0,0,128,225,cl1)
	Gu.start3d()
	temp = {{0, 0, 0, 0, 0},{image:width(), image:height(), 128, 128, 0}}
	Gu.enable(Gu.TEXTURE_2D)
	Gu.texImage(image)
	Gum.drawArray(Gu.SPRITES, Gu.TEXTURE_32BITF+Gu.VERTEX_32BITF+Gu.TRANSFORM_2D, temp)
	temp = {{0, image:height(), 0, 129, 0},{image:width(), 0, 128, 257, 0}}
	Gu.texImage(image)
	Gum.drawArray(Gu.SPRITES, Gu.TEXTURE_32BITF+Gu.VERTEX_32BITF+Gu.TRANSFORM_2D, temp)
	temp = {{Color.new(0,0,0,160), 0, 128, 0},{Color.new(0,0,0,160), 128, 128, 0},{cl1, 0, 225, 0},{cl1, 128, 225, 0}}
	Gu.disable(Gu.TEXTURE_2D)
	Gum.drawArray(Gu.TRIANGLE_STRIP, Gu.COLOR_8888+Gu.VERTEX_32BITF+Gu.TRANSFORM_2D, temp)
	Gu.end3d()

	temp = Image.createEmpty(256,256)
	temp:blit(0,0,screen,0,0,128,225)

	temp:drawLine(0,0,127,0,cl2)
	temp:drawLine(0,127,127,127,cl2)
	temp:drawLine(0,0,0,127,cl2)
	temp:drawLine(127,0,127,127,cl2)

	temp2 = Image.createEmpty(480,32)
	temp2:fontPrint(fnt, 240-(fnt:getTextSize(album)["width"]/2), 14, album, cl3)
	temp2:fontPrint(fnt, 240-(fnt:getTextSize(artist)["width"]/2), 28, artist, cl3)
	table.insert(tex, {art = temp, text = temp2, mf = mfl})
end

cfg = io.open("cache/library.index")
if cfg then
	function gcfl()
		gls = cfg:read("*l")
		return string.sub(gls,1,string.len(gls)-1)
	end
	total=gcfl()
	if not total then cfg=nil end
end
if cfg then
	loadtxt("Reading from cache...")
	total=math.floor(total)
	for i=1,total do
		sfile=gcfl()
		artist=gcfl()
		album=gcfl()
		image=Image.load("cache/"..i..".png")
		drawTex(image,album,artist,sfile)
	end
	cfg:close()
	System.currentDirectory("music")
else
	total=0
	gen=Image.load("res/gen.png")
	nl=string.char(13,10)
	loadtxt("Cache not found, indexing music...")
	function pcfg()
		cfg = io.open("cache/library.index","w+")
	end
	if not pcall(pcfg) then System.createDirectory(cache) loadtxt("Cache directory created") pcfg()  end
	cfgstr=""
	System.currentDirectory("music")
	artdir = System.listDirectory()
	loadtxt("Writing cache...")
	for i = 1, table.getn(artdir) do
		if artdir[i].directory == false then
			if string.lower(string.sub(artdir[i].name, -4)) == ".mp3" then
				total = total + 1
				loadtxt("Analyzing "..artdir[i].name)
				fstr = string.sub(artdir[i].name,1,string.len(artdir[i].name)-4)
				imgfnd=false
				ifile = io.open(fstr..".png", "rb")
				if ifile then imgfnd=true
					image = Image.loadFromMemory(ifile:read("*a"))
					ifile:close()
				end
				if not imgfnd then
					ifile = io.open(fstr..".jpg", "rb")
					if ifile then imgfnd=true
						image = Image.loadFromMemory(ifile:read("*a"))
						ifile:close()
					end
				end
				if not imgfnd then
					pcall(readart,artdir[i].name)
					if image then imgfnd=true end
				end
				if not imgfnd then
					image = gen
				end
				image:save("../cache/"..total..".png")
				Mp3me.load(artdir[i].name)
				album,artist=Mp3me.album(),Mp3me.artist()
				cfgstr=cfgstr..artdir[i].name..nl..artist..nl..album..nl
				drawTex(image,album,artist,artdir[i].name)
				image=nil
				loadtxt("Added to library")
			end
		end
	end
	cfg:write(total..nl..cfgstr)
	cfg:close()
	cfgstr=nil
end

function putTex(tex,d,vel)
	mx = 128*d+240
	if d > 1 then mx = 28*d+340 end
	if d < -1 then mx = 28*d+140 end
	my = (1-vel)*(32-((mx-240)^2/512))+(168-((mx-240)^2/3600))
	hl = math.min(16,math.max(-16,(mx-240)/8))
	_l,_r = .005*my*(128+hl),.005*my*(128-hl)
	_w = (64-math.abs(hl))*.005*my
	h = (hl*.005*my)/4
	ax,bx,cx,dx = mx-_w+h,mx+_w+h,mx-_w-h,mx+_w-h
	ay,by,cy,dy = my-_l,my-_r,my+_r,my+_l
	l,r = math.min(255,math.max(127,-mx+495)),math.min(255,math.max(127,mx+15))
	t = (-17*(mx-240)^2)/3840+255
	t1 = {{0,0,Color.new(l,l,l,t),ax,ay,0},{128,0,Color.new(r,r,r,t),bx,by,0},{0,256,Color.new(l,l,l,t),cx,cy,0},{128,256,Color.new(r,r,r,t),dx,dy,0}}
	Gu.enable(Gu.TEXTURE_2D)
	Gu.texImage(tex)
	Gu.texFilter(Gu.LINEAR, Gu.LINEAR)
	Gu.texFunc(Gu.TFX_MODULATE, Gu.TCC_RGBA)
	Gum.drawArray(Gu.TRIANGLE_STRIP, Gu.COLOR_8888+Gu.TEXTURE_32BITF+Gu.VERTEX_32BITF+Gu.TRANSFORM_2D, t1)
end

function timedis()
	tim=Mp3me.gettime()
	stim=string.sub(tim,4,5)*60+string.sub(tim,7,8)
	perc=stim*300/ttim
	screen:fontPrint(fnt, 90, 267+ofst, string.sub(tim,4,8), cl3)
	min=math.floor((ttim-stim)/60)
	sec=(ttim-stim)-(min*60)
	if min<10 then min="0"..min end
	if sec<10 then sec="0"..sec end
	screen:fontPrint(fnt, 349, 267+ofst, min..":"..sec, cl3)
end

function play()
	Mp3me.stop()
	Mp3me.load(tex[cursong].mf)
	Mp3me.play()
	tst=Mp3me.title()
	perc=0
	bar = Image.createEmpty(480,64)
	bar:fontPrint(fnt, 240-(fnt:getTextSize(tst)["width"]/2), 16, tst, cl3)
	bar:blit(90,28,pro)
	bar:blit(48,20,pla)
	tim=Mp3me.songTime()
	ttim=string.sub(tim,4,5)*60+string.sub(tim,7,8)
	pause=false
end

function txt(str,ln)
	screen:fontPrint(fnt, 0, 14*ln, str, cl3)
end

pos = {x = 1, vel = 0}
playing=false
input = Controls.read()
curdir=System.currentDirectory()
while not input:start() do
	screen:clear()
	oldinput = input
	input = Controls.read()

	if math.abs(input:analogX()) > 30 then
		targ=nil
		pos.vel = pos.vel+math.abs(input:analogX())*input:analogX()/800000
	else
		pos.vel = pos.vel/1.25
		if math.abs(pos.vel) < .0001 and not targ then
			pos.vel = 0
			pos.x = pos.x + (math.floor(pos.x+.5)-pos.x)/3
			if math.abs(math.floor(pos.x+.5)-pos.x) < .0001 then
				pos.x = math.floor(pos.x+.5)
			end
		end
	end
	if input:left() and not oldinput:left() then
		if targ then
			targ=targ-1
		else
			targ=math.floor(pos.x+.5)-1
		end
	end
	if input:right() and not oldinput:right() then
		if targ then
			targ=targ+1
		else
			targ=math.floor(pos.x+.5)+1
		end
	end
	if input:up() and not oldinput:up() and menu then
		mens=mens-1
		if mens==0 then mens=3 end
	end
	if input:down() and not oldinput:down() and menu then
		mens=mens+1
		if mens==4 then mens=1 end
	end
	if input:cross() and not oldinput:cross() then
		if menu then
			if mens==1 then
				screen:clear()
				txt("Help",1)
				txt("Cross: plays the selected album, select menu item",3)
				txt("Square: stops playing the current song",4)
				txt("Circle: pauses/plays the current song",5)
				txt("Triangle: displays/closes menu",6)
				txt("L/R: play previous/next song",7)
				txt("Left/Right: browse albums one by one",8)
				txt("Analog nub: scrolls through albums",9)
				txt("Up/Down: change selection in menu",10)
				txt("Press X to close",12)
				screen.waitVblankStart()
				screen:flip()
				while true do
					oldinput = input
					input = Controls.read()
					if input:cross() and not oldinput:cross() then break end
				end
				screen:clear()
			elseif mens==2 then
				System.removeFile("../cache/library.index")
				Mp3me.stop()
				restart=true
			else
				System.Quit()
			end
		else
			if not ofst then ofst=64 end
			targ=math.floor(pos.x+.5)
			cursong=targ
			play()
			playing = true
		end
	end
	if input:square() and not oldinput:square() and playing then
		ofst=.03125
		playing = false
		Mp3me.stop()
		bar:blit(48,20,sto)
	end
	if input:circle() and not oldinput:circle() and playing then
		Mp3me.pause()
		if pause then
			pause=false
			bar:blit(48,20,pla)
		else
			pause=true
			bar:blit(48,20,pau)
		end
	end
	if input:triangle() and not oldinput:triangle() then
		menu=not menu
	end
	if input:l() and not oldinput:l() and playing and (cursong>1) then
		cursong=cursong-1
		play()
	end
	if input:r() and not oldinput:r() and playing and (cursong<total) then
		cursong=cursong+1
		play()
	end
	if targ then
		pos.vel = 0
		pos.x = pos.x + (targ-pos.x)/5
	end
	pos.x = pos.x + pos.vel 
	if pos.x < .5 then
		pos.x = .5
		pos.vel = -(pos.vel/3)
		targ = nil
	elseif pos.x > total+.499 then
		pos.x = total+.499
		pos.vel = -(pos.vel/3)
		targ = nil
	end

	--screen:print(0,0,"fps: "..1000/frt:reset(),cl3)
	--if playing then screen:print(0,10,"playing",cl3) else screen:print(0,10,"stopped",cl3) end
	--screen:print(0,20,curdir,cl3)
	--screen:print(0,30,total.." "..type(total),cl3)
	frt:start()


	Gu.start3d()
		tile = math.floor(pos.x+.5)
		ofs = tile-pos.x
		for e=-5,0 do
			if tile+e>0 then
				putTex(tex[tile+e].art,e+ofs,math.abs(pos.vel))
			end
		end
		for e=5,0,-1 do
			if tile+e<total+1 then
				putTex(tex[tile+e].art,e+ofs,math.abs(pos.vel))
			end
		end
	Gu.end3d()
	fn1,cofs=128*ofs,Color.new(255,255,255,-1020*ofs^2+255)
	Gu.start3d()
		Gu.enable(Gu.TEXTURE_2D)
		Gu.texImage(tex[tile].text)
		Gu.texFunc(Gu.TFX_MODULATE, Gu.TCC_RGBA)
		Gum.drawArray(Gu.TRIANGLE_STRIP, Gu.COLOR_8888+Gu.TEXTURE_32BITF+Gu.VERTEX_32BITF+Gu.TRANSFORM_2D, {{0,0,cofs,fn1,30,0},{480,0,cofs,480+fn1,30,0},{0,32,cofs,fn1,62,0},{480,32,cofs,480+fn1,62,0}})
	Gu.end3d()
	if playing then
		if ofst>0 then ofst=math.floor(ofst/2) end
		pcall(timedis)
		if Mp3me.eos()=="true" then
			if cursong==total then
				ofst=.03125
				playing = false
				Mp3me.stop()
				bar:blit(48,20,sto)
			else
				cursong=cursong+1
				play()
			end
		end
	elseif ofst then
		ofst=ofst*2
		if ofst>64 then ofst=nil end
	end
	Gu.start3d()
		if ofst then
			temp = {{cl4, 90, 236+ofst, 0},{cl4, 90+perc, 236+ofst, 0},{cl5, 90, 252+ofst, 0},{cl5, 90+perc, 252+ofst, 0}}
			Gu.disable(Gu.TEXTURE_2D)
			Gum.drawArray(Gu.TRIANGLE_STRIP, Gu.COLOR_8888+Gu.VERTEX_32BITF+Gu.TRANSFORM_2D, temp)
		end
	Gu.end3d()
	if ofst then screen:blit(0,208+ofst,bar) end
	if menu then
		if meno>0 then
			meno=meno-32
		end
	else
		if meno<128 then
			meno=meno+32
		end
	end
	if meno<128 then
		Gu.start3d()
			temp = {{cl5, 352+meno, 0, 0},{cl1, 480+meno, 0, 0},{cl5, 352+meno, 272, 0},{cl1, 480+meno, 272, 0}}
			Gu.disable(Gu.TEXTURE_2D)
			Gum.drawArray(Gu.TRIANGLE_STRIP, Gu.COLOR_8888+Gu.VERTEX_32BITF+Gu.TRANSFORM_2D, temp)
		Gu.end3d()
		if mens==1 then screen:fontPrint(fnt, 356+meno, 28, "Help", cl4) screen:fontPrint(fnt, 356+meno, 42, "Reset cache", cl3) screen:fontPrint(fnt, 356+meno, 56, "Exit", cl3)
		elseif mens==2 then screen:fontPrint(fnt, 356+meno, 28, "Help", cl3) screen:fontPrint(fnt, 356+meno, 42, "Reset cache", cl4) screen:fontPrint(fnt, 356+meno, 56, "Exit", cl3)
		else screen:fontPrint(fnt, 356+meno, 28, "Help", cl3) screen:fontPrint(fnt, 356+meno, 42, "Reset cache", cl3) screen:fontPrint(fnt, 356+meno, 56, "Exit", cl4) end
	end
	screen.waitVblankStart()
	screen.flip()
	if input:select() and not oldinput:select() then
		screen:save("scrn.png")
	end
	if restart then break end
end