DailyAutoShare              = DailyAutoShare or {}
DAS                         = DailyAutoShare

DAS.name                    = "DailyAutoShare"
DAS.version                 = "3.5"
DAS.author                  = "manavortex"
DAS.settings                = {}
DAS.globalSettings          = {}

DAS.shareables   	        = {}
DAS.bingo 			        = {}
DAS.bingoFallback           = {}
DAS.subzones 		        = {}
DAS.activeZoneQuests        = {}

DAS.questFinisher           = {}
DAS.questStarter            = {}
DAS.questIds                = {}
DAS.activeBingoIndices      = {}
DAS.prequests               = {}
DAS.channelTypes 	        = {
  [CHAT_CHANNEL_PARTY]    = true,
  [CHAT_CHANNEL_SAY ]     = false,
  [CHAT_CHANNEL_YELL]     = false,
  [CHAT_CHANNEL_ZONE]     = false,
  [CHAT_CHANNEL_WHISPER]  = true,
}

DAS.locale 			    = GetCVar("language.2")
DAS.autoInviting        = false
DAS.guildInviteText     = nil

DAS_STATUS_COMPLETE 	= 0
DAS_STATUS_OPEN 		= 1
DAS_STATUS_ACTIVE		= 2
DAS_STATUS_TRACKED	    = 3

local activeInCurrentZone   = false
DAS.fullBingoString         = ""
local fullBingoString       = DAS.fullBingoString

UNITTAG_PLAYER              = UNITTAG_PLAYER or "player"

local defaults = {

	debugging		   			= false,
	keepInviteUpOnDegroup 		= false,

	DasControl = {
		x = 0,
		y = 0,
  },
	DasButton = {
		x = 0,
		y = 0,
  },
	inactiveZones			= {
hide				= true,
  },
	[849] = {
		relic = {
			invisible = false,
			active = true,
    },
		hunt = {
invisible = false,
			active = true,
    },
		delve = {
			invisible = false,
			active = true,
    },
		boss = {
			invisible = false,
			active = true,
    },
  },
	[980] = {
		crow = {
			invisible = false,
			active = true,
    },
		craft = {
			invisible = false,
			active = true,
    },
		delve = {
			invisible = false,
			active = true,
    },
		boss = {
			invisible = false,
			active = true,
    },
  },
  [726] = {
		root = {
			invisible = false,
			active = true,
    },
		delve = {
			invisible = false,
			active = true,
    },
		boss = {
			invisible = false,
			active = true,
    },
  },

  questShareString            = "I can give a DailyAutoShare for <<1>>, type <<2>> for an instant invite",
  whisperString               = "whisper + for an instant invite",
	guildInviteText,
	listenInGuilds,
  whisperOnly                 = false,

	autoAcceptInvite 			      = false,
	autoAcceptInviteInterval 	  = 5,

	autoAcceptQuest		          = true,
	autoAcceptShared 			      = true,

	autoDeclineShared 			    = false,

	autoHide 					          = false,
	autoMinimize 				        = false,

	minimised 					        = false,
	locked 						          = false,
	hidden 						          = false,

	autoShare 					        = true,
	autoInvite 					        = false,
	autoLeave 					        = false,

	useGlobalSettings 			    = true,

	fontScale					          = 0.8,
	tooltipRight 				        = false,
	upsideDown 					        = false,
  hideCompleted				        = false,
	startupMinimized			      = true,
	resetAutoShareOnNewGroup    = true,
	lastLookingFor 				      = "",
	guildInviteNumber 			    = 1,
	groupInviteDelay			      = 500,
	questShareDelay				      = 500,
  mapMarkersVisible           = true,

  tracked = {
		[684]  = true,
		[823]  = true,
		[849]  = true,	    -- Vvardenfell
		[181]  = false,
		[1011] = true,     -- Summerset
		[726] = true,      -- Murkmire
  },
}

