--[[
	UO_OGRANISER:
	'uo' (unOfficial) Version by Hoshizora [http://hoshizora.tripod.com/uo_ograniser]
	Original Concept and Program by modsyn [http://cs.ulm.edu/~jself]

	Uses LUA Player: 0.20 MOD 2 by Cools [http://www.theriddlingsphinx.com/]
	Last updated   : 2006.10.10
  ]]

----------------------
-- Import Libraries --
----------------------
require('lib/pad')
require('lib/string')

-----------------------
-- Utility Functions --
-----------------------
-- Hoshizora 2006.07.26: Load program images
function load_images()
	organisebg      =Image.load(imagesdir..'bg-organise.png')
	contextbg       =Image.load(imagesdir..'bg-context.png')
	padup           =Image.load(imagesdir..'pad-up.png')
	paddown         =Image.load(imagesdir..'pad-down.png')
	padleft         =Image.load(imagesdir..'pad-left.png')
	padright        =Image.load(imagesdir..'pad-right.png')
	padtriangle     =Image.load(imagesdir..'pad-triangle.png')
	padsquare       =Image.load(imagesdir..'pad-square.png')
	padcircle       =Image.load(imagesdir..'pad-circle.png')
	padcross        =Image.load(imagesdir..'pad-cross.png')
	padl            =Image.load(imagesdir..'pad-l.png')
	padr            =Image.load(imagesdir..'pad-r.png')
	padselect       =Image.load(imagesdir..'pad-select.png')
	padstart        =Image.load(imagesdir..'pad-start.png')
	analogleft      =Image.load(imagesdir..'analog-left.png')
	iconbattery     =Image.load(imagesdir..'icon-battery.png')
	iconlistlocked  =Image.load(imagesdir..'icon-listlocked.png')
	iconlistunlocked=Image.load(imagesdir..'icon-listunlocked.png')
	iconitemnoedit  =Image.load(imagesdir..'icon-itemnoedit.png')
	iconitemrepair  =Image.load(imagesdir..'icon-itemrepair.png')
	iconitemrepair0 =Image.load(imagesdir..'icon-itemrepair0.png')
	iconitemignore  =Image.load(imagesdir..'icon-itemignore.png')
	iconitemignore0 =Image.load(imagesdir..'icon-itemignore0.png')
	iconbarstatus   =Image.load(imagesdir..'icon-barstatus.png')
	iconbarhelp     =Image.load(imagesdir..'icon-barhelp.png')
	iconbarprogress =Image.load(imagesdir..'icon-barprogress.png')
	textascending   =Image.load(imagesdir..'text-ascending.png')
	textdescending  =Image.load(imagesdir..'text-descending.png')
	textformatted   =Image.load(imagesdir..'text-formatted.png')
	textoriginal    =Image.load(imagesdir..'text-original.png')
	text__sce       =Image.load(imagesdir..'text-__sce.png')
	textirshell     =Image.load(imagesdir..'text-irshell.png')
end

-- Hoshizora 2006.07.26: Pre-splash screen to initialise variables
function osPreSplashScreen()
	os:clear()
	os:print(fontdim,fontdim*28,'Initialising... please wait',black)
	os:print(fontdim,fontdim*31,msgSplashProgInfo1,black)
	os:print(fontdim,fontdim*32,msgSplashProgInfo2,black)
	os:print(fontdim*49,fontdim*32,pad_left_char(progver,10,' ',1),black)
	screen:blit(0,0,splashbg,0,0,splashbg:width(),splashbg:height(),false)
	screen:blit(0,0,os)
	screen.waitVblankStart()
	screen.flip()
end

-- Hoshizora 2006.07.13: New splash screen! :)
function osSplashScreen()
	msg=msgSplashProgInfo2
  while true do
		os:clear()
		os:print(fontdim,fontdim*28,'Press',black)
		os:print(fontdim,fontdim*31,msgSplashProgInfo1,black)
		os:print(fontdim,fontdim*32,msg,black)
		os:print(fontdim*49,fontdim*32,pad_left_char(progver,10,' ',1),black)
		screen:blit(0,0,splashbg,0,0,splashbg:width(),splashbg:height(),false)
		screen:blit(0,0,os)
		screen:blit(fontdim*7,fontdim*28,padstart)
		screen.waitVblankStart()
		screen.flip()

    Pad:Update()
		if Pad.Ax<(analogDeadZone*-1) then
			-- Pushed LEFT (Analog Stick)
			-- Hoshizora 2006.07.21: Added exit functionality to the splash screen
			ans=confirm(quittitle,msgYNQuitOgraniser)
			if ans then System.Quit() -- Requires Lua Player .17dk_2 / .20 MOD and above to work
			else msg=msgSplashProgInfo2 end
    elseif Pad.tSt then
			break
		elseif Pad.tSl then
			-- Pushed Select
			-- Hoshizora 2006.07.20: Added screen capture functionality to the splash screen
			-- Hoshizora 2006.07.27: Added support for multiple screen captures
			msg=screen_save()
		end
	end
end

-- Hoshizora 2006.10.10: Quick fix to support Dark_AleX's new 2.71 SE Custom Firmware mod
function getGameDir()
	local files={}
	local se=false

	if dirExists(device..pspdir,pspgame150dir)==1 then
		files=System.listDirectory(device..pspdir..pspgame150dir)
		for index,file in ipairs(files) do
			if file.directory and not (file.name=='.' or file.name=='..') then -- GAME150 folder is not empty, good chance that the PSP is installed with SE mod
				se=true
				break
			end
		end
	end
	if se then return pspdir..pspgame150dir end
	return pspdir..pspgamedir
end

-- Hoshizora 2006.07.11: New ogranise screen with progress bar! :)
-- Hoshizora 2006.08.24: Improved visual appearance of the progress bar
function osTouchProgressScreen(shortcutdir,curri,maxi,msState)
	local pbarheight=fontdim-1
	local pbarwidth=296
	local pbarcurrwidth=pbarwidth/maxi*(curri-1)
	local pbarpercent=math.floor((curri-1)/maxi*100)..'%'
	local obarsh=2
	local pbarsh=2
	local shx=11
	local shy=16
	local barsections=50
	local barseparatorwidth=1
	local barseparatorsh

	os:print(fontdim+2,fontdim+2,organisetitle,black)
	os:print(fontdim*shx,fontdim*13,'Organising: '..pad_right(shortcutdir,26),black)
	os:print(fontdim*shx,fontdim*14,'Completed '..curri-1 ..' out of '..maxi,black)
	os:print(fontdim*shx,fontdim*19,msState,black)
	if msState=='Done.' then
		os:print(fontdim*shx,fontdim*20,'Press   to view '..reporttitle..'.',black)
	else
		os:print(fontdim*shx,fontdim*20,'Do not remove the Memory Stick.',black)
	end

	-- Draw the progress bar!
	os:fillRect(fontdim*shx+pbarsh,fontdim*shy,pbarcurrwidth,pbarheight,green) -- The progress bar itself!
	for i=1,barsections-1 do -- Draw thin separators along the width of the bar
		barseparatorsh=math.floor(pbarwidth/barsections*i)
		os:fillRect(fontdim*shx+pbarsh+barseparatorsh,fontdim*shy,barseparatorwidth,pbarheight)
	end
	os:print((screenwidth-fontdim*string.len(pbarpercent))/2,fontdim*shy,pbarpercent,black) -- Percentage completed

	screen:blit(0,0,contextbg,0,0,contextbg:width(),contextbg:height(),false)
	screen:blit(fontdim*shx,fontdim*shy-obarsh,iconbarprogress)
	osPrintBatteryLife()
	screen:blit(0,0,os)
	if msState=='Done.' then
		screen:blit(fontdim*17,fontdim*20,padcross)
	end
	screen.waitVblankStart()
	screen.flip()
end

-- Hoshizora 2006.07.07: Modified function touch_icon to support file counter
-- Hoshizora 2006.07.12: Rewrote the touch routine to support for multiple files within the shortcut dir
-- Hoshizora 2006.07.15: Support for directory renaming to repair/restore corrupted icons
-- Hoshizora 2006.07.22: Support for iR Shell folder name scheme
-- Hoshizora 2006.08.05: Added support for restore custom list
function touch_shortcut(proglist,list1_5item,repair,curri,maxi)
	local files={}
	local shortcutfiles={}
	local shortcutdir=list1_5item.name
	local repairThisItem=list1_5item.flag=='1'
	local oldProgDir=''
	local oldShortcutDir=''
	local newProgDir=''
	local sce='__SCE__'
	local irs='~1%'
	local scd='%'
	local success=true
	local errcode=''
	local inf,outf,msg,block,filedata,ok,prgdir,scdir,padlen

	local log=io.open(device..progextdir..logfile,'a+') -- Log this operation
	if debug and log then log:write(pad_right('BEGIN: Shortcut '..shortcutdir,maxtitlelen)..'\n') end

	osClear()
	osTouchProgressScreen(shortcutdir,curri,maxi,'Reading...')
	files=System.listDirectory(device..gamedir..shortcutdir)
	for index,file in ipairs(files) do
		if not (file.directory or file.name=='.' or file.name=='..') then
			-- Read a file to memory
			inf,msg=io.open(device..gamedir..shortcutdir..'/'..file.name,'rb')
			if inf then
				block=''
				filedata={}
				repeat
					block=inf:read(1024*8)
					table.insert(filedata,block)
				until block==nil
				inf:close()
				table.insert(shortcutfiles,{name=file.name,data=filedata})

				-- Remove the file from MS after the read
				if not fileRemove(device..gamedir..shortcutdir..'/'..file.name) then -- Assertion check
					if debug and log then log:write(pad_right('  fileRemove('..file.name..')',maxtitlelen)..'  Error\n') end
					success=false
					errcode='A'
				end
			else
				if debug and log then log:write(pad_right('  io.open('..file.name..',rb): '..msg,maxtitlelen)..'  Error\n') end
				success=false
				errcode=errcode..'B'
			end
		end
	end

	-- Remove the shortcut directory (after all the files have been processed)
	if dirRemove(device..gamedir,shortcutdir)==0 then -- Assertion check
		if debug and log then log:write(pad_right('  dirRemove()',maxtitlelen)..'  Error\n') end
		success=false
		errcode=errcode..'C'
	end

	-- Update the progress screen
	osClear()
	osTouchProgressScreen(shortcutdir,curri,maxi,'Saving...')

	-- Create the (new) shortcut directory, aka 'touching' the directory and modifying the timestamp
	-- Repair corrupted data icons using __SCE__foldername/%__SCE__foldername scheme
	if repair==1 and repairThisItem then
		ok=true
		oldShortcutDir=shortcutdir
		if (string.startsWith(shortcutdir,scd) or string.endsWith(shortcutdir,scd)) and not string.endsWith(shortcutdir,irs) then
			-- foldername/foldername% -=> __SCE__foldername/%__SCE__foldername
			-- Fixes %(_)sce(_)foldername and folder length errors
			ok=false
			scdir=string_format(shortcutdir,2)
			for i=1,table.getn(proglist) do -- Assert shortcut name have a matching program name
				if string.upper(proglist[i])==scdir then -- We have a match!
					oldProgDir=proglist[i]
					newProgDir=sce..fix_string_len(string_format(oldProgDir,0),maxSCEFolderNameLen-string.len(sce))
					shortcutdir=scd..newProgDir
					ok=true
					break
				end
			end
		elseif string.endsWith(shortcutdir,irs) then
			-- foldername                     _/folder~1% -=> __SCE__foldername/%__SCE__foldername
			ok=false
			scdir=string_format(shortcutdir,1)
			if string.len(scdir)>5 then scdir=string.sub(scdir,1,5) end
			for i=1,table.getn(proglist) do -- Assert shortcut name have a matching program name
				if string_format(proglist[i],6)==scdir then -- We have a match!
					oldProgDir=proglist[i]
					newProgDir=sce..fix_string_len(string_format(oldProgDir,3),maxSCEFolderNameLen-string.len(sce))
					shortcutdir='%'..newProgDir
					ok=true
					break
				end
			end
		else ok=false end
		if ok and string.upper(newProgDir)~=string.upper(oldProgDir) then --If newProgDir==oldProgDir, then the program dir is already repaired, so skip this section
			-- Let's do a check on the new dir names to make sure the names are unique and not already in use, if not unique, we'll skip this section
			if dirExists(device..gamedir,newProgDir)==1 or dirExists(device..gamedir,shortcutdir)==1 then ok=false
			else ok=true end
			if ok then
				-- The program dir simply needs to be renamed to match the shortcut dir name
				if dirRename(device..gamedir,oldProgDir,newProgDir)==0 then -- Assertion check
					if debug and log then log:write(pad_right('  repair=1: dirRename()',maxtitlelen)..'  Error\n') end
					shortcutdir=oldShortcutDir -- Rename failed, so revert new shortcut dir to old shortcut dir name
					success=false
					errcode=errcode..'D'
				end
			else
				if debug and log then
					log:write(pad_right('  repair=1: Duplicate dir name exists:',maxtitlelen)..'  Error\n')
					log:write(pad_right('    '..newProgDir,maxtitlelen)..'  Error\n')
				end
				shortcutdir=oldShortcutDir -- Rename failed, so revert new shortcut dir to old shortcut dir name
				success=false
				errcode=errcode..'E'
			end
		elseif not ok then
			if debug and log then log:write(pad_right('  repair=1: program=shortcut not found',maxtitlelen)..'  Error\n') end
			shortcutdir=oldShortcutDir -- Rename failed, so revert new shortcut dir to old shortcut dir name
			success=false
			errcode=errcode..'F'
		end

	-- Repair corrupted data icons using foldername                     _/folder~1% scheme
	elseif repair==2 and repairThisItem then
		ok=true
		oldShortcutDir=shortcutdir
		if (string.startsWith(shortcutdir,scd) or string.endsWith(shortcutdir,scd)) and not string.endsWith(shortcutdir,irs) then
			-- __SCE__foldername/%__SCE__foldername -=> foldername                     _/folder~1%
			--               foldername/foldername% -=> foldername                     _/folder~1%
			ok=false
			scdir=string_format(shortcutdir,2)
			for i=1,table.getn(proglist) do -- Assert shortcut name have a matching program name
				if string.upper(proglist[i])==scdir then -- We have a match!
					oldProgDir=proglist[i]
					prgdir=string_format(oldProgDir,0)
					scdir=string_format(prgdir,7) -- Remove spaces between the folder names (if any)
					if string.len(scdir)>=(minShortcutDirSchemeLen-3) then
						newProgDir=pad_right_char(prgdir,minProgramDirSchemeLen,' ',0)..' 1'
						shortcutdir=string.sub(scdir,1,minShortcutDirSchemeLen-3)..irs
					else
						shortcutdir=pad_right_char(scdir,minShortcutDirSchemeLen-4,'_',1)..'_'..irs
						padlen=minShortcutDirSchemeLen-1-string.len(scdir)
						prgdir=prgdir..pad_right_char('',padlen,'_',0)
						newProgDir=pad_right_char(prgdir,minProgramDirSchemeLen-1,' ',0)..'1'
					end
					ok=true
					break
				end
			end
		elseif not (string.startsWith(shortcutdir,scd) or string.endsWith(shortcutdir,scd)) then ok=false end
		if ok and string.upper(newProgDir)~=string.upper(oldProgDir) then --If newProgDir==oldProgDir, then the program dir is already repaired, so skip this section
			-- Let's do a check on the new dir names first
			if dirExists(device..gamedir,newProgDir)==1 or dirExists(device..gamedir,shortcutdir)==1 then ok=false
			else ok=true end
			if ok then
				-- The program dir simply needs to be renamed
				if dirRename(device..gamedir,oldProgDir,newProgDir)==0 then -- Assertion check
					if debug and log then log:write(pad_right('  repair=2: dirRename()',maxtitlelen)..'  Error\n') end
					shortcutdir=oldShortcutDir -- Rename failed, so revert new shortcut dir to old shortcut dir name
					success=false
					errcode=errcode..'G'
				end
			else
				if debug and log then
					log:write(pad_right('  repair=2: Duplicate dir name exists:',maxtitlelen)..'  Error\n')
					log:write(pad_right('    '..newProgDir,maxtitlelen)..'  Error\n')
				end
				shortcutdir=oldShortcutDir -- Rename failed, so revert new shortcut dir to old shortcut dir name
				success=false
				errcode=errcode..'H'
			end
		elseif not ok then
			if debug and log then log:write(pad_right('  repair=2: program=shortcut not found',maxtitlelen)..'  Error\n') end
			shortcutdir=oldShortcutDir -- Rename failed, so revert new shortcut dir to old shortcut dir name
			success=false
			errcode=errcode..'I'
		end
	
	-- Restore corrupted data icons using foldername/foldername% scheme
	elseif repair==3 and repairThisItem then
		ok=true
		oldShortcutDir=shortcutdir
		if (string.startsWith(shortcutdir,scd) or string.endsWith(shortcutdir,scd)) and not string.endsWith(shortcutdir,irs) then
			-- __SCE__foldername/%__SCE__foldername -=> foldername/foldername%
			-- Fixes folder length errors
			ok=false
			scdir=string_format(shortcutdir,2)
			for i=1,table.getn(proglist) do -- Assert shortcut name have a matching program name
				if string.upper(proglist[i])==scdir then -- We have a match!
					oldProgDir=proglist[i]
					newProgDir=fix_string_len(string_format(oldProgDir,0),maxFPFFolderNameLen)
					shortcutdir=newProgDir..scd
					ok=true
					break
				end
			end
		elseif string.endsWith(shortcutdir,irs) then
			-- foldername                     _/folder~1% -=> foldername/foldername%
			ok=false
			scdir=string_format(shortcutdir,1)
			if string.len(scdir)>5 then scdir=string.sub(scdir,1,5) end
			for i=1,table.getn(proglist) do -- Assert shortcut name have a matching program name
				if string_format(proglist[i],6)==scdir then -- We have a match!
					oldProgDir=proglist[i]
					newProgDir=fix_string_len(string_format(oldProgDir,3),maxFPFFolderNameLen)
					shortcutdir=newProgDir..scd
					ok=true
					break
				end
			end
		else ok=false end
		if ok and string.upper(newProgDir)~=string.upper(oldProgDir) then --If newProgDir==oldProgDir, then the program dir is already restored, so skip this section
			-- Let's do a check on the new dir names first
			if dirExists(device..gamedir,newProgDir)==1 or dirExists(device..gamedir,shortcutdir)==1 then	ok=false
			else ok=true end
			if ok then
				-- The program dir simply needs to be renamed
				if dirRename(device..gamedir,oldProgDir,newProgDir)==0 then -- Assertion check
					if debug and log then log:write(pad_right('  repair=3: dirRename()',maxtitlelen)..'  Error\n') end
					shortcutdir=oldShortcutDir -- Rename failed, so revert new shortcut dir to old shortcut dir name
					success=false
					errcode=errcode..'J'
				end
			else
				if debug and log then
					log:write(pad_right('  repair=3: Duplicate dir name exists:',maxtitlelen)..'  Error\n')
					log:write(pad_right('    '..newProgDir,maxtitlelen)..'  Error\n')
				end
				shortcutdir=oldShortcutDir -- Rename failed, so revert new shortcut dir to old shortcut dir name
				success=false
				errcode=errcode..'K'
			end
		elseif not ok then
			if debug and log then log:write(pad_right('  repair=3: program=shortcut not found',maxtitlelen)..'  Error\n') end
			shortcutdir=oldShortcutDir -- Rename failed, so revert new shortcut dir to old shortcut dir name
			success=false
			errcode=errcode..'L'
		end
	end
	
	-- Create the shortcut dir using the original/fixed name
	if dirExists(device..gamedir,shortcutdir)==0 then -- Assertion check
		if dirCreate(device..gamedir,shortcutdir)==0 then -- Assertion check
			if debug and log then log:write(pad_right('  dirCreate()',maxtitlelen)..'  Error\n')	end
			shortcutdir=oldShortcutDir -- Rename failed, so revert new shortcut dir to old shortcut dir name
			success=false
			errcode=errcode..'M'
			if dirCreate(device..gamedir,shortcutdir)==0 then -- Assertion check
				if debug and log then log:write(pad_right('  dirCreate()',maxtitlelen)..'  Error\n')	end
				shortcutdir=device..gamedir -- Recover the files in game dir
				success=false
				errcode=errcode..'N'
			end
		end
	else
		if debug and log then
			log:write(pad_right('  Duplicate shortcut dir name exists:',maxtitlelen)..'  Error\n')
			log:write(pad_right('    '..shortcutdir,maxtitlelen)..'  Error\n')
		end
		shortcutdir=oldShortcutDir -- Rename failed, so revert new shortcut dir to old shortcut dir name
		success=false
		errcode=errcode..'O'
		if dirCreate(device..gamedir,shortcutdir)==0 then -- Assertion check
			if debug and log then log:write(pad_right('  dirCreate()',maxtitlelen)..'  Error\n')	end
			shortcutdir=device..gamedir -- Recover the files in game dir
			success=false
			errcode=errcode..'P'
		end
	end

	-- Copy the files in memory back to the shortcut directory
	for index,file in ipairs(shortcutfiles) do
		outf,msg=io.open(device..gamedir..shortcutdir..'/'..file.name,'wb')
    if outf then
			for idx,dat in pairs(file.data) do
				outf:write(dat)
			end
			outf:flush()
			outf:close()
		else
			if debug and log then log:write(pad_right('  io.open('..file.name..',wb): '..msg,maxtitlelen)..'  Error\n') end
			success=false
			errcode=errcode..'Q'
		end
	end

	if debug and log then log:write(pad_right('END: Shortcut '..shortcutdir,maxtitlelen)..'  '..print_result(success)..'\n') end
	if not debug then
		msg=string_format(shortcutdir,0)
		if success and log then
			log:write(pad_right(msg,maxtitlelen)..'  OK\n')
		else
			log:write(pad_right(msg,maxtitlelen)..'  Error:'..errcode..'\n')
		end
	end

	if log then
		log:flush()
		log:close()
	end
  System.sleep(1000)

	-- Update the progress screen
	if curri==maxi then
		osClear()
		osTouchProgressScreen('',curri+1,maxi,'Done.')
		waitX()
	end

	-- Returns the modified shortcutdir for the saveCustomList() function
	return shortcutdir
end

function print_result(ok)
	if ok then return 'OK' end
	return 'Failed'
end

function fix_string_len(str,len)
	if string.len(str)>len then -- return concatenated string
		return string.sub(str,1,len)
	end
	return str
end

-- Hoshizora 2006.07.22: Append x no. of chars to the right
function pad_right_char(str,maxlen,char,concat)
	local pad=''
	local strlen=string.len(str)
	if char==nil or string.len(char)~=1 then char=' ' end
	if maxlen==nil then maxlen=maxSCEFolderNameLen end
	if strlen<maxlen then
		for i=1,maxlen-strlen do
			pad=pad..char
		end
		return str..pad
	end
	if concat==1 then
		return fix_string_len(str,maxlen)
	end
	return str
end

-- Hoshizora 2006.07.22: Append x no. of chars to the right
function pad_left_char(str,maxlen,char,concat)
	local pad=''
	local strlen=string.len(str)
	if char==nil or string.len(char)~=1 then char=' ' end
	if maxlen==nil then maxlen=maxSCEFolderNameLen end
	if strlen<maxlen then
		for i=1,maxlen-strlen do
			pad=pad..char
		end
		return pad..str
	end
	if concat==1 then
		return fix_string_len(str,maxlen)
	end
	return str
end

-- Hoshizora 2006.07.13: Append white spaces to the right get a nicely formatted table effect
-- Hoshizora 2006.07.23: Code updated to use fix_string_len()
function pad_right(str,maxlen)
	local white=' '
	local pad=''
	local strlen=string.len(str)
	if maxlen==nil then maxlen=maxtitlelen end
	if strlen<maxlen then
		for i=1,maxlen-strlen do
			pad=pad..white
		end
		return str..pad
	end
	return fix_string_len(str,maxlen-2)..'..'
end

-- Hoshizora 2006.07.14: Append white spaces to the left to get a nicely formatted table effect
-- Hoshizora 2006.07.23: Code updated to use fix_string_len()
function pad_left(str,maxlen)
	local white=' '
	local pad=''
	local strlen=string.len(str)
	if maxlen==nil then maxlen=maxtitlelen end
	if strlen<maxlen then
		for i=1,maxlen-strlen do
			pad=pad..white
		end
		return pad..str
	end
	return fix_string_len(str,maxlen-2)..'..'
end

-- Hoshizora 2006.07.25: Take and save multiple screenshots to your memory stick!
function screen_save()
	local maxn=9999
	local scrsdir=device..progextdir..scrsavedir..'/'
	local snapfile='Snap'..pad_left_char('1',4,'0',1)..'.png'
	local snapfile0='Snap'..pad_left_char('0',4,'0',1)..'.png'
	local result=dirExists(device..progextdir,scrsavedir)
	local msg
	
	if result==1 then
		for i=1,maxn do
			snapfile='Snap'..pad_left_char(i,4,'0',1)..'.png'
			msg=msgScreenCaptured..snapfile
			if not fileExists(scrsdir..snapfile) then break end -- We have found an empty file slot
			if i==maxn then
				snapfile=snapfile0  -- All file slots taken, so we will write to the default 'zero' file only
				msg=msgScreenCaptured..snapfile..' (no more slots)'
			end
		end
	elseif result==0 then
		msg=msgScreenCaptured..snapfile
		if dirCreate(device..progextdir,scrsavedir)==0 then
			snapfile=nil
			msg=msgScrSaveError -- Something went wrong, we will not write the file to anywhere else
		end
	else -- result==-1
		snapfile=nil
		msg=msgScrSaveError -- Something went wrong, we will not write the file to anywhere else
	end
	if snapfile~=nil then
		screen:save(scrsdir..snapfile)
		return msg
	end
end

-- Hoshizora 2006.07.09: Remove log file (if exist)
function delLogFile()
	if fileExists(device..progextdir..logfile) then
		System.removeFile(device..progextdir..logfile)
	end
end

-- Hoshizora 2006.07.14: -- New report screen! :)
function osReportScreen()
	local lines={}
	local idx=1
	local ss=23 -- Changed for the new tab look
	local error=false
	local errcodepage=false
	local msg=msgReportScreen
	local inf,tlen,ans

	-- Read the log file to memory
	inf,msg=io.open(device..progextdir..logfile,'r')
	if inf then
		msg=msgReportScreen
		for line in inf:lines() do
			if not error then
				if string.contains(string.sub(line,maxtitlelen),'Error:') then
					msg=msgViewErrorCode
					error=true
				end
			end
			if not debug then table.insert(lines,1,line) -- Print the list in proper (reversed) order
			else table.insert(lines,line) end
		end
		inf:close()
	end

	cprint_report(reporttitle,lines,idx,ss,msg)
	tlen=table.getn(lines)
  while true do
	  Pad:Update()
		if Pad.tLr and tlen>ss and not errcodepage then -- Use this only for multi-page report
			-- Pushed RIGHT
			if idx+ss<=tlen then -- Go to next page
				idx=idx+ss
			end
			cprint_report(reporttitle,lines,idx,ss,msgReportScreen)
		elseif Pad.tLl and tlen>ss and not errcodepage then -- Use this only for multi-page report
			-- Pushed LEFT
			if idx-ss>=1 then -- Go to prev page
				idx=idx-ss
			end
			cprint_report(reporttitle,lines,idx,ss,msgReportScreen)
		elseif Pad.tRr then
			-- Pushed CIRCLE
			errcodepage=false
			cprint_report(reporttitle,lines,idx,ss,msgReportScreen)
		elseif Pad.tRd then
			-- Pushed CROSS
			errcodepage=true
			cprint_errorcodes()
		elseif Pad.Ax<(analogDeadZone*-1) then
			-- Pushed LEFT (Analog Stick)
			ans=confirm(quittitle,msgYNQuitOgraniser)
			if ans then
				if not debug then delLogFile() end
				System.Quit() -- Requires Lua Player .17dk_2 / .20 MOD and above to work
			end
			if errcodepage then cprint_errorcodes()
			else cprint_report(reporttitle,lines,idx,ss,msgReportScreen) end
		elseif Pad.tSt then
			if not debug then delLogFile() end
			break
		elseif Pad.tSl then
			-- Hoshizora 2006.07.27: Added support for multiple screen captures
			msg=screen_save()
			if errcodepage then cprint_errorcodes(msg)
			else cprint_report(reporttitle,lines,idx,ss,msg) end
		end
	end
