content: ' Copyright (c) 2018 Roku, Inc. All rights reserved.
  
  sub OnRootContentLoaded()
      ' remove root config
      m.top.content[m.Handler_ConfigField] = invalid
      m.top.content.isLoaded = true
  
      requiredRowsCount = 3
      numrowsToLoad = GetNumRowsToLoad()
  
      nonEmptyRows = 0
  
      if requiredRowsCount > m.top.content.getChildCount() then
          requiredRowsCount = m.top.content.getChildCount()
      end if
  
      MarkRows()
      for each row in m.top.content.GetChildren(-1, 0)
          PopulateLoadingFlags(row)
          if row.GetChildCount() > 0 then
              nonEmptyRows++
              row.isLoaded = true
              row.isLoading = false
              row.isFailed = false
          else
              if row[m.Handler_ConfigField] <> invalid then
                  ' row needs to be loaded
                  callback = {
                      row : row
                      onReceive : sub(data)
                          ClearPageFails(m.row, 0)
                          RemovePageFromQueue(m.row, 0)
                          TryToSetContent()
                      end sub
                  }
                  LoadContentForRow(row, callback)
              end if
          end if
          if numrowsToLoad <= 0 then
              ' we are loading start amount of rows
              exit for
          end if
          numRowsToLoad--
      end for
  
      canSetContent = true 'nonEmptyRows >= requiredRowsCount
  
      if canSetContent then
          m.view.content = m.top.content
      else
          ShouldTryToSetContentOnLoad(true)
      end if
  end sub
  
  sub LoadContentForRow(row, callback = invalid as Object)
      aditionalParams = {}
      shouldDeleteHandlerConfig = not IsInsertionMode(row[m.Handler_ConfigField])
  
      simpleLoadFunction = sub(data, isSuccess)
          if GetGlobalAA().debug then ? "received row content="m.row.title
          m.row.isLoading = false
          m.row.isLoaded = isSuccess
          if m.callback <> invalid
              if isSuccess or m.callback.onError = invalid
                  if m.callback.onReceive <> invalid then m.callback.OnReceive(data)
              else if m.callback.onError <> invalid then
                  m.callback.OnError(data)
              end if
              ' if no extra callback was passed and we failed then we have to restore config
          else if not isSuccess then
              Handler_ConfigField = GetGlobalAA().Handler_ConfigField
  
              if m.row[Handler_ConfigField] = invalid then
                  m.row[Handler_ConfigField] = m.config
              end if
          end if
      end sub
  
      functionToUse = simpleLoadFunction
  
      rowIndex = invalid
      itemIndex = -2
      config = row[m.Handler_ConfigField]
  
      callback = {
          ' this will be used for sorting
          itemIndex: itemIndex
          ' extra callback if needed
          callback: callback
          ' current loading row
          row: row
          ' simple load function that executes basic functionality
          simpleLoadFunction: simpleLoadFunction
          ' config that is used to retrieve content
          config: config
  
          functionToUse: functionToUse
          onReceive: sub(data)
              m.FunctionToUse(data, true)
          end sub
          onError: sub(data)
              m.FunctionToUse(data, false)
          end sub
      }
  
      QueueGetContentData(callback, config, row, aditionalParams, true)
      addPageToQueue(row, 0)
      if shouldDeleteHandlerConfig then row[m.Handler_ConfigField] = invalid
  
      row.isLoaded = false
      row.isLoading = true
      row.isFailed = false
  end sub
  
  function GetNumRowsToLoad()
      return 5
  end function
  
  sub doPrioritySort()
      if m.view.content <> invalid then
          focusedChannel = m.view.channelFocused
          focusedItem = m.view.programFocused
          if focusedItem = invalid or focusedItem < 0 then focusedItem = 0
          if focusedChannel = invalid or focusedChannel < 0 then focusedChannel = 0
          if m.debug then ? "new priority for rows near "focusedChannel
          rowPriority = 10
          itemPriority = 10
          rows = m.view.content.GetChildren( - 1, 0)
          for each taskObject in m.waitingQueue
              ' set new priority
              rowId = taskObject.id[0]
              itemId = taskObject.id[1]
              row = rows[rowId]
  
              if row <> invalid then
                  focusedItem = getFocusedItem(row, 0)
  
                  diffRow = Abs(focusedChannel - rowId)
                  diffItem = Abs(focusedItem - itemId)
                  ' calculate distance from end of row
                  secondItemDiff = diffItem
  
                  secondItemDiff = row.GetChildCount() - itemId + focusedItem
                  ' take smallest distance
                  if diffItem > secondItemDiff then diffItem = secondItemDiff
                  diff = diffItem
                  if diff < diffRow then diff = diffRow
                  taskObject.priority = diff + rowPriority * diffRow + diffItem * itemPriority
              end if
          end for
          ' sort the queue
          m.waitingQueue.SortBy("priority", "r")
      end if
  end sub
  
  sub LoadInsertionContent(pageToLoad, row)
      mapKey = pageToLoad.index
      shouldDeleteHandlerConfig = not IsInsertionMode(row[m.Handler_ConfigField])
      if not isPageAlreadyInQueue(row, mapKey)
          callback = {
              ' this will be used for sorting
              itemIndex: mapKey
              ' extra callback if needed
              row: row
              ' simple load function that executes basic functionality
  
              onReceive: sub(data)
                  ClearPageFails(m.row, m.itemIndex)
                  RemovePageFromQueue(m.row, m.itemIndex)
              end sub
  
              onError: sub(data)
                  ClearPageFails(m.row, m.itemIndex)
                  RemovePageFromQueue(m.row, m.itemIndex)
              end sub
          }
  
          fields = {
              startTime: pageToLoad.pageNum
              offset: pageToLoad.index + 1 'we need to insert content after this point
              endTime: pageToLoad.endTime
          }
  
          'just simple check if everything is done correctly
          if fields.startTime < fields.endTime OR (fields.startTime > 0 AND fields.endTime = 0) then
              config = row[m.Handler_ConfigField]
  
              QueueGetContentData(callback, config, row, fields, true)
              addPageToQueue(row, mapKey)
              if shouldDeleteHandlerConfig then row[m.Handler_ConfigField] = invalid
          end if
      end if
  end sub
  
  sub ShouldTryToSetContentOnLoad(should as Boolean)
      m._tryToSetContentOnLoad = should
  end sub
  
  Sub TryToSetContent()
      if m._tryToSetContentOnLoad = true AND not IsContentSet() then
          requiredRowsCount = 3
          nonEmptyRows = 0
          content = m.top.content
          rowCount = content.getChildCount()
  
          for each row in content.GetChildren(-1, 0)
              if row.getChildCount() > 0 OR row.isFailed = true then nonEmptyRows++
          end for
  
          if nonEmptyRows >= requiredRowsCount OR nonEmptyRows = rowCount then
              m.view.content = content
          end if
      end if
  End Sub
  
  Function IsContentSet() as Boolean
      return m.view.content <> invalid
  End Function
  