local function pointerUpSubzones()

  local settings = DAS.GetSettings()
  -- Summerset
  settings[1012]                      = settings[1011]
  settings[1013]                      = settings[1011]
  settings[1014]                      = settings[1011]
  settings[1015]                      = settings[1011]
  settings[1016]                      = settings[1011]
  settings[1017]                      = settings[1011]
  settings[1018]                      = settings[1011]
  settings[1019]                      = settings[1011]
  settings.tracked[1012]              = settings.tracked[1011]
  settings.tracked[1013]              = settings.tracked[1011]
  settings.tracked[1014]              = settings.tracked[1011]
  settings.tracked[1015]              = settings.tracked[1011]
  settings.tracked[1016]              = settings.tracked[1011]
  settings.tracked[1017]              = settings.tracked[1011]
  settings.tracked[1018]              = settings.tracked[1011]
  settings.tracked[1019]              = settings.tracked[1011]

  -- Gold Coast
  settings[825]                       = settings[823]
  settings[826]                       = settings[823]
  settings.tracked[825]               = settings.tracked[823]
  settings.tracked[826]               = settings.tracked[823]

  -- Capitals
  settings[19]                       = settings[57]
  settings[383]                      = settings[57]
  settings.tracked[19]               = settings.tracked[57]
  settings.tracked[383]              = settings.tracked[57]

  -- Clockwork City
  settings[981]                       = settings[980]
  settings[981]                       = settings[980]
  settings[982]                       = settings[980]
  settings.tracked[982]               = settings.tracked[980]
  settings.tracked[983]               = settings.tracked[980]
  settings.tracked[983]               = settings.tracked[980]

  -- Morrowind
  settings[921]                       = settings[849]
  settings[922]                       = settings[849]
  settings[923]                       = settings[849]
  settings[924]                       = settings[849]
  settings[925]                       = settings[849]
  settings[961]                       = settings[849]
  settings.tracked[921]               = settings.tracked[849]
  settings.tracked[922]               = settings.tracked[849]
  settings.tracked[923]               = settings.tracked[849]
  settings.tracked[924]               = settings.tracked[849]
  settings.tracked[925]               = settings.tracked[849]
  settings.tracked[961]               = settings.tracked[849]

  -- Wrothgar
  settings[689]                       = settings[684]
  settings[690]                       = settings[684]
  settings[691]                       = settings[684]
  settings[692]                       = settings[684]
  settings[693]                       = settings[684]
  settings[694]                       = settings[684]
  settings.tracked[689]               = settings.tracked[684]
  settings.tracked[690]               = settings.tracked[684]
  settings.tracked[691]               = settings.tracked[684]
  settings.tracked[692]               = settings.tracked[684]
  settings.tracked[693]               = settings.tracked[684]
  settings.tracked[694]               = settings.tracked[684]
end

local characterName     = zo_strformat(GetUnitName(UNITTAG_PLAYER))

local em = EVENT_MANAGER

local function debugOut(p1, p2, p3, p4, p5, p6, p7, p8)
  if not DAS.GetDebugMode() then return end
  if (not p2) then d(p1); return; end
  if p8 then
    d(zo_strformat("<<1>> <<2>> <<3>> <<4>> <<5>> <<6>> <<7>> <<8>>", p1, p2, p3, p4, p5, p6, p7, p8))
    elseif p7 then
    d(zo_strformat("<<1>> <<2>> <<3>> <<4>> <<5>> <<6>> <<7>>", p1, p2, p3, p4, p5, p6, p7))
    elseif p6 then
    d(zo_strformat("<<1>> <<2>> <<3>> <<4>> <<5>> <<6>>", p1, p2, p3, p4, p5, p6))
    elseif p5 then
    d(zo_strformat("<<1>> <<2>> <<3>> <<4>> <<5>>", p1, p2, p3, p4, p5))
    elseif p4 then
    d(zo_strformat("<<1>> <<2>> <<3>> <<4>>", p1, p2, p3, p4))
    elseif p3 then
    d(zo_strformat("<<1>> <<2>> <<3>>", p1, p2, p3))
    else
    d(zo_strformat("<<1>> <<2>>", p1, p2))
  end