end

-- Hoshizora 2006.07.14: Helper function to print the report list
function cprint_report(title,lines,idx,ss,statusBarMsg)
	local st=4
	local tlen,totpages,currpage
  
	if statusBarMsg==nil then statusBarMsg='' end
	osClear()
  os:print(fontdim+2,fontdim+2,title,black)
	os:print(fontdim*3,fontdim*st,pad_right('Title',maxtitlelen)..'  Result',blue)
	tlen=table.getn(lines)
  for i=idx,(idx+ss-1) do
    if i>tlen then break end -- eof
		-- Hoshizora 2006.08.02: Print the lines using alternate colours for easy viewing
		if string.contains(string.sub(lines[i],maxtitlelen),'Error:') then
			os:print(fontdim*3,fontdim*(i-idx+st+1),lines[i],ltred)
		else
			if math.fmod(i,2)==1 then
				os:print(fontdim*3,fontdim*(i-idx+st+1),lines[i],white)
			else
				os:print(fontdim*3,fontdim*(i-idx+st+1),lines[i],ltblue)
			end
		end
  end

	os:print(fontdim*3,fontdim*32,statusBarMsg,white)
	screen:blit(0,0,organisebg,0,0,organisebg:width(),organisebg:height(),false)
	screen:blit(0,screenheight-iconbarstatus:height(),iconbarstatus)
	osPrintBatteryLife()
	osPrintReportScreenPad(statusBarMsg)

	-- Get total no. of pages
	totpages=math.ceil(tlen/ss)
	currpage=math.ceil(idx/ss)
	if totpages>1 then
		os:print(fontdim*46,fontdim*29,pad_left('Page '..currpage..'/'..totpages,10),black)
	end
	if totpages>1 and currpage<=totpages and currpage~=1 then
		screen:blit(fontdim*57,fontdim*29,padleft)
	end		
	if totpages>1 and currpage>=1 and currpage~=totpages then
		screen:blit(fontdim*58,fontdim*29,padright)
	end

	screen:blit(0,0,os)
	screen.waitVblankStart()
  screen.flip()
