-- Scan all panes, while delegating as much work as possible to lines.love search.
-- * Text.search_next in lines.love scans from cursor while wrapping around
--   within the pane, so we need to work around that.
-- * Each pane's search_term field influences whether the search term at
--   cursor is highlighted, so we need to manage that as well. At any moment
--   we want the search_term and search_text to be set for at most a single
--   pane.
--
-- Side-effect: we perturb the cursor of panes as we scan them.
function search_next()
  if Cursor_pane.col < 1 then return end
  clear_all_search_terms()
  local pane = Surface[Cursor_pane.col][Cursor_pane.row]
  if pane == nil then
    return
  end
  print('search next', Cursor_pane.col, Cursor_pane.row, pane.cursor1.line, pane.cursor1.pos)
  local old_cursor_in_cursor_pane = {line=pane.cursor1.line, pos=pane.cursor1.pos}
  -- scan current pane down from cursor
  if search_next_in_pane(Surface[Cursor_pane.col][Cursor_pane.row]) then
    print('found in same pane', pane.cursor1.line, pane.cursor1.pos)
    return
  end
  pane.cursor1 = old_cursor_in_cursor_pane
  -- scan current column down from current pane
  for current_pane_index=Cursor_pane.row+1,#Surface[Cursor_pane.col] do
    local pane = Surface[Cursor_pane.col][current_pane_index]
    pane.cursor1 = {line=1, pos=1}
    pane.screen_top1 = {line=1, pos=1}
    if search_next_in_pane(pane) then
      Cursor_pane.row = current_pane_index
      print('found in same column', Cursor_pane.col, Cursor_pane.row, pane.cursor1.line, pane.cursor1.pos)
      return
    end
  end
  local current_column_index = 1 + Cursor_pane.col%#Surface  -- (i+1)%#Surface in the presence of 1-indexing
  -- scan columns past current, looping around
  while true do
    for current_pane_index,pane in ipairs(Surface[current_column_index]) do
      pane.cursor1 = {line=1, pos=1}
      pane.screen_top1 = {line=1, pos=1}
      if search_next_in_pane(pane) then
        Cursor_pane = {col=current_column_index, row=current_pane_index}
        print('found', Cursor_pane.col, Cursor_pane.row, pane.cursor1.line, pane.cursor1.pos)
        return
      end
    end
    -- loop update
    current_column_index = 1 + current_column_index%#Surface  -- i = (i+1)%#Surface in the presence of 1-indexing
    -- termination check
    if current_column_index == Cursor_pane.col then
      break
    end
  end
  -- scan current column until current pane
  for current_pane_index=1,Cursor_pane.row-1 do
    if search_next_in_pane(Surface[Cursor_pane.col][current_pane_index]) then
      Cursor_pane.row = current_pane_index
      print('found in same column', Cursor_pane.col, Cursor_pane.row, pane.cursor1.line, pane.cursor1.pos)
      return
    end
  end
  -- finally, scan the cursor pane until the cursor
  local pane = Surface[Cursor_pane.col][Cursor_pane.row]
  local old_cursor = pane.cursor1
  pane.cursor1 = {line=1, pos=1}
  pane.screen_top1 = {line=1, pos=1}
  if search_next_in_pane(pane) then
    if Text.lt1(pane.cursor1, old_cursor) then
      return
    end
  end
  -- nothing found
  print('f')
  pane.cursor1 = old_cursor_in_cursor_pane
end
-- returns whether it found an occurrence
function search_next_in_pane(pane)
  pane.search_term = Display_settings.search_term
  pane.search_text = Display_settings.search_text
  pane.search_backup = {cursor={line=pane.cursor1.line, pos=pane.cursor1.pos}, screen_top={line=pane.screen_top1.line, pos=pane.screen_top1.pos}}
  for i=1,#pane.lines do
    if pane.line_cache[i] == nil then
      pane.line_cache[i] = {}
    end
  end
  if Text.search_next(pane) then
    if Text.le1(pane.search_backup.cursor, pane.cursor1) then
      -- select this occurrence
      return true
    end
    -- Otherwise cursor wrapped around. Skip this pane.
  end
  -- Clean up this pane before moving on to the next one.
  pane.search_term = nil
  pane.search_text = nil
  pane.cursor1.line = pane.search_backup.cursor.line
  pane.cursor1.pos = pane.search_backup.cursor.pos
  pane.screen_top1.line = pane.search_backup.screen_top.line
  pane.screen_top1.pos = pane.search_backup.screen_top.pos
  pane.search_backup = nil
end
-- Scan all panes, while delegating as much work as possible to lines.love search.
function search_previous()
end
function bring_cursor_of_cursor_pane_in_view(dir)
  if Cursor_pane.col < 1 then
    return
  end
  local pane = Surface[Cursor_pane.col][Cursor_pane.row]
  if pane == nil then
    return
  end
--?   print('viewport before', Display_settings.x, Display_settings.y)
  local left_edge_sx = left_edge_sx(Cursor_pane.col)
  local cursor_sx = left_edge_sx + Text.x_of_schema1(pane, pane.cursor1)
  local vertically_ok = cursor_sx > Display_settings.x and cursor_sx < Display_settings.x + App.screen.width - App.width(Em)
  local cursor_sy = up_edge_sy(Cursor_pane.col, Cursor_pane.row) + y_of_schema1(pane, pane.cursor1)
--?   print(cursor_sy, Display_settings.y, App.screen.height, Line_height, Display_settings.y + App.screen.height - 2*Line_height)
  local horizontally_ok = cursor_sy > Display_settings.y and cursor_sy < Display_settings.y + App.screen.height - Header_height - 2*Line_height  -- account for search bar along the bottom
  if vertically_ok and horizontally_ok then
    return
  end
  if dir == 'up' then
    if not vertically_ok then
      Display_settings.x = left_edge_sx - Margin_left - Padding_horizontal
    end
    if not horizontally_ok then
      Display_settings.y = cursor_sy - 3*Line_height
    end
  else
    assert(dir == 'down')
    if not vertically_ok then
      Display_settings.x = left_edge_sx + Display_settings.column_width + Margin_right + Padding_horizontal - App.screen.width
    end
    if not horizontally_ok then
      Display_settings.y = cursor_sy + 3*Line_height - (App.screen.height - Header_height)
    end
  end
--?   print('viewport before clamp', Display_settings.x, Display_settings.y)
  Display_settings.x = math.max(Display_settings.x, 0)
  Display_settings.y = math.max(Display_settings.y, 0)
--?   print('viewport now', Display_settings.x, Display_settings.y)
end
function clear_all_search_terms()
  for col,column in ipairs(Surface) do
    for row,pane in ipairs(column) do
      pane.search_term = ''
      pane.search_text = nil
    end
  end
end