end
DAS.DebugOut = debugOut
local p = debugOut

function DAS.Report(text)
	if not DAS.GetShutUp() then d(text) end
end

--==============================
--======= Event hooks  =========
--==============================

local function OnGroupTypeChanged(eventCode, unitTag)
	if IsUnitGrouped(UNITTAG_PLAYER) then
    if not DAS.GetAutoShare() and DAS.GetResetAutoShareOnNewGroup() then
      DAS.SetAutoShare(true)
    end
    return
  end

  if DAS.GetStopInviteOnDegroup() then DAS.SetAutoInvite(false) end

end

local function forceRefreshControl()
  DAS.RefreshControl(true)
end

local function OnQuestAdded(eventCode, journalIndex, questName, objectiveName)

	local zoneId = DAS.GetZoneId()
	if not DAS.GetActiveIn(zoneId) 			then return end
	if not GetIsQuestSharable(journalIndex) then return end

  local shareables = DAS.shareables[zoneId] or {}
  local bingoIndex = DAS.GetBingoIndexFromQuestName(questName) or 0
  DAS.activeBingoIndices[bingoIndex] = true

  if nil ~= shareables[questName] then
		DAS.LogQuest(questName, false)
		zo_callLater(forceRefreshControl, 700)
  end
end

local questSharePending = false
local questLoopInterval = 500
local function stopAcceptQuestLoop(eventCode, journalIndex)
  if not questSharePending then
    ShareQuest(journalIndex)
    return
  end
  questSharePending = nil ~= GetOfferedQuestShareIds()
  questLoopInterval = 500
end

local function acceptQuestLoop()
  if not questSharePending then return end
  for id, _ in pairs(GetOfferedQuestShareIds()) do
    AcceptSharedQuest(id)
  end
  questLoopInterval = questLoopInterval + questLoopInterval*0.5
  zo_callLater(acceptQuestLoop, questLoopInterval)
end

local function OnQuestShared(eventCode, questId)

  if not DAS.settings.autoAcceptShared then return end
  local questName =  GetOfferedQuestShareInfo(questId)
  p(zo_strformat("<<1>> \t <<2>>", questId, questName))
	local zoneQuestIds = DAS.questIds[DAS.GetZoneId()] or {}
	if not (zoneQuestIds[questName] or DAS_QUEST_IDS[questId]) and DAS.GetActiveIn(zoneId) then return end

	if zoneQuestIds[questId] then
    AcceptSharedQuest(questId)
    em:RegisterForEvent(DAS.name, EVENT_QUEST_ADDED, stopAcceptQuestLoop)
    zo_callLater(forceRefreshControl, 500)
  end
end

local function OnChatMessage(eventCode, channelType, fromName, messageText, _, fromDisplayName)
  return DAS.OnChatMessage(eventCode, channelType, fromName, messageText, _, fromDisplayName)
end

local function OnPlayerActivated(eventCode)
	local active 		= DAS.GetActiveIn()
	DAS.SetHidden(not active)
  DAS.SetAutoInvite(DAS.GetAutoInvite()) -- disables if we aren't group lead
  DAS.SetChatListenerStatus(DAS.autoInviting)
  DAS.guildInviteText = DAS.GetGuildInviteText()
  DAS.cacheChatterData()
end

local function OnUnitCreated(eventCode, unitTag)
  local unitZone = GetZoneId(GetUnitZoneIndex(unitTag))
  if not DAS.GetActiveIn(unitZone) then return end
  if GetUnitDisplayName(unitTag) == cachedDisplayName then return end
  DAS.TryShareActiveDaily(unitZone)
end

local function OnQuestToolUpdate()
	forceRefreshControl()
end