end

-- Hoshizora 2006.08.03: On-screen Error Codes quick reference guide (accessible from the Summary Report screen)
function cprint_errorcodes(msg)
	if msg==nil then msg=msgErrorCodeScreen end
	osClear()
	os:print(fontdim+6,fontdim+2,errcodetitle,black)
	os:print(fontdim*3,fontdim*4, 'Code   Description',blue)
	os:print(fontdim*3,fontdim*5, 'A      Error in removing a file from Shortcut folder',white)
	os:print(fontdim*3,fontdim*6, 'B      Error in reading a file from Shortcut folder',ltblue)
	os:print(fontdim*3,fontdim*7, 'C      Error in removing the Shortcut folder',white)
	os:print(fontdim*3,fontdim*8, 'D,G,J  Error in renaming the Program folder',ltblue)
	os:print(fontdim*3,fontdim*9, 'E,H,K  Duplicate Program folder name exists',white)
	os:print(fontdim*3,fontdim*10,'F,I,L  Unable to find Program:Shortcut folder pair',ltblue)
	os:print(fontdim*3,fontdim*11,'M,N,P  Error in creating the Shortcut folder',white)
	os:print(fontdim*3,fontdim*12,'O      Duplicate Shortcut folder name exists',ltblue)
	os:print(fontdim*3,fontdim*13,'Q      Error in writing a file to Shortcut folder',white)
	os:print(fontdim*3,fontdim*32,msg,white)
	screen:blit(0,0,organisebg,0,0,organisebg:width(),organisebg:height(),false)
	screen:blit(0,screenheight-iconbarstatus:height(),iconbarstatus)
	osPrintBatteryLife()
	osPrintReportScreenPad(msg)
	screen:blit(0,0,os)
	screen.waitVblankStart()
	screen.flip()
