-----------------------------------------------------------
-- findCoords()
--
-- returns a Point object containing the current x and y
-- coordinates. Use this over fastFindCoords, which is
-- misnamed and is oddly significantly slower.
----------------------------------------------------------
function findCoords()
  srReadScreen();

  local result = nil;
  local str = "";
  local clockRegion = findClockRegion();
  local lines = findAllText(nil, clockRegion);
  srSetWindowInvertColorRange(minSetWindowInvertColorRange, maxSetWindowInvertColorRange);

  for i=1,#lines do
    if i == 2 then
      str = lines[i][2];
      str = string.gsub(str, " ?1 ?","1");
    end
  end

  local start, stop = string.find(str, "%-?[0-9]+. ?%-?[0-9]+");
  if start ~= nil then
    -- Strip everything except the coords
    str = string.sub(str, start, stop);

    --[[
      Updated to explode on full stop, rather than a comma, due to new HD textures on the clockloc
      which require much more accurate stripping, so the ability to train all characters individually
      is no longer possible without stripping away part of the comma. - T11
    --]]
    local coords = explode(".", str);

    for i=1,#coords do
      x = tonumber(coords[1])
      y = tonumber(coords[2])
    end

    --  One more check to ensure x and y have values. If they're nil, exit with a friendlier message than.
    --  "wrong number of parameters sent to makePoint". -Tizuby
    if x == nil or y == nil then
      error("Could not find coordinates from the clock.\nIs the /clockloc visible or partially covered?");
    end
    result = makePoint(tonumber(x), tonumber(y));
    if not result[0] or not result[1] then
      result = nil;
      lsPrintln("Failed to find coords");
    end
  end
  return result;
end


-----------------------------------------------------------
-- walkTo(dest)
--
-- dest needs to be x,y
-- global: bool globalWalkingStop is checked while walking
-- ie if your script sets a global of globalWalkingStop = 1 then walking is cancelled
-- global: bool globalWalking = true is set while walking. Set back to nil when walking is finished.
----------------------------------------------------------

function walkTo(dest)
  srReadScreen();
  local escape = "\27"
  local coords = findCoords();
    if not coords then
      error("Could not find coordinates from the clock.\nIs the /clockloc visible or partially covered?");
    end
  globalWalking = 1;
  globalWalkingStop = nil;
  while coords[0] ~= dest[0] or coords[1] ~= dest[1] do
    while coords[0] < dest[0] do
      stepTo(makePoint(1, 0), dest); -- Walking East
      srReadScreen();
      coords = findCoords();
      checkBreak();
      if globalWalkingStop then break; end
    end
    while coords[0] > dest[0] do
      stepTo(makePoint(-1, 0), dest); -- Walking West
      srReadScreen();
      coords = findCoords();
      checkBreak();
      if globalWalkingStop then break; end
    end
    while coords[1] < dest[1] do
      stepTo(makePoint(0, -1), dest, "North"); -- Walking North
      srReadScreen();
      coords = findCoords();
      checkBreak();
      if globalWalkingStop then break; end
    end
    while coords[1] > dest[1] do  -- Walking South
      stepTo(makePoint(0, 1), dest, "South");
      srReadScreen();
      coords = findCoords();
      checkBreak();
      if globalWalkingStop then break; end
    end
  if globalWalkingStop then break; end
  end
  srKeyEvent(escape) -- Hit ESC to force avatar to stop running.
  globalWalking = nil;
  globalWalkingStop = nil;
  return coords;
end

local gpsInit = false;
local gpsCenter;
local gpsStep;

-----------------------------------------------------------
-- getRegion()
----------------------------------------------------------
function getRegion()
  srReadScreen();

  local result = nil;
  local str = "";
  local clockRegion = findClockRegion();
  local lines = findAllText(nil, clockRegion);
  srSetWindowInvertColorRange(minSetWindowInvertColorRange, maxSetWindowInvertColorRange);

  for i=1,#lines do
    if i == 2 then
      str = lines[i][2];
    end
  end

  currentRegion = string.match(str, "(%D+):")
  return currentRegion;
end

