local host;
local port;
local password;
local tid = -1;

------------------------------------------------------------------------
-- Events
------------------------------------------------------------------------

events.focus = function ()
	host = settings.host;
	port = settings.port;
	password = settings.password;
	
	if (test()) then
		update_status();
		update_library();
	end
end

events.blur = function ()
	last_title = "";
	libs.timer.cancel(tid);
end

function test()
	local resp = send();	
	if (resp == nil or resp.status ~= 200) then
		libs.server.update({
			type = "dialog",
			title = "VLC Connection",
			text = "A connection to VLC could not be established." ..
				"We recommend using the latest version of VLC.\n\n" ..
				"1. Make sure VLC is running on your computer.\n\n" ..
				"2. Enable [Web] interface in VLC settings > Show all settings > Interface > Main interfaces.\n\n" ..
				"3. VLC 2.1+ you MUST specify a password in Main interfaces > Lua > Lua HTTP > Password. Unified Remote is configured to use the password 'vlcremote'.\n\n" ..
				"4. You can also specify a different IP address, port, or password in the remote settings.\n\n" ..
				"You may have to restart VLC after enabling the web interface for the changes to take effect.",
			children = {{ type = "button", text = "OK" }}
		});
		return false;
	else
		return true;
	end
end

------------------------------------------------------------------------
-- Web Request
------------------------------------------------------------------------

function request(url)
	local auth = libs.data.tobase64(":" .. password);
	local req = {
		method = "get",
		url = url,
		headers = { Authorization = "Basic " .. auth }
	}
	local ok, resp = pcall(libs.http.request,req);
	if (ok and resp.status == 200) then
		return resp;
	else
		libs.server.update({ id = "title", text = "[Not Connected]" });
		return nil;
	end
end

function send(cmd, val, id)
	local url = "http://" .. host .. ":" .. port .. "/requests/status.xml";
	if (cmd ~= nil) then
		url = url .. "?command=" .. cmd;
	end
	if (val ~= nil) then
		url = url .. "&val=" .. val;
	end
	if (id ~= nil) then
		url = url .. "&id=" .. id;
	end
	return request(url);
end

function art()
	local url = "http://" .. host .. ":" .. port .. "/art";
	return request(url);
end

------------------------------------------------------------------------
-- Status
------------------------------------------------------------------------

local pos = 0;
local length = 0;
local seeking = false;
local seeking_pos = 0;
local last_title = "";

function update_status()
	local resp = send();
	if (resp == nil) then 
		tid = libs.timer.timeout(update_status, 500);
		return;
	end
	
	local root = libs.data.fromxml(resp.content);
	local title = "";
	local file = "";
	local playing = false;
	
	for k,v in pairs(root.children) do
		if (v.name == "state") then playing = v.text == "playing"; end
		if (v.name == "time") then pos = tonumber(v.text); end
		if (v.name == "length") then length = tonumber(v.text); end
		if (v.name == "volume") then vol = tonumber(v.text); end
		if (v.name == "information") then
			for k2,v2 in pairs(v.children) do
				if (v2.attributes.name == "meta") then
					for k3,v3 in pairs(v2.children) do
						local name = v3.attributes.name;
						if (name == "title") then title = v3.text; end
						if (name == "filename") then file = v3.text; end
					end
				end
			end
		end
	end	
	
	local icon = "play";
	if (playing) then
		icon = "pause";
	end
	
	local image;
	if (last_title ~= title) then
		resp = art();
		if (resp ~= nil) then
			image = resp.content;
		else
			image = "";
		end
		last_title = title;
	end
	
	if (title == "") then
		if (file == "") then
			title = "[Not Playing]";
		else
			title = file;
		end
	end
	
	if (seeking) then
		pos = seeking_pos;
	end
	
	libs.server.update(
		{ id = "title", text = title },
		{ id = "info", text = info },
		{ id = "pos", progress = pos, progressmax = length, text = libs.data.sec2span(pos) .. " / " .. libs.data.sec2span(length) },
		{ id = "vol", progress = vol, progressmax = 320},
		{ id = "art", image = image },
		{ id = "play", icon = icon }
	);
	
	tid = libs.timer.timeout(update_status, 500);
end

------------------------------------------------------------------------
-- Library
------------------------------------------------------------------------

local library_root = {};
local library = {};
local selection = {};

function update_items(items)
	local list = {};
	library = {};
	for k,v in pairs(items) do
		if (v.name == "item") then
			local id = v.attributes.id;
			local name = v.attributes.name;	
			local duration = v.attributes.duration;
			table.insert(list, { type = "item", text = name });
			table.insert(library, { id = id, name = name, duration = duration });
		end
	end
	libs.server.update({ id = "list", children = list });
