
local GetTime = QuestHelper_GetTime

QuestHelper_File["collect_location.lua"] = "4.0.1.$svnversion$"
QuestHelper_Loadtime["collect_location.lua"] = GetTime()

-- little endian two's complement
local function signed(c)
  QuestHelper: Assert(not c or c >= -127 and c < 127)
  if not c then c = -128 end
  if c < 0 then c = c + 256 end
  return c
  --return strchar(c)
end

local dec2hex = {[0] = "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"}

local hex2dec = {}

for k, v in pairs(dec2hex) do hex2dec[v] = k end

local function tohex(c)
	return dec2hex[c]
end

local function lgToDec(c, pos)
	if not c or c == "" then return 0 end

	local ret = 0

	pos = pos or 0

	if pos == 0 then c = string.reverse(c) end

	ret = todec(string.sub(c,1,1)) * math.pow(16, pos) + lgToDec(string.sub(c, 2), pos + 1)

	return ret
end

local function lgToHex(c, pos)
	local ret, rem, hex

	pos = pos or 0
	c = c or 0
	local minVal = math.pow(16, pos)
	local maxVal = math.pow(16, pos+1) - 1

	if c > maxVal then
		rem, hex = lgToHex(c, pos + 1)
	else
		rem, hex = c, ""
	end

	local mult = 0

	while rem >= minVal do
		mult = mult + 1
		rem = rem - minVal
	end

	return rem, hex .. tohex(mult)
end

local function todec(c)
	return hex2dec[c]
end

local function float(c)
--  if not c then c = -128 end
--  QuestHelper: Assert( c >= -128, string.format("c is too small. It is %s.", tostring(c)))
--  QuestHelper: Assert( c < 128, string.format("c is too big. It is %s.", tostring(c)))
  local ret = tohex(math.floor(128 * c))
  return ret
end

local function rep_comma(val)
	return string.gsub(tostring(val), ",", ".")
end

local function BolusizeLocation(m, f, x, y)
  -- m and f are positive integers.
  -- x and y are floating-point values, generally between 0 and 1. We'll convert to string and then replace any "," decimal separator (because it'll be easier later to import on an enUS machine).
  local str_x = rep_comma(x)
  local str_y = rep_comma(y)

  -- Next, we are going to calculate the distance this point is from either Azeroth 50,50 or Outland 50,50.
  -- We will only keep the dx and dy values, since we can compute distance from those (dist = sqrt(dx*dx + dy*dy)). We can also compute a bearing from dx and dy, since we are going relative to (50,50)
  --   Said bearing is the inverse tangent of dy/dx, trig people, trig. SOHCAHTOA. I have all three values, so I could use any pair, but dx and dy make the most sense.
  --   Of course, the bearing DOES need adjusting, since WoW sets 0 to be north. Normally, angles increase counter-clockwise, WoW does the same... SO, all we'd have to do is add 90 degrees, or pi/2 radians to the result of the inverse tangent.
  --   This discourse is of no real consequence, beyond explaining the WHY of collecting dx and dy, rather than just the distance.
  local _, dxAz, dyAz = QuestHelper.Astrolabe:ComputeDistance(  0, 0, 0.5, 0.5, m, f, x, y)
  local _, dxOl, dyOl = QuestHelper.Astrolabe:ComputeDistance(466, 0, 0.5, 0.5, m, f, x, y)

  local dx_str, dy_str
  local dist_rel
  if dxAz then
	dx_str = rep_comma(dxAz)
	dy_str = rep_comma(dyAz)
	dist_rel = "A"
  elseif dxOl then
	dx_str = rep_comma(dxOl)
	dy_str = rep_comma(dyOl)
	dist_rel = "A"
  end

  -- Finally, we are going to go back to doing a string for the location bolus, but it will be tab delimited in the form "m\tf\tx\t\y\tA\tdx\tdy" or "m\tf\tx\t\y\tO\tdx\tdy" where A means dx,dy are relative to Azeroth (50,50) (in yards) and O means they are relative to Outland (50,50)
  -- 	Note: if only four values are present, then we couldn't compute a distance... Probably because we are in an instance of some kind.

  local loc = string.format("%d\t%d\t%s\t%s", m, f, str_x, str_y)
  if dxAz or dxOl then
    loc = string.format("%s\t%s\t%s\t%s", loc, dist_rel, dx_str, dy_str)
  end

  return loc;
  --return string.format("%s,%s,%s,%s,%s", signed(delayed and 1 or 0), signed(c), signed(z), float_x, float_y)
  --return signed(delayed and 1 or 0) .. signed(c) .. signed(z) .. float_x .. float_y
end

-- This merely provides another API function
function QH_Collect_Location_Init(_, API)
  API.Callback_LocationBolus = BolusizeLocation  -- Yeah. *Bolusize*. You heard me.
  API.Callback_LocationBolusCurrent = function () return BolusizeLocation(API.Callback_Location_Raw()) end  -- This is just a convenience function, really
end