--------------------------------------------------------------
-- getTime(fmt)
--
-- fmt -  format of resultant text
--
-- if fmt == "date" then Returns Date (Shemu I-30) - ie getTime("date")
-- if fmt == "time" then Returns Time (8:52AM) - ie getTime("time")
-- if fmt == "time2" then Returns Time in special format (8_52AM) - ie getTime("time2")
-- if fmt == "datetime2" then Returns date/time in special format (Akhet_I-1_12_00AM) - ie getTime("datetime2")
-- if fmt == "datetime3" then Returns date/time in special format (1_Akhet_I-1_12_00AM) - ie getTime("datetime3")
-- if fmt == nil, then Returns the date in minutes since epoch (123456) - ie getTime()
-- if fmt ~= nil then Returns the date in minutes since epoch (Year 1, Akhet I-1, 12:00AM) - ie getTime(1)
--
-- Returns nil if the date cannot be obtained
---------------------------------------------------------------
function getTime(fmt)
  local str = nil;
  local datetime = nil;
  local date = nil;
  local time = nil;
  local datetime2 = nil;
  local t = findAllText("Year", findClockRegion());
  srSetWindowInvertColorRange(minSetWindowInvertColorRange, maxSetWindowInvertColorRange);

  if #t == 0 then
    return nil;
  end

  -- Strip spaces - Fixes issue where one's (1) will show as a space before and after it. ie 11 shows as 1 1
  str = string.gsub(t[1][2], " ?1 ?","1");

  --[[
    Updated regex pattern to use full stop, rather than a comma, due to new HD textures on the clockloc
    which require much more accurate stripping, so the ability to train all characters individually
    is no longer possible without stripping away part of the comma. - T11
  --]]
  local year, season, month, day, hour, minute, ampm = string.match(str, "Year ?(%d+). (%a+) (%a+)-(%d+). ?(%d+):(%d+)(%a+)");
  if year and season and month and day and hour and minute then
    datetime = "Year " .. year .. ", " .. season .. " " .. month .. "-" .. day .. ", " .. hour .. ":" .. minute .. ampm
    date = season .. " " .. month .. "-" .. day
    time = hour .. ":" .. minute .. ampm
    time2 = hour .. "_" .. minute .. ampm
    datetime2 = season .. "_" .. month .. "-" .. day .. "_" .. hour .. "_" .. minute .. ampm
    datetime3 = year .. "_" .. season .. "_" .. month .. "-" .. day .. "_" .. hour .. "_" .. minute .. ampm
    -- perform data validation
    local seasonIndex = {};
    seasonIndex["Akhet"] = 1;
    seasonIndex["Peret"] = 2;
    seasonIndex["Shemu"] = 3;
    local monthIndex = {};
    monthIndex["I"] = 1;
    monthIndex["II"] = 2;
    monthIndex["III"] = 3;
    monthIndex["IV"] = 4;
    year = tonumber(year);
    day = tonumber(day);
    hour = tonumber(hour);
    minute = tonumber(minute);
    season = seasonIndex[season];
    month = monthIndex[month];
    if ampm == "AM" then
      ampm = 0;
    elseif ampm == "PM" then
      ampm = 12;
    else
      ampm = nil;
    end
    if year and season and month and day and hour and minute and ampm then
      if fmt == "date" then
        return date;
      elseif fmt == "time" then
        return time;
      elseif fmt == "time2" then
        return time2;
      elseif fmt == "datetime2" then
        return datetime2;
      elseif fmt == "datetime3" then
        return datetime3;
      elseif fmt ~= nil then
        return datetime;
      end
      if hour == 12 then
        hour = 0;
      end
      hour = hour + ampm;
      local seasons = (year - 1)*3 + season;
      local months = (seasons - 1)*4 + month;
      local days = (months - 1)*30 + day;
      local hours = (days - 1)*24 + hour;
      local minutes = hours*60 +  minute;
      return minutes;
    end
  end
  return nil;
end

function initStep()
  if not gpsInit then
    srReadScreen();
    gpsInit = true;
    -- Macro written with 1720 pixel wide window

    xyWindowSize = srGetWindowSize();

    local pixel_scale = xyWindowSize[0] / 1720;
    lsPrintln("pixel_scale " .. pixel_scale);

    gpsStep = makePoint(340*pixel_scale, 380*pixel_scale);

    local walk_x_drift = 14;
    local walk_y_drift = 18;
    if (lsScreenX < 1280) then
      -- Have to click way off center in order to not move at high resolutions
      walk_x_drift = math.floor(walk_x_drift * pixel_scale);
      walk_y_drift = math.floor(walk_y_drift * pixel_scale);
    else
      -- Very little drift at these resolutions, clicking dead center
      -- barely moves
      walk_x_drift = 1;
      walk_y_drift = 1;
    end

    gpsCenter = makePoint(xyWindowSize[0] / 2 - walk_x_drift,
			  xyWindowSize[1] / 2 + walk_y_drift);
  end