end

function osPrintReportScreenPad(msg)
	if msg==msgReportScreen then
		screen:blit(fontdim*9,fontdim*32,padstart)
		screen:blit(fontdim*43,fontdim*32,analogleft)
	elseif msg==msgViewErrorCode then
		screen:blit(fontdim*34,fontdim*32,padcross)
	elseif msg==msgErrorCodeScreen then
		screen:blit(fontdim*9,fontdim*32,padcircle)
		screen:blit(fontdim*42,fontdim*32,analogleft)		
	end
end

-- Hoshizora 2006.07.11: Recycle the table by removing all the elements in the table
function table.del(list)
	local n=table.getn(list)
	if n==0 then return end
	for i=1,n do
		table.remove(list)
	end
end

-- Hoshizora 2006.07.21: Updated to support iR Shell compatible folder naming scheme
function getGameList(prog1_5,list1_5,clist1_5,list1_0)
	local	files=System.listDirectory(device..gamedir)
	local tmplist={}
	local listdat,strf

	table.del(prog1_5)
	table.del(list1_5)
	table.del(clist1_5)
	table.del(list1_0)
	-- 1st pass: Separate dir names with % in 1.5 list and those without in 1.0 list
	for index,file in ipairs(files) do
		if file.directory and not (file.name=='.' or file.name=='..') then
			if folder_scheme_match(file.name,'[ _]+[1_]$') then
				table.insert(prog1_5,file.name)
			elseif string.endsWith(file.name,'~1%') then
				table.insert(tmplist,{name=file.name,flag='1'})
			elseif string.startsWith(file.name,'%') or string.endsWith(file.name,'%') then
				table.insert(list1_5,{name=file.name,flag='1'})
			else
				table.insert(list1_0,{name=file.name,flag='1'})
			end
		end
	end
	-- 2nd pass: Remove 1.5 titles in 1.0 list
	for i=1,table.getn(list1_5) do
		strf=string_format(list1_5[i].name,2)
		for j=1,table.getn(list1_0) do
			if strf==string.upper(list1_0[j].name) then -- We have a match!
				listdat=table.remove(list1_0,j) -- Remove the 1.5 title in the 1.0 list
				table.insert(prog1_5,listdat.name) -- Insert the 1.5 title into the 1.5 program list
				break -- We can exit the inner loop
			end
		end
	end
	-- Insert the remaining titles in tmplist to 1.5 list
	n=table.getn(tmplist)
	if n>0 then
		for i=1,n do
			table.insert(list1_5,table.remove(tmplist))
		end
	end

	-- Sort the initial list in ascending order
	tableSortAsc(list1_0)
	tableSortAsc(list1_5)

	-- Set custom saved list (if available)
	setCustomList(list1_5,clist1_5)
	if table.getn(clist1_5)>0 then
		getCustomList(list1_5,clist1_5)
	end