local function OnQuestRemoved(eventCode, isCompleted, journalIndex, questName, zoneIndex, poiIndex, questId)

  local zoneId = DAS.GetZoneId()
  local zoneIds = DAS.questIds[zoneId] or {}
  -- is it a daily quest, and are we logging?
  if not ((zoneIds[questName] or DAS_QUEST_IDS[questId]) and DAS.GetActiveIn(zoneId)) then return end

	DAS.LogQuest(questName, isCompleted)

  -- set auto invite off until the questlog has refreshed
	local autoInvite = DAS.GetAutoInvite()
  DAS.SetAutoInvite(false)

  local bingoIndex = DAS.GetBingoIndexFromQuestName(questName) or 0
  DAS.activeBingoIndices[bingoIndex] = false
  if DAS.trackedIndex == journalIndex then
    DAS.trackedIndex = 99
  end

  zo_callLater(function()
  DAS.SetAutoInvite(autoInvite)
  forceRefreshControl()
  DAS.RefreshLabelsWithDelay()
  end, 5000)
  end

  local function deleteYesterdaysLog()
	-- kill yesterday's log, we don't need it
	local currentDate = tonumber(GetDate())
	if (nil ~= DAS.globalSettings and nil ~= DAS.globalSettings.lastLogDate) and (DAS.globalSettings.lastLogDate < currentDate) then
	if nil == DAS.Log then DAS.Log = {} end
  DAS.Log[DAS.globalSettings.lastLogDate] = nil
  DAS.globalSettings.lastLogDate = currentDate
	end
  end

  local alreadyRefreshing = false
  local function questRefresh()
  alreadyRefreshing = false
  DAS.RefreshControl(true)
  end
  local function queueQuestRefresh()
  if alreadyRefreshing then return end
  alreadyRefreshing = true
  zo_callLater(questRefresh, 600)
  end

  local function hookQuestTracker()
  if FOCUSED_QUEST_TRACKER and FOCUSED_QUEST_TRACKER.ForceAssist then
  ZO_PreHook(FOCUSED_QUEST_TRACKER, "ForceAssist", queueQuestRefresh)
  end

  end

  --==============================
  --= DailyAutoShare_Initialize ==
  --==============================

  local function RegisterEventHooks()

	DailyAutoShare.Fragment 	= ZO_HUDFadeSceneFragment:New(DasControl)

	SCENE_MANAGER:GetScene("hud"  ):AddFragment(DailyAutoShare.Fragment)
	SCENE_MANAGER:GetScene("hudui"):AddFragment(DailyAutoShare.Fragment)
	hookQuestTracker()

	em:RegisterForEvent(DAS.name, EVENT_PLAYER_ACTIVATED, 		OnPlayerActivated)

	em:RegisterForEvent(DAS.name, EVENT_QUEST_ADDED, 			OnQuestToolUpdate)
	em:RegisterForEvent(DAS.name, EVENT_QUEST_REMOVED, 			OnQuestRemoved)
	em:RegisterForEvent(DAS.name, EVENT_TRACKING_UPDATE, 		OnQuestToolUpdate)

	em:RegisterForEvent(DAS.name, EVENT_QUEST_ADDED, 			OnQuestAdded)
	em:RegisterForEvent(DAS.name, EVENT_QUEST_REMOVED, 			OnQuestRemoved)
	em:RegisterForEvent(DAS.name, EVENT_QUEST_SHARED, 			OnQuestShared)

	em:RegisterForEvent(DAS.name, EVENT_GROUP_TYPE_CHANGED,     OnGroupTypeChanged)
	em:RegisterForEvent(DAS.name, EVENT_UNIT_CREATED,	 		OnUnitCreated)
	em:RegisterForEvent(DAS.name, EVENT_UNIT_DESTROYED, 		OnGroupTypeChanged)

	em:RegisterForEvent(DAS.name, EVENT_CHAT_MESSAGE_CHANNEL,   OnChatMessage)
	-- DasControl:OnMoveStop
	-- DailyAutoShare.SaveControlLocation(self)
  end


  local function resetQuests()
  local currentDate = tonumber(GetDate())
  DAS.todaysLog = {}
  DAS.globalSettings.completionLog[currentDate] = DAS.todaysLog
  forceRefreshControl()
  end

  local typeTable = "table"
  local function isEmpty(tbl)
  if not tbl then return true end
  local ret = true
  for key, value in pairs(tbl) do
  if type(value) == typeTable then
  ret = ret and ({} == value or isEmpty(value))
  else
  ret = false
  end
  end
  return ret
  end


  -- has to be a local var, lua error if not
  -- Keep outside of function namespace so we can overwrite it for debugging
  local afterEight = tonumber(GetTimeString():sub(0, 2)) >= 08

  local function handleLog(forceNoAfterEight)

  local todaysLog = DAS.GetSettingsArray()
  if {} ~= todaysLog then
  todaysLog = ZO_DeepTableCopy(todaysLog, {})
  end

  local allLogs = DAS.globalSettings.completionLog
  local currentDate = tonumber(GetDate())
  allLogs[currentDate] = allLogs[currentDate] or {}

  local logSize, lastDate = NonContiguousCount(DAS.globalSettings.completionLog)

  local counter = 0
  for dateNumber, dateLog in pairs(DAS.globalSettings.completionLog) do
  counter = counter + 1
  if nil ~= dateNumber and dateNumber < currentDate then
  lastDate = dateNumber
  end
  if counter < logSize-2 then
  DAS.globalSettings.completionLog[dateNumber] = nil
  end
  end

  local afterEight = not forceNoAfterEight and tonumber(GetTimeString():sub(0, 2)) >= 08 -- has to be a local var, lua error if not

  if (not afterEight) and isEmpty(DAS.todaysLog) and lastDate ~= currentDate then
  local lastLog = DAS.globalSettings.completionLog[lastDate]
  DAS.globalSettings.completionLog[currentDate] = ZO_DeepTableCopy(lastLog, {})
  -- d(DAS.globalSettings.completionLog[currentDate])
  for charName, charLog in pairs(DAS.globalSettings.completionLog[currentDate]) do
  for questName, questData in pairs(charLog) do
  questData.afterEight = false
  end
  end
  characterName                   = characterName or GetUnitName(UNITTAG_PLAYER)
  DAS.todaysLog                   = DAS.globalSettings.completionLog[currentDate]
	DAS.todaysCharacterLog              = DAS.todaysLog[characterName]
  end
  end
  DAS.handleLog = handleLog   -- expose this for debugging purpose

  local function minimiseOnStartup()
	DAS.SetMinimized(DAS.GetSettings().startupMinimized)
  end
  --==============================
  --===== Rise, my minion!  ======
  --==============================

  function DailyAutoShare_Initialize(eventCode, addonName)

	if addonName ~= DAS.name then return end

	DAS.settings        = ZO_SavedVars:New(             "DAS_Settings", 2, "DAS_Settings", defaults)
	DAS.globalSettings  = ZO_SavedVars:NewAccountWide(  "DAS_Globals",  2, "DAS_Globals",  defaults)
  DAS.pdn = GetUnitDisplayName(UNITTAG_PLAYER)

  pointerUpSubzones()
	RegisterEventHooks()

	DAS.CreateMenu(DAS.settings, defaults)
	DAS.CreateGui()

  -- local timetoreset = (GetTimeStamp() - 60*60*7)%86400
  -- zo_callLater(resetQuests, timetoreset)


  handleLog()
  zo_callLater(OnPlayerActivated, 5000)
  zo_callLater(minimiseOnStartup, 5500)
  DAS.CreateMapMarkers()
	EVENT_MANAGER:UnregisterForEvent("DailyAutoShare", EVENT_ADD_ON_LOADED)

  end


  ZO_CreateStringId("SI_BINDING_NAME_TOGGLE_DAS_GUI",  GetString(DAS_SI_TOGGLE))
  ZO_CreateStringId("SI_BINDING_NAME_TOGGLE_DAS_LIST", GetString(DAS_SI_MINIMISE))
  EVENT_MANAGER:RegisterForEvent("DailyAutoShare", EVENT_ADD_ON_LOADED, DailyAutoShare_Initialize)