end

function stepTo(dir, dest, compass)
  local offsetY = 0;
  local message = ""
  initStep();
  if compass == "North" then
    offsetY = 50;  -- Postive offset need to prevent clicking on ATITD Clock
  elseif compass == "South" then
    offsetY = -65; -- Negative offset needed to prevent clicking on Icon Tray
  end
  safeClick(gpsCenter[0] + dir[0] * gpsStep[0],
	    (gpsCenter[1] + dir[1] * gpsStep[1]) + offsetY);
  sleepWithStatus(250, dest[0] .. ", " .. dest[1] .. "\n\n" .. coord2region(dest[0], dest[1]), nil, 0.7, "Walking to");
end

local ffc_coordsPos = nil;
local ffc_dash = -1;
local ffc_comma = -2;

------------------------------------------------------------------------------------
-- fastFindCoords()
--
-- DEPRECATED. Less reliable and nearly 10x slower than findCoords().
-- Use findCoords() instead. Returns the current coordinates as a Point object.
------------------------------------------------------------------------------------
function fastFindCoords()
	local pos;
	if(not ffc_coordsPos) then
		pos = srFindImage("Year.png",5000);
		if(not pos) then
			pos = findText("Year");
			if(not pos) then
				for i=1,9 do
					pos = findText("ar " .. i .. ", ");
					if(pos) then
						break
					end
				end

				if(not pos) then
					lsPrintln("fastFindCoords() : Can't find the clock");
					return nil;
				end
			end
		end
		local window = getWindowBorders(pos[0], pos[1]);
    srReadScreen(); -- required due to image search functions after a potential text search.
		window.top = window.top + 13;
		window.y = window.y + 13;
		window.height = window.height - 13;
		window.bottom = window.y + window.height;
		pos = srFindImageInRange("colon.png", window.x, window.y, window.width, window.height,5000);
		if(not pos) then
			lsPrintln("fastFindCoords() : Can't find the colon on the second line of the clock");
			return nil;
		end
		window.width = window.width + window.x - pos[0] - 5;
		window.left = pos[0] + 5;
		window.x = pos[0] + 5;
		window.right = window.x + window.width;
		window.top = pos[1];
		window.y = window.top;
		window.height = window.bottom - window.top;
		ffc_coordsPos = window;
	end
	if(not ffc_coordsPos) then
		lsPrintln("fastFindCoords() : Can't find the coordinates");
		return nil;
	end

	local digits = ffc_readDigits(ffc_coordsPos);
	if(digits) then
		return ffc_parseDigits(digits);
	end
	return nil;
end

-----------------------------------------------------------------------------
-- ffc_parseDigits(digits)
--
-- Helper function for fastFindCoords(). Deprecated.
-----------------------------------------------------------------------------
function ffc_parseDigits(digits)
	local x;
	local pos;
	x, pos = ffc_parseOneCoord(digits);
	local y;
	y, pos = ffc_parseOneCoord(digits,pos);
	if((not x) or (not y)) then
		if(not x) then
			lsPrintln("fastFindCoords() : x is nil");
		end
		if(not y) then
			lsPrintln("fastFindCoords() : y is nil");
		end
		return nil;
	end
	return makePoint(x,y);
end