end

function getCustomList(list,clist)
	table.del(list)
	for i=1,table.getn(clist) do
		-- Hoshizora 2006.08.07: The flag key fails to return the correct value using table.insert(list,clist[i])
		table.insert(list,{name=clist[i].name,flag=clist[i].flag})
	end
end

-- Hoshizora 2006.08.07: Creates a custom list from Custom.dat file
function setCustomList(list1_5,clist1_5)
	local tmplist={}
	local remlist={}
	local n,strf,found

	loadCustomList(clist1_5) -- Load custom list (if available)
	if table.getn(clist1_5)==0 then return end -- No custom list to process so just return

	-- 1st pass: Find new titles not from the custom list and gather titles no longer in saved list
	for i=1,table.getn(list1_5) do
		table.insert(tmplist,list1_5[i])
	end
	for i=1,table.getn(clist1_5) do
		strf=string.upper(clist1_5[i].name)
		found=false
		for j=1,table.getn(tmplist) do
			if strf==string.upper(tmplist[j].name) then -- We have a match!
				table.remove(tmplist,j)
				found=true
				break
			end
		end
		if not found then	table.insert(remlist,strf) end -- This saved title is no longer in GAME folder
	end
	-- 2nd pass: Remove titles no longer in saved list and combine new titles to custom list
	for i=1,table.getn(remlist) do
		for j=1,table.getn(clist1_5) do
			if remlist[i]==string.upper(clist1_5[j].name) then -- We have a match!
				table.remove(clist1_5,j) -- Remove the obselete title from the custom list
				break
			end
		end
	end
	n=table.getn(tmplist)
	if n==0 then return end -- No new titles to process so just return
	for i=1,n do -- Insert the new titles to the top of the custom list
		table.insert(clist1_5,1,tmplist[n-i+1])
	end
end

function loadCustomList(list)
	local inf,pos

	if type(list)~='table' then return end
	inf=io.open(device..progextdir..customsavefile,'r')
	if inf then
		for line in inf:lines() do
			if not string.startsWith(line,'*') then -- Ignore a comment line
				pos=string.find(line,':')
				if pos~=nil then
					table.insert(list,{name=string.sub(line,1,pos-1),flag=string.sub(line,pos+1)})
				end
			end
		end
		inf:close()
	end
end

function saveCustomList(list)
	local outf,n

	if type(list)~='table' then return end
	outf=io.open(device..progextdir..customsavefile,'w+')
	outf:write('** This file is automatically generated by uo_Ograniser. Please do not edit! **\n')
	n=table.getn(list)
	if outf then
		for i=1,n do
			outf:write(list[i].name..':'..list[i].flag)
			if i~=n then outf:write('\n') end
		end
		outf:flush()
		outf:close()
	end
end

function cprint_list(lines,ls,st,ss,idx,fmtlist)
	local tlen=table.getn(lines)
	local color

	for i=st,(st+ss) do
    if i>tlen then break end
    if     i==idx            then color=blue
    elseif math.fmod(i,2)==1 then color=white
		else                          color=ltblue end
		-- Hoshizora 2006.07.08: Pre-format homebrew titles before printing to screen
		if lines[i]~=nil then
			if fmtlist then
				os:print(fontdim*5,fontdim*(i-st+ls),string_format(lines[i].name,0),color)
			else
				os:print(fontdim*5,fontdim*(i-st+ls),lines[i].name,color)
			end
		end
  end
end

function cprint_list_icons(lines,ls,st,ss,repair,title)
	local tlen=table.getn(lines)

	for i=st,(st+ss) do
    if i>tlen then break end
		-- Hoshizora 2006.07.24: Icon to indicate whether the item will be repaired/ignored during organising
		if title==list1_0title then
			screen:blit(fontdim*3,fontdim*(i-st+ls),iconitemnoedit)
		else
			if repair==0 then
				if lines[i]~=nil then
					if lines[i].flag=='1' then
						screen:blit(fontdim*3,fontdim*(i-st+ls),iconitemrepair0)
					else
						screen:blit(fontdim*3,fontdim*(i-st+ls),iconitemignore0)
					end
				end
			else
				if lines[i]~=nil then
					if lines[i].flag=='1' then
						screen:blit(fontdim*3,fontdim*(i-st+ls),iconitemrepair)
					else
						screen:blit(fontdim*3,fontdim*(i-st+ls),iconitemignore)
					end
				end
			end
		end
	end
