local M = {}

--[[ This comment is for LuaDoc.
---
-- A module for hotexit - keeps unsaved buffers on quit
module('_M.hotexit')]]



-- Base 64 encoding decoding from: https://stackoverflow.com/a/35303321
local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' -- You will need this for encoding/decoding
-- encoding
function enc_base64(data)
	return ((data:gsub('.', function(x)
		local r,b='',x:byte()
		for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
		return r;
	end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
		if (#x < 6) then return '' end
		local c=0
		for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
		return b:sub(c+1,c+1)
	end)..({ '', '==', '=' })[#data%3+1])
end

-- decoding
function dec_base64(data)
	data = string.gsub(data, '[^'..b..'=]', '')
	return (data:gsub('.', function(x)
		if (x == '=') then return '' end
		local r,f='',(b:find(x)-1)
		for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end
		return r;
	end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
		if (#x ~= 8) then return '' end
		local c=0
		for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end
			return string.char(c)
	end))
end

_UNSAVED_CHANGED = false

-- when made changes on a saved buffer
events.connect(events.SAVE_POINT_LEFT, function(str)
	buffer.notsaved = true
	_UNSAVED_CHANGED = true
end)
events.connect(events.CHAR_ADDED, function(str)
	-- so that ui.print does not see it as a savable change
	if buffer.tab_label ~= '[Message Buffer]' then
		buffer.notsaved = true
		_UNSAVED_CHANGED = true
	end
end)
events.connect(events.SAVE_POINT_REACHED, function(str)
	buffer.notsaved = false
end)

function save_unsaveddata(force_save)
	if not force_save then force_save = false end
	-- when force_save is true, we won't respect the timeout.
	-- it will run the function right away if it's set to true
	-- regardless of what is set on _UNSAVED_CHANGED.
	if force_save == false and _UNSAVED_CHANGED == false then return '' end

	local buffer_filename = ''
	os.remove(_USERHOME..'/unsaveddata.txt')
	if (#_BUFFERS > 0) then
		file = io.open(_USERHOME..'/unsaveddata.txt', "a")
		for j = 1, #_BUFFERS do
			if (_BUFFERS[j].notsaved == true) then
				if not _BUFFERS[j].filename then
					buffer_filename = ''
				else
					buffer_filename = _BUFFERS[j].filename
				end
				file:write('unsavedbuffer||'..buffer_filename..'||'..enc_base64(buffer.get_text(_BUFFERS[j]))..'||'..(_BUFFERS[j].current_pos), "\n")
			end
		end
		io.close(file)
		_UNSAVED_CHANGED = false
	end

	return false -- quit. returning true will not quit
end

events.connect(events.QUIT, function(str)
	textadept.session.save( _USERHOME..'/session' )
	save_unsaveddata(true)
	return false
end, 1) -- adding 1 prevents the default quit event function to run

-- save unsaved data after certain intervals
timeout(10, function()
	save_unsaveddata()
	return true -- true means repeat
end)

function file_exists(file)
	local f = io.open(file, "rb")
	if f then f:close() end
	return f ~= nil
end

function split(pString, pPattern)
	local Table = {n = 0}  -- NOTE: use {n = 0} in Lua-5.0
	local fpat = "(.-)" .. pPattern
	local last_end = 1
	local s, e, cap = pString:find(fpat, 1)
	while s do
		if s ~= 1 or cap ~= "" then
			table.insert(Table,cap)
		end
		last_end = e+1
		s, e, cap = pString:find(fpat, last_end)
	end
	if last_end <= #pString then
		cap = pString:sub(last_end)
		table.insert(Table, cap)
	end
	return Table
end

-- return buffer index after searching for filename
function getbufferbyfilename(filename)
	for j = 1, #_BUFFERS do
		if (_BUFFERS[j].filename == filename) then
			return j
		end
	end
	return nil
end

function restore_unsaveddata()
	local unsaveddata_filename = _USERHOME..'/unsaveddata.txt'
	local line_data
	if not file_exists(unsaveddata_filename) then return {} end
	lines = {}
	for line in io.lines(unsaveddata_filename) do
		line_data = split(line, "||")

		local buffer_index = getbufferbyfilename(line_data[2])
		if buffer_index ~= nil then -- buffer already exists
			_mybuffer = _BUFFERS[buffer_index]
		else
			_mybuffer = buffer.new()
		end

		-- fix: set the text so that it can undo to original text
		-- when buffer has unsaved change
		buffer.set_text(_mybuffer, dec_base64(line_data[3]))

		if (line_data[2] ~= '') then
			_mybuffer.filename = line_data[2]
		end
		_mybuffer.notsaved = true
		buffer.goto_pos(_mybuffer, tonumber(line_data[4])) -- doesn't work properly for all buffers
		buffer.scroll_caret(_mybuffer)
	end
end

events.connect(events.INITIALIZED, function(str)
	restore_unsaveddata()
end)



return M