-------------------------------------------------------------------------------
-- ffc_parseOneCoord(digits, pos)
--
-- Helper function for fastFindCoords(). Deprecated.
------------------------------------------------------------------------------
function ffc_parseOneCoord(digits,pos)
	if(pos == nil) then
		pos = 1;
	end
	if(pos > #digits) then
		lsPrintln("ffc_parseOneCoord(): pos > #digits(" .. #digits .. ")");
		return nil, nil;
	end
	local negative = false;
	local val = 0;
	local i;
	for i=pos,#digits do
		if(digits[i][2] == ffc_comma) then
			if(negative) then
				val = val * -1;
			end
			return val, i+1;
		end
		if(digits[i][2] == ffc_dash) then
			negative = true;
		else
			val = val * 10 + digits[i][2];
		end
	end
	if(negative) then
		val = val * -1;
	end
	return val, #digits+1;
end

-----------------------------------------------------------------------------
-- ffc_readDigits(box)
--
-- Helper function for fastFindCoords(). DEPRECATED.
-----------------------------------------------------------------------------
function ffc_readDigits(box)
	local digits = {};
	local i;
	for i=0,9 do
		local x = ffc_coordsPos.x;
		local pos = true;
		while((x < ffc_coordsPos.x + ffc_coordsPos.width - 6) and pos) do
			pos = srFindImageInRange(i .. ".png",x,ffc_coordsPos.y,ffc_coordsPos.width,ffc_coordsPos.height,5000);
			if(pos) then
				digits[#digits+1] = {pos[0],i};
				x = pos[0] + 7;
			end
		end
	end
	if(#digits < 2) then
		lsPrintln("ffc_readDigits() : Unable to read any digits");
		return nil;
	end
	local x = ffc_coordsPos.x;
	local pos = true;
	while(pos) do
		pos = srFindImageInRange("dash.png",x,ffc_coordsPos.y,ffc_coordsPos.width,ffc_coordsPos.height,5000);
		if(pos) then
			digits[#digits+1] = {pos[0],ffc_dash};
			x = x + 5;
		end
	end
	pos = srFindImageInRange("comma.png",ffc_coordsPos.x,ffc_coordsPos.y,ffc_coordsPos.width,ffc_coordsPos.height,5000);
	if(pos) then
		digits[#digits+1] = {pos[0],ffc_comma};
	end
	table.sort(digits, ffc_compareDigits);
	return digits;
end

-----------------------------------------------------------------------------
-- ffc_compareDigits(left,right)
--
-- Helper function for fastFindCoords(). DEPRECATED.
-----------------------------------------------------------------------------
function ffc_compareDigits(left,right)
	if(left[1] < right[1]) then
		return true;
	end
	return false;
end

-----------------------------------------------------------------------------
-- coord2region(x, y)
--
-- Returns a region name - Valid for T9
-----------------------------------------------------------------------------
function coord2region(x,y)
  if not x  or not y then
    x = 9999;
    y = 9999;
  end

  if x >=-3072 and x <= -745 and y >=7445 and y <= 8192 then
    regionName = "Cyrene"
  elseif x>=2795 and x<=3220 and y>=3385 and y<=3785 then
    regionName = "Hinterlands"
  elseif x>=-3072 and x<=-1910 and y>=6375 and y<=7445 then
    regionName = "Hamim"
  elseif x>=-3072 and x<=-1625 and y>=5150 and y<=6375 then
    regionName = "Bahariya Oasis"
  elseif x>=-3072 and x<=-1910 and y>=3955 and y<=5150 then
    regionName = "Ammonium"
  elseif x>=-3072 and x<=-1910 and y>=2985 and y<=3955 then
    regionName = "Dunqul Oasis"
  elseif x>=-3072 and x<=-1345 and y>=965 and y<=2985 then
    regionName = "Dakhla Oasis"
  elseif x>=-3072 and x<=-350 and y>=-725 and y<=965 then
    regionName = "Buhen"
  elseif x>=-3072 and x<=-1285 and y>=-8192 and y<=-6500 then
    regionName = "Meroe Desert"
  elseif x>=-3072 and x<=-900 and y>=-5690 and y<=-2320 then
    regionName = "Western Desert"
  elseif x>=-3072 and x<=130 and y>=-6500 and y<=-5020 then
    regionName = "Napata"
  elseif x>=945 and x<=3152 and y>=-8192 and y<=-7088 then
    regionName = "Nubia"
  elseif x>=-1285 and x<=1065 and y>=-8192 and y<=-5020 then
    regionName = "Blue Nile"
  elseif x>=-1910 and x<=-745 and y>=6375 and y<=7445 then
    regionName = "Wadi Natrun"
  elseif x>=-1625 and x<=450 and y>=5860 and y<=6625 then
    regionName = "Faiyum"
  elseif x>=-745 and x<=155 and y>=6625 and y<=8192 then
    regionName = "Zau"
  elseif x>=155 and x<=1660 and y>=6625 and y<=8192 then
    regionName = "Meshwesh Delta"
  elseif x>=1660 and x<=2328 and y>=6336 and y<=8192 then
    regionName = "Bitter Lakes"
  elseif x>=2328 and x<=3700 and y>=6336 and y<=8192 then
    regionName = "West Sinai"
  elseif x>=3700 and x<=5120 and y>=6176 and y<=8192 then
    regionName = "East Sinai"
  elseif x>=4255 and x<=5120 and y>=3785 and y<=6176 then
    regionName = "Timna"
  elseif x>=2795 and x<=4255 and y>=3785 and y<=6336 then
    regionName = "South Sinai"
  elseif x>=1860 and x<=2795 and y>=4350 and y<=6336 then
    regionName = "Arsinoe"
  elseif x>=1165 and x<=1860 and y>=5240 and y<=6625 then
    regionName = "Suez"
  elseif x>=155 and x<=1860 and y>=4350 and y<=5570 then
    regionName = "Herakleopolis"
  elseif x>=-1345 and x<=190 and y>=2500 and y<=4530 then
    regionName = "Kharga Oasis"
  elseif x>=450 and x<=1165 and y>=5570 and y<=6625 then
    regionName = "Giza"
  elseif x>=-1910 and x<=-1345 and y>=2985 and y<=5150 then
    regionName = "Nabta Playa"
  elseif x>=2795 and x<=4255 and y>=3785 and y<=6336 then
    regionName = "South Sinai"
  elseif x>=190 and x<=2795 and y>=3385 and y<=4350 then
    regionName = "Hermopolis"
  elseif x>=190 and x<=1985 and y>=2750 and y<=3385 then
    regionName = "Abydos"
  elseif x>=1985 and x<=3220 and y>=2100 and y<=3385 then
    regionName = "Naqada"
  elseif x>=3220 and x<=4515 and y>=1856 and y<=3785 then
    regionName = "Gebel"
  elseif x>=3975 and x<=5120 and y>=-1030 and y<=860 then
    regionName = "Pwenet"
  elseif x>=4515 and x<=5120 and y>=860 and y<=3785 then
    regionName = "Arabia"
  elseif x>=1630 and x<=4515 and y>=465 and y<=2100 then
    regionName = "Red Sea"
  elseif x>=-1625 and x<=450 and y>=4530 and y<=5860 then
    regionName = "Lahun"
  elseif x>=190 and x<=1985 and y>=1360 and y<=2750 then
    regionName = "Asyut"
  elseif x>=-350 and x<=1985 and y>=-1415 and y<=-87 then
    regionName = "Swenett"
  elseif x>=500 and x<=2795 and y>=-3135 and y<=-1310 then
    regionName = "Upper Egypt"
  elseif x>=1630 and x<=3975 and y>=-1415 and y<=465 then
    regionName = "Bernike"
  elseif x>=-350 and x<=1630 and y>=-87 and y<=1360 then
    regionName = "Thebes"
  elseif x>=-1345 and x<=190 and y>=965 and y<=2500 then
    regionName = "Akhetaton"
  elseif x>=-3072 and x<=-350 and y>=-2320 and y<=-725 then
    regionName = "Kerma"
  elseif x>=-900 and x<=500 and y>=-3135 and y<=-1310 then
    regionName = "Philae"
  elseif x>=2795 and x<=5120 and y>=-2675 and y<=-1030 then
    regionName = "Damot"
  elseif x>=-900 and x<=2795 and y>=-3615 and y<=-3135 then
    regionName = "Elephantine"
  elseif x>=1065 and x<=3280 and y>=-7088 and y<=-5620 then
    regionName = "White Nile"
  elseif x>=3152 and x<=5120 and y>=-8192 and y<=-5500 then
    regionName = "Axum"
  elseif x>=2795 and x<=5120 and y>=-5620 and y<=-2675 then
    regionName = "Blemmyes"
  elseif x>=-900 and x<=1500 and y>=-5020 and y<=-3615 then
    regionName = "West Kush"
  elseif x>=1065 and x<=2795 and y>=-5620 and y<=-3615 then
    regionName = "East Kush"
  elseif x == 9999 and y == 9999 then
    regionName = "Invalid Coordinates"
  else
    regionName = "Hinterlands"
  end
  return regionName;
end