end

function cprint_list_options(sh,listorder,customorder,repair,fmtlist)
	if     listorder==0 then os:print(fontdim*23,fontdim*25+sh,'CUSTOM',yellow)
	elseif listorder==1 then screen:blit(fontdim*23,fontdim*25+sh,textascending)
	elseif listorder==2 then screen:blit(fontdim*23,fontdim*25+sh,textdescending) end

	if     repair==0 then os:print(fontdim*39,fontdim*28+sh,'----',yellow)
	elseif repair==1 then screen:blit(fontdim*39,fontdim*28+sh,text__sce)
	elseif repair==2 then screen:blit(fontdim*39,fontdim*28+sh,textirshell)
	elseif repair==3 then os:print(fontdim*39,fontdim*28+sh,'F&F%',yellow) end
	
	if fmtlist then screen:blit(fontdim*23,fontdim*28+sh,textformatted)
	else            screen:blit(fontdim*23,fontdim*28+sh,textoriginal) end
end

-- Hoshizora 2006.07.08: Added status bar functionality. cprint() will do most of the GUI work for the Edit screen
function cprint(title,lines,idx,max,listorder,customorder,fmtlist,repair,statusBarMsg)
	local ss=16 -- no. of items to display in the list+1 (changed for the new tab look)
  local st=0
	local sh=-2
	local ls=4

	-- Max isnt set then set it
  if max==1 then max=ss+1 end
	-- Up max if index is greater
  if idx>max then max=idx end
	-- Index got larger than max so set start point
  st=max-ss
	-- Adjust max when index goes low
  if idx<st then
    max=st+ss-1
    st=idx
  end
	-- Reset max when start is reset
  if st==1 then max=ss+1 end

	if statusBarMsg==nil then statusBarMsg='' end
	osClear()
	os:print(fontdim+2,fontdim+2,title,black)

  -- Print the list
	cprint_list(lines,ls,st,ss,idx,fmtlist)

	-- Hoshizora 2006.07.10: Updated screen instructions and display inner box as transparent
  os:print(fontdim*5,fontdim*24+sh,'   Manual Sort: Hold   +  /  On Selection',white)
	os:print(fontdim*5,fontdim*25+sh,'   Sort Option:           List Order',ltblue)
  os:print(fontdim*5,fontdim*26+sh,'Display Option:   FW1.0 List      FW1.5 List',white)
	os:print(fontdim*5,fontdim*27+sh,' Ignore Toggle:   All Titles      Single Title',ltblue)
	os:print(fontdim*5,fontdim*28+sh,'KXploit Option:          List          Name Scheme',white) 
	os:print(fontdim*5,fontdim*29+sh,'   Quit           Screen Capture          Organise',ltblue)
	os:print(fontdim*3,fontdim*32,statusBarMsg,white)
	screen:blit(0,0,organisebg,0,0,organisebg:width(),organisebg:height(),false)
	screen:blit(0,screenheight-iconbarstatus:height()-iconbarhelp:height(),iconbarhelp)
	screen:blit(0,screenheight-iconbarstatus:height(),iconbarstatus)
	osPrintBatteryLife()
	osPrintListMode(title)
	cprint_list_icons(lines,ls,st,ss,repair,title)
	cprint_list_options(sh,listorder,customorder,repair,fmtlist)
	screen:blit(0,0,os)
	screen:blit(fontdim*26,fontdim*24+sh,padcross)
	screen:blit(fontdim*30,fontdim*24+sh,padup)
	screen:blit(fontdim*32,fontdim*24+sh,paddown)
	screen:blit(fontdim*21,fontdim*25+sh,padtriangle)
	screen:blit(fontdim*21,fontdim*26+sh,padleft)
	screen:blit(fontdim*37,fontdim*26+sh,padright)
	screen:blit(fontdim*21,fontdim*27+sh,padsquare)
	screen:blit(fontdim*37,fontdim*27+sh,padcircle)
	screen:blit(fontdim*21,fontdim*28+sh,padl)
	screen:blit(fontdim*37,fontdim*28+sh,padr)
	screen:blit(fontdim*5,fontdim*29+sh,analogleft)
	screen:blit(fontdim*19,fontdim*29+sh,padselect)
	screen:blit(fontdim*43,fontdim*29+sh,padstart)
	screen.waitVblankStart()
  screen.flip()

	return max
end

-- Hoshizora 2006.07.08: Added cprint2 function to decide which message to print in original/current listing
function cprint2(title,list,sel,max,listorder,customorder,move,fmtlist,repair,msgOrig,msgCurr)
	if move then -- Current listing
		max=cprint(title,list,sel,max,listorder,customorder,fmtlist,repair,msgCurr)
	else -- Original listing
		max=cprint(title,list,sel,max,listorder,customorder,fmtlist,repair,msgOrig)
	end
	return max
end

function osPrintProgramInfo()
	-- Hoshizora 2006.07.08: Display program information
	local proginfo=progname .. ' ' .. progver
	os:print((screenwidth-fontdim*string.len(proginfo))/2,fontdim,proginfo,black)
end

function osPrintListMode(mode)
	local shx=5
	local shy=3
	if mode==list1_0title then
		screen:blit(fontdim*57+shx,fontdim*32-shy,iconlistlocked)
	else
		screen:blit(fontdim*57+shx,fontdim*32-shy,iconlistunlocked)
	end
end

-- Hoshizora 2006.07.16: Display battery life indicator
-- Hoshizora 2006.08.24: Improved visual appearance of the battery bar
function osPrintBatteryLife()
	local bbarwidth=11
	local bbarheight=6
	local bbarpercent=System.powerGetBatteryLifePercent()
	local bbareraserwidth=math.floor(bbarwidth/100*(100-bbarpercent))
	local icoshx=7
	local icoshy=-3
	local barshx=5
	local barshy=3
	local bbarsections=3
	local bbarseparatorwidth=1
	local bbarseparatorsh
	
	-- Draw the battery life bar!
	if bbarpercent>=50 then -- The battery life indicator
		os:fillRect(fontdim*56+icoshx+barshx,fontdim+icoshy+barshy,bbarwidth,bbarheight,green)
	elseif bbarpercent>=15 and bbarpercent<50 then
		os:fillRect(fontdim*56+icoshx+barshx,fontdim+icoshy+barshy,bbarwidth,bbarheight,yellow)
	else
		os:fillRect(fontdim*56+icoshx+barshx,fontdim+icoshy+barshy,bbarwidth,bbarheight,red)
	end
	os:fillRect(fontdim*56+icoshx+barshx,fontdim+icoshy+barshy,bbareraserwidth,bbarheight) -- The bar eraser!
	for i=1,bbarsections-1 do -- Draw thin separators along the width of the bar
		bbarseparatorsh=math.floor(bbarwidth/bbarsections*i)
		os:fillRect(fontdim*56+icoshx+barshx+bbarseparatorsh,fontdim+icoshy+barshy,bbarseparatorwidth,bbarheight)
	end	
	screen:blit(fontdim*56+icoshx,fontdim+icoshy,iconbattery)
end

-- Hoshizora 2006.07.11: Changed function name from clear() to osClear()
function osClear()
		-- Hoshizora 2006.07.10: Updated function to accomodate using image as background
		os:clear()
		osPrintProgramInfo()
end