end

function parse_items(items, level)
	if (#selection < level) then
		update_items(items);
	else
		for k,v in pairs(items) do
			local id = v.attributes.id;
			local name = v.attributes.name;
			if (selection[level] == id) then
				parse_items(v.children, level+1);
				return;
			end
		end
		update_items(items);
	end
end

actions.library_select = function (i)
	local item = library[i+1];
	if (item.duration == nil) then
		-- Folders don't have a duration
		table.insert(selection, library[i+1].id);
		parse_items(library_root.children, 1);
	else
		libs.device.toast("Playing " .. item.name .. "...");
		play_item(item.id);
	end
end

function play_item (id)
	send("pl_play", nil, libs.utf8.sub(id, 5));
end

actions.library_back = function ()
	if (#selection > 0) then
		table.remove(selection);
		parse_items(library_root.children, 1);
	else
		libs.device.toast("Cannot go back any more.");
	end
end

actions.library_refresh = function ()
	libs.device.toast("Refreshing...");
	update_library();
end

function update_library()
	-- Grab new playlist data from vlc
	libs.server.update({ id = "list", children = { { type = "item", text = "Loading..." } } });
	local url = "http://" .. host .. ":" .. port .. "/requests/playlist_jstree.xml";
	local resp = request(url);
	if (resp == nil) then return end
	
	-- Save it and refresh the view
	library_root = libs.data.fromxml(resp.content);
	parse_items(library_root.children, 1);
end

------------------------------------------------------------------------
-- Seeking
------------------------------------------------------------------------

function seek(pos)
	seeking = true;
	
	-- Calculate the seek percentage from the time position
	local v = 0;
	if (length > 0) then
		v = math.floor(math.min(100, pos / length * 100));
	end
	send("seek", v .. "%25");
	
	-- Add delay so that the slider doesn't "jump" due to an incoming status update
	libs.timer.timeout(function ()
		seeking = false;
	end, 1000);
end

actions.position_change = function (pos)
	-- Trigger seeking mode so that the slider text updates
	seeking = true;
	seeking_pos = pos;
end
--@help Change position
--@param pos:number Set Position
actions.position_stop = function (pos)
	seek(pos);
end

--@help Seek backwards
actions.jump_back = function ()
	-- Seeking precision is only 1% so:
	-- If 1% is greater than 10 sec, then jump 1%
	-- Otherwise just jump 10 sec
	local pc = math.floor(0.01 * length);
	if (pc > 10) then
		seeking_pos = pos - pc;
	else
		seeking_pos = pos - 10;
	end
	seek(seeking_pos);
end

--@help Seek forwards
actions.jump_forward = function ()
	-- Seeking precision is only 1% so:
	-- If 1% is greater than 10 sec, then jump 1%
	-- Otherwise just jump 10 sec
	local pc = math.floor(0.01 * length);
	if (pc > 10) then
		seeking_pos = pos + pc;
	else
		seeking_pos = pos + 10;
	end
	seek(seeking_pos);
end

------------------------------------------------------------------------
-- General
------------------------------------------------------------------------

--@help Launch VLC application
actions.launch = function()
	if OS_WINDOWS then
		pcall(function ()
			os.start("C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe");
		end);
		pcall(function ()
			os.start("C:\\Program Files\\VideoLAN\\VLC\\vlc.exe");
		end);
	end
end

--@help Toggle play/pause
actions.play_pause = function ()
	send("pl_pause");
end

--@help Start playback
actions.play = function ()
	send("pl_play");
end

--@help Resume playback
actions.resume = function ()
	send("pl_forceresume");
end

--@help Pause playback
actions.pause = function ()
	send("pl_pause");
end

--@help Stop playback
actions.stop = function ()
	send("pl_stop");
end

--@help Play next item
actions.next = function ()
	send("pl_next");
end

--@help Play previous item
actions.previous = function ()
	send("pl_previous");
end

--@help Toggle shuffle
actions.shuffle = function ()
	send("pl_random");
end

--@help Toggle loop
actions.loop = function ()
	send("pl_loop");
end

--@help Toggle repeat
actions.loop_repeat = function ()
	send("pl_repeat");
end

--@help Raise volume
actions.volume_up = function ()
	send("volume", "%2B20");
end

--@help Lower volume
actions.volume_down = function ()
	send("volume", "-20");
end

--@help Mute volume
actions.volume_mute = function ()
	send("volume", "-1000");
end

--@help Change volume
--@param vol:number Set Volume
actions.volume_change = function (vol)
	send("volume", vol);
end

--@help Toggle fullscreen
actions.fullscreen = function ()
	send("fullscreen");
end
