local group = class("core.ui.uniqueType", require("core.ui.uitype.groupBase"))

function group:ctor(ui, config)
  group.super.ctor(self, ui, config)
  self._curPage = nil
  self._freePages = {}
  self._freeIndex = 0
  self._uniqueOutCount = config.uniqueOutCount or 1
end

function group:_enterFreePage(pageName, page)
  self._freeIndex = self._freeIndex + 1
  page.index = self._freeIndex
  self._freePages[pageName] = page
  local indexes = {}
  local indexesPages = {}
  for i, v in pairs(self._freePages) do
    table.insert(indexes, v.index)
    indexesPages[v.index] = v
  end
  table.sort(indexes, function(a, b)
    return b < a
  end)
  for i = self._uniqueOutCount, #indexes do
    local d = indexesPages[indexes[i]]
    d.cls:unBind()
    d.cls:destroy()
    d.cls:disposeUIBinding()
    self._ui:execMiddleware("onDestroy", d.assetName, d.gameObject)
    if d.cls.loadHandle:IsValid() then
      self._ui:execMiddleware("releaseHandler", d.cls)
    end
    self._freePages[d.pageName] = nil
  end
end

function group:_doOpen(page, options)
  self._ui:profilerMarkTimeForRecord(page.pageName, "t_doOpenStart")
  page.cls:open(options)
  page.cls:show(options)
  self._ui:playAudio(self._ui.audioEvent.pageBgm, page.config.windowBGM, true)
  self._ui:dispatch(self._ui.pageEvent.showed, page.pageName)
  if page.config.blockInput then
    self._ui:execMiddleware("blockInput", true)
  end
  self._ui:profilerMarkTimeForRecord(page.pageName, "t_doOpenEnd")
end

function group:_toOpen(page, options, callback)
  self._ui:profilerMarkTimeForRecord(page.pageName, "t_preOpenStart")
  self:disableRaycaster()
  page.gameObject:SetActive(true)
  page.cls:openModules(options)
  page.cls:showModules()
  page.cls:preOpen(options)
  self._ui:playAudio(self._ui.audioEvent.pageOpen, page.config.windowOpenAudio)
  self._ui:dispatch(self._ui.pageEvent.preOpen, page.pageName)
  page.cls.status = "shown"
  page.status = "shown"
  self._ui:profilerMarkTimeForRecord(page.pageName, "t_preOpenEnd")
  if page.cls.blendDefinition then
    page.animating = true
    page.cls.blendDefinition:OpenReset()
    self._ui:profilerMarkTimeForRecord(page.pageName, "t_openAnimStart")
    page.cls.blendDefinition:PlayOpen(function()
      self._ui:profilerMarkTimeForRecord(page.pageName, "t_openAnimEnd")
      self:enableRaycaster()
      page.animating = false
      if page.status == "shown" then
        self:_doOpen(page, options)
      end
      if callback ~= nil then
        callback(true)
      end
    end)
  else
    self:enableRaycaster()
    self:_doOpen(page, options)
    if callback ~= nil then
      callback(true)
    end
  end
end

function group:_toCheck(page, options, callback)
  self._ui:checkPage(page, options, function(result)
    if result then
      self:_toOpen(page, options, callback)
    elseif callback ~= nil then
      callback(false)
    end
  end)
end

function group:open(pageName, options, callback)
  if self._curPage ~= nil then
    if callback ~= nil then
      callback(false)
    end
    print("uniquepage is dont nil:" .. self._curPage.pageName .. "must close")
    return
  end
  self._curPage = self._freePages[pageName]
  if self._curPage == nil then
    local newPageFailed = false
    local page = self._ui:newPage(pageName, options, function(p)
      newPageFailed = p == nil
      self._curPage = p
      if p then
        self:_toOpen(p, options, callback)
      elseif callback ~= nil then
        callback(false)
      end
    end)
    if not newPageFailed then
      self._curPage = page
    end
  else
    self._freePages[pageName] = nil
    self:_toCheck(self._curPage, options, function(result)
      if result == false then
        self._curPage = nil
      end
      if callback ~= nil then
        callback(result)
      end
    end)
  end
end

function group:currentPage()
  if self._curPage ~= nil then
    return self._curPage.pageName
  else
    return nil
  end
end

function group:_doClose(options)
  local page = self._curPage
  if page.cls.status == "shown" then
    page.cls:hide()
    self._ui:dispatch(self._ui.pageEvent.hided, page.pageName)
  end
  self:_enterFreePage(page.pageName, page)
  self._curPage = nil
  page.cls:close(options)
  page.cls:hideModules()
  page.cls:closeModules(options)
  page.gameObject:SetActive(false)
  page.status = "closed"
  page.cls.status = "closed"
  self._ui:dispatch(self._ui.pageEvent.closed, page.pageName)
end

function group:close(pageName, options, callback)
  if self._curPage == nil then
    print("uniquepage is nil  must open")
    return
  end
  if self._curPage.cls.blendDefinition then
    self._curPage.animating = true
    self._curPage.cls.blendDefinition:CloseReset()
    self._curPage.cls.blendDefinition:PlayClose(function()
      self._curPage.animating = false
      self:_doClose(options)
      if callback ~= nil then
        callback(pageName)
      end
    end)
  else
    self:_doClose(options)
    if callback ~= nil then
      callback(pageName)
    end
  end
end

function group:update()
  if self._curPage ~= nil and self._curPage.status == "shown" then
    local pcls = self._curPage.cls
    if pcls and pcls.update then
      pcls:update()
    end
  end
end

function group:info()
  if self._curPage ~= nil then
    local result = "UniquePages:"
    result = result .. self._curPage.pageName .. ","
    return result
  else
    return nil
  end
end

function group:pageInfo(pageName)
  if self._curPage ~= nil then
    return table.tostring(self._curPage, 20)
  else
    return nil
  end
end

function group:internalEnableRaycaster()
  if self._curPage and self._curPage.status == "shown" then
    self._ui:setPageRaycasterEnabled(self._curPage, true)
  end
end

function group:internalDisableRaycaster()
  if self._curPage and self._curPage.status == "shown" then
    self._ui:setPageRaycasterEnabled(self._curPage, false)
  end
end

function group:destroy(pageName, options)
  local d = self._curPage
  if d then
    self._curPage = nil
  else
    d = self._freePages[pageName]
    self._freePages[pageName] = nil
  end
  if d then
    d.cls:unBind()
    d.cls:destroy(options)
    self._ui:execMiddleware("onDestroy", d.asset)
    if d.cls.loadHandle:IsValid() then
      self._ui:execMiddleware("releaseHandler", d.cls)
    end
  end
end

function group:getPage(pageName)
  if self:currentPage() == pageName then
    return self._curPage
  end
  return nil
end

function group:getAllPages()
  local ret = {}
  if self._curPage then
    ret[self._curPage.pageName] = self._curPage
  end
  return ret
end

function group:refreshAllPages()
  if self._curPage and self._curPage.cls then
    self._curPage.cls:refresh()
    self._curPage.cls:refreshModules()
  end
end

function group:clearAllPages()
  if self._curPage == nil then
    return
  end
  self:destroy(self._curPage.pageName)
end

return group