-- Hoshizora 2006.07.10: Confirm screen before executing the touch process or exiting uo_Ograniser
function confirm(title,msg)
	local msgprompt='  Yes     No'

  while true do
		osClear()
		os:print(fontdim+2,fontdim+2,title,black)
		os:print((screenwidth-fontdim*string.len(msg))/2,fontdim*14,msg,black)
		os:print((screenwidth-fontdim*string.len(msgprompt))/2,fontdim*19,msgprompt,white)
    screen:blit(0,0,contextbg,0,0,contextbg:width(),contextbg:height(),false)
		osPrintBatteryLife()
		screen:blit(0,0,os)
		screen:blit((screenwidth-fontdim*string.len(msgprompt))/2,fontdim*19,padcross)
		screen:blit((screenwidth-fontdim*string.len(msgprompt))/2+fontdim*8,fontdim*19,padcircle)
		screen.waitVblankStart()
    screen.flip()
    Pad:Update()
		osClear()
    if Pad.tRd then
			-- Pushed CROSS
			return true
    elseif Pad.tRr then
			-- Pushed CIRCLE
			return false
    end
  end
end

-- Hoshizora 2006.08.08: New confirm screen for option to save list order before exiting uo_Ograniser
function confirm2(title,msg)
	local msgprompt='  Yes     No     Cancel'

  while true do
		osClear()
		os:print(fontdim+2,fontdim+2,title,black)
		os:print((screenwidth-fontdim*string.len(msg))/2,fontdim*14,msg,black)
		os:print((screenwidth-fontdim*string.len(msgprompt))/2,fontdim*19,msgprompt,white)
    screen:blit(0,0,contextbg,0,0,contextbg:width(),contextbg:height(),false)
		osPrintBatteryLife()
		screen:blit(0,0,os)
		screen:blit((screenwidth-fontdim*string.len(msgprompt))/2,fontdim*19,padsquare)
		screen:blit((screenwidth-fontdim*string.len(msgprompt))/2+fontdim*8,fontdim*19,padcross)
		screen:blit((screenwidth-fontdim*string.len(msgprompt))/2+fontdim*15,fontdim*19,padcircle)
		screen.waitVblankStart()
    screen.flip()
    Pad:Update()
		osClear()
		if Pad.tRl then
			-- Pushed SQUARE
			return 'Y'
    elseif Pad.tRd then
			-- Pushed CROSS
			return 'N'
		elseif Pad.tRr then
			-- Pushed CIRCLE
			return 'C'
    end
  end
end

function waitX()
  while true do
    Pad:Update()
    if Pad.Rd then break end
  end
end

function fileExists(file)
  local t,msg=io.open(file,"r")
	if not t then return false end
	t:close()
  return true
end

-- Hoshizora 2006.08.11: Removes an existing file and returns its errorlevel
function fileRemove(file)
	System.removeFile(file)
	return not fileExists(file)
end

-- Hoshizora 2006.07.15: Check if directory exists
function dirExists(dir,name)
	local files=System.listDirectory(dir)
	local name1=string.upper(string.gsub(name,'/$','')) -- Remove trailing forwardslash (if exists)
	local result=0

	if files==nil then result=-1 -- An error has occurred
	else
		for index,file in ipairs(files) do
			if file.directory and string.upper(file.name)==name1 then
				result=1
				break -- Dir exists, let's return the result
			end
		end
	end
	return result
end

-- Hoshizora 2006.08.11: Creates a new directory and returns its errorlevel
function dirCreate(dir,name)
	System.createDirectory(dir..name)
	return dirExists(dir,name)
end

-- Hoshizora 2006.08.11: Removes an existing directory and returns its errorlevel
function dirRemove(dir,name)
	local result
	System.removeDirectory(dir..name)
	result=dirExists(dir,name)
	if     result==0 then return 1
	elseif result==1 then return 0
	else   return result end
end

-- Hoshizora 2006.08.11: Renames an existing directory and returns its errorlevel
function dirRename(dir,name0,name1)
	System.rename(dir..name0,dir..name1) -- Requires Lua Player .20 and above to work
	return dirExists(dir,name1)
end

function swap(table,i,j)
  local tmp=table[i]
  table[i]=table[j]
  table[j]=tmp
end

-- Hoshizora 2006.07.11: Added string_format function to preformat the string for the string.sort function
-- Hoshizora 2006.07.15: type=0-No case conversion, loose sc.disp; type=1-Case conversion, loose sc.cf; type=2-Case conversion, strict sc.cf-w/sce (for folder naming schemes 1-2)
-- Hoshizora 2006.07.19: type=3-No case conversion, loose prg.disp; type=4-Case conversion, loose prg.cf (for folder naming schemes 3-8)
-- Hoshizora 2006.07.21: type=5-No case conversion, compress prg.disp; type=6-Case conversion, compress prg.cf (for folder naming scheme 7, compress program folders)
--                       type 7-No case conversion, strip white.disp; type 8-Case conversion, strip white.cf
-- Hoshizora 2006.08.19: Fix rare instances of folder names with '%' appended to both ends
function string_format(str,type)
	local s=''
	local str1=''
	local shortcutPattern={'[ _]+[1_]$','~1%','[ _]*[1_]?~1%%$','%','^%%?_+[sS][cC][eE]_*'}
	--    shortcutPattern={'1.........','2..','3..............','4','5...................'}

	if type==1 or type==2 or type==4 or type==6 or type==8 then -- Convert string to all caps
		s=string.upper(str)
	else s=str end -- No case conversion on the string

	slen=string.len(s)
	if string.startsWith(s,shortcutPattern[4]) and string.endsWith(s,shortcutPattern[4]) then -- Fix folder names with '%' appended to both ends
		if string.match(s,shortcutPattern[5])~=nil then -- Repair __SCE folder names with '%' appended to the end
			return string_format(string.sub(s,1,slen-1),type)
		else -- Repair non-__SCE folder names with '%' appended to the start
			return string_format(string.sub(s,2,slen),type)
		end
	elseif string.endsWith(s,shortcutPattern[2]) then
		return string_format2(string.gsub(s,shortcutPattern[3],''))
	elseif string.endsWith(s,shortcutPattern[4]) then
		return string.sub(s,1,slen-1)
	elseif type==2 and string.startsWith(s,shortcutPattern[4]) then
		return string.sub(s,2,slen)
	elseif (type==3 or type==4) and folder_scheme_match(s,shortcutPattern[1]) then
		return string_format2(string.gsub(s,shortcutPattern[1],''))
	elseif (type==5 or type==6) then
		str1=string_format(string_format(s,3),7)
		if string.len(str1)>=minShortcutDirSchemeLen-4 then
			return string.sub(str1,1,minShortcutDirSchemeLen-4)
		else return str1 end
	elseif (type==7 or type==8) then
		return string.gsub(s,'%s','')
	else
		return string_format2(string.gsub(s,shortcutPattern[5],''))
	end
end

-- Hoshizora 2006.08.02 - Handle special folders named '_'/'_%'
function string_format2(s)
	if string.len(s)==0 then return '_' end
	return s
end

function folder_scheme_match(s,pattern)
	if string.len(s)<minProgramDirSchemeLen then return false end
	if string.match(s,pattern) then return true end
	return false	
end

function tableSortAsc(list)
	table.sort(list,function(a,b)
		return (string_format(a.name,1)<string_format(b.name,1))
	end)
end

function tableSortDesc(list)
	table.sort(list,function(a,b)
		return (string_format(a.name,1)>string_format(b.name,1))
	end)
end

function toggleItemRepair(list,i)
	local msg
	if list[i]==nil then return '' end
	if list[i].flag=='0' then
		list[i].flag='1'
		msg=msgItemRepairToggle
	else
		list[i].flag='0'
		msg=msgItemIgnoreToggle
	end
	return msg
end

function toggleAllItemRepair(list,repairall)
	local msg,f
	if repairall then
		repairall=false
		msg=msgAllIgnoreToggle
		f='0'
	else
		repairall=true
		msg=msgAllRepairToggle
		f='1'
	end
	for i=1,table.getn(list) do
		list[i].flag=f
	end
	return repairall,msg
end

function msgOptionItemRepair(list,i)
	if list[i]==nil then return '' end
	if list[i].flag=='1' then return msgItemRepairOption end
  return msgItemIgnoreOption
end

function choose(title,list1_5,clist1_5,list1_0)
	local sel=1
	local tmp=''
	local show=list1_5
	local max=1
	local move=true
	local fmtlist=true
	local repair=0
	local repairall=true
	local customorder=(table.getn(clist1_5)~=0)
	local listorder=0
	local msg,ans

	if not customorder then listorder=1 end
	osClear()
	max=cprint(title,show,sel,max,listorder,customorder,fmtlist,repair,table.getn(list1_5)..msg1_5HomebrewsInTotal)

  while true do
	  Pad:Update()
		if Pad.tLd or Pad.Ay>analogDeadZone then
			-- Pushed DOWN (D-pad) or Pushed DOWN (Analog Stick)
			if sel<table.getn(show) then
				sel=sel+1
				msg=msgOptionItemRepair(show,sel)
				if Pad.Rd and move then
					-- Pushed CROSS
					swap(show,sel,sel-1)
					listorder=0 -- Change the sort order display to CUSTOM
					msg=msgManualSort
				end
			else -- We have reached the last item in the list (going down!)...
				sel=1
				msg=msgOptionItemRepair(show,sel)
				if Pad.Rd and move then
					-- Pushed CROSS
					tmp=table.remove(show) -- Remove the last item from list
					table.insert(show,1,tmp) -- So jump back to the first item on the next move!
					listorder=0 -- Change the sort order display to CUSTOM
					msg=msgManualSort
				end
			end
			max=cprint2(title,show,sel,max,listorder,customorder,move,fmtlist,repair,msgEditDisabled,msg)

		elseif Pad.tLu or Pad.Ay<(analogDeadZone*-1) then
			-- Pushed UP (D-pad) or Pushed UP (Analog Stick)
			if sel>1 then
				sel=sel-1
				msg=msgOptionItemRepair(show,sel)
				if Pad.Rd and move then
					-- Pushed CROSS
					swap(show,sel,sel+1)
					listorder=0 -- Change the sort order display to CUSTOM
					msg=msgManualSort
				end
			else -- We have reached the first item in the list (going up!)...
				sel=table.getn(show)
				msg=msgOptionItemRepair(show,sel)
				if Pad.Rd and move then
					-- Pushed CROSS
					tmp=table.remove(show,1) -- Remove the first item from list
					table.insert(show,tmp) -- So jump to the last item on the next move!
					listorder=0 -- Change the sort order display to CUSTOM
					msg=msgManualSort
				end
			end
			max=cprint2(title,show,sel,max,listorder,customorder,move,fmtlist,repair,msgEditDisabled,msg)

		elseif Pad.Ax<(analogDeadZone*-1) then
			-- Pushed LEFT (Analog Stick)
			if Pad.Rd and move then
				-- Pushed CROSS
				debug=false -- (-oo-)
			end
			ans=confirm2(quittitle,msgYNCQuitOgraniser)
			if ans=='Y' or ans=='N' then
				if ans=='Y' then saveCustomList(list1_5) end
				System.Quit() -- Requires Lua Player .17dk_2 / .20 MOD and above to work
			end
			max=cprint2(title,show,sel,max,listorder,customorder,move,fmtlist,repair,table.getn(list1_0)..msg1_0HomebrewsInTotal,table.getn(list1_5)..msg1_5HomebrewsInTotal)

		elseif Pad.Ax>analogDeadZone then
			-- Pushed RIGHT (Analog Stick)
			if Pad.Rd and move then
				-- Pushed CROSS
				debug=true -- (^oo^)
			end

		elseif Pad.tLl then
			-- Pushed LEFT
			title=list1_0title
			show=list1_0
			move=false
			if sel>table.getn(show) then sel=1 end
			max=cprint(title,show,sel,max,listorder,customorder,fmtlist,repair,table.getn(list1_0)..msg1_0HomebrewsInTotal)

		elseif Pad.tLr then
			-- Pushed RIGHT
			title=list1_5title
			show=list1_5
			move=true
			if sel>table.getn(show) then sel=1 end
			max=cprint(title,show,sel,max,listorder,customorder,fmtlist,repair,table.getn(list1_5)..msg1_5HomebrewsInTotal)

		elseif Pad.tRu then
			-- Pushed TRIANGLE
			-- Hoshizora 2006.07.21: Button reassigned to perform sorting functions
			if move then -- Toggle mode
				listorder=math.fmod(listorder+1,3)
				if not customorder and listorder==0 then listorder=1 end
				if listorder==0 then
					-- Hoshizora 2006.08.05: Added RESTORE function, CUSTOM list order
					getCustomList(list1_5,clist1_5)
					msg=msgRestoreCustomList
				elseif listorder==1 then
					-- Hoshizora 2006.07.07: Added SORT function, ASCENDING list order
					tableSortAsc(list1_5)
					msg=msgAutoSort..'ascending order'
				elseif listorder==2 then
					-- Hoshizora 2006.07.07: Added SORT function, DESCENDING list order
					tableSortDesc(list1_5)
					msg=msgAutoSort..'descending order'
				end
			end
			max=cprint2(title,show,sel,max,listorder,customorder,move,fmtlist,repair,msgEditDisabled,msg)

		elseif Pad.tRl then
			-- Pushed SQUARE
			-- Hoshizora 2006.07.21: Button reassigned to perform all repair/ignore titles option
			if move then -- Toggle mode
				repairall,msg=toggleAllItemRepair(show,repairall)
			end
			max=cprint2(title,show,sel,max,listorder,customorder,move,fmtlist,repair,msgEditDisabled,msg)
		
		elseif Pad.tRr then
			-- Pushed CIRCLE
			if move then
				-- Hoshizora 2006.07.24: Button reassigned to 'Repair this item/Ignore this item' toggle functionality
				msg=toggleItemRepair(show,sel)
			end
			max=cprint2(title,show,sel,max,listorder,customorder,move,fmtlist,repair,msgEditDisabled,msg)

		elseif Pad.tRd then
			-- Pushed CROSS
			max=cprint2(title,show,sel,max,listorder,customorder,move,fmtlist,repair,msgEditDisabled,msgManualSort)

		elseif Pad.tL1 then
			-- Pushed L
			if move then -- Toggle mode
				if fmtlist then
					msg=msgDispShowOption
					fmtlist=false
				else
					msg=msgDispHideOption
					fmtlist=true
				end
			end
			max=cprint2(title,show,sel,max,listorder,customorder,move,fmtlist,repair,msgEditDisabled,msg)

		elseif Pad.tR1 then
			-- Pushed R
			if move then -- Toggle mode
				repair=math.fmod(repair+1,4)
				if     repair==0 then msg=msgIconNoChangeOption
				elseif repair==1 then msg=msgIconRepairSCEOption
				elseif repair==2 then msg=msgIconRepairIRSOption
				elseif repair==3 then msg=msgIconRestoreOption end
			end
			max=cprint2(title,show,sel,max,listorder,customorder,move,fmtlist,repair,msgEditDisabled,msg)

		elseif Pad.tSl then
			-- Pushed Select
			-- Hoshizora 2006.07.08: Modified screen capture file save location
			-- Hoshizora 2006.07.27: Added support for multiple screen captures
			msg=screen_save()
			max=cprint(title,show,sel,max,listorder,customorder,fmtlist,repair,msg)

		elseif Pad.tSt then
			-- Pushed Start
			-- Hoshizora 2006.07.08: Check battery life before commiting changes
			if System.powerIsLowBattery() and not System.powerIsPowerOnline() then
				max=cprint(title,show,sel,max,listorder,customorder,fmtlist,repair,msgIsLowBattery)
			elseif title==list1_0title then
				max=cprint(title,show,sel,max,listorder,customorder,fmtlist,repair,msgEditDisabled)
			else
				ans=confirm(organisetitle,msgYNCommitChanges)
				if ans then return list1_5,repair end
				max=cprint(title,show,sel,max,listorder,customorder,fmtlist,repair,table.getn(list1_5)..msg1_5HomebrewsInTotal)
			end
		end
		osClear()
	end
end