local VALUE = 0
local COMBO = 1

local TA_LEFT = 0
local TA_RIGHT = 1

local fields = {}

local printText = (0x800 + 0x02)
local hPWin = 0
local Id = 0
local editMode = false
local modifications = {}
local refreshState = 0
local calibrationStep = 0
local calibrationState = 0
local pageOffset = 0
local page = 1
local pages = {}


local configFields = {
  {"Wing type:", COMBO, 0x80, nil, { "Normal", "Delta", "VTail" } },
  {"Mounting type:", COMBO, 0x81, nil, { "Horz", "Horz rev.", "Vert", "Vert rev." }},
}

local settingsFields = {
  {"S6R functions:", COMBO, 0x9C, nil, { "Disable", "Enable" } },
  {"Quick Mode:", COMBO, 0xAA, nil, { "Disable", "Enable" } },
  {"Enable ch5 as Ail2:", COMBO, 0xA8, nil, { "Disable", "Enable" } },
  {"Enable ch6 as Ele2:", COMBO, 0xA9, nil, { "Disable", "Enable" } },
  {"AIL direction:", COMBO, 0x82, nil, { "Normal", "Invers" }, { 255, 0 } },
  {"ELE direction:", COMBO, 0x83, nil, { "Normal", "Invers" }, { 255, 0 } },
  {"RUD direction:", COMBO, 0x84, nil, { "Normal", "Invers" }, { 255, 0 } },
  {"AIL2 direction:", COMBO, 0x9A, nil, { "Normal", "Invers" }, { 255, 0 } },
  {"ELE2 direction:", COMBO, 0x9B, nil, { "Normal", "Invers" }, { 255, 0 } },
  {"AIL stabilize gain:", VALUE, 0x85, nil, 0, 200, "%"},
  {"ELE stabilize gain:", VALUE, 0x86, nil, 0, 200, "%"},
  {"RUD stabilize gain:", VALUE, 0x87, nil, 0, 200, "%"},
  {"AIL auto level gain:", VALUE, 0x88, nil, 0, 200, "%"},
  {"ELE auto level gain:", VALUE, 0x89, nil, 0, 200, "%"},
  {"ELE hover gain:", VALUE, 0x8C, nil, 0, 200, "%"},
  {"RUD hover gain:", VALUE, 0x8D, nil, 0, 200, "%"},
  {"AIL knife-edge gain:", VALUE, 0x8E, nil, 0, 200, "%"},
  {"RUD knife-edge gain:", VALUE, 0x90, nil, 0, 200, "%"},
  {"AIL auto angle offset:", VALUE, 0x91, nil, -20, 20, "%", 0x6C},
  {"ELE auto angle offset:", VALUE, 0x92, nil, -20, 20, "%", 0x6C},
  {"ELE hover angle offset:", VALUE, 0x95, nil, -20, 20, "%", 0x6C},
  {"RUD hover angle offset:", VALUE, 0x96, nil, -20, 20, "%", 0x6C},
  {"AIL knife-edge angle offset:", VALUE, 0x97, nil, -20, 20, "%", 0x6C},
  {"RUD knife-edge angle offset:", VALUE, 0x99, nil, -20, 20, "%", 0x6C},
}


local calibrationFields = {
  {"X:", VALUE, 0x9E, 0, -100, 100, "%"},
  {"Y:", VALUE, 0x9F, 0, -100, 100, "%"},
  {"Z:", VALUE, 0xA0, 0, -100, 100, "%"}
}

local function telemetryRead(field)
	return sport.TelemetryPush(0x1b, 0x30, 0x0C30, field)
end

local function telemetryWrite(field, value)
	return sport.TelemetryPush(0x1b, 0x31, 0x0C30, field+value*256)  
end

-- Redraw the current page
local function redrawFieldsPage(hWin)
  
  if #fields > NUM_PER_PAGE then
    drawScrollbar(hWin, #fields, NUM_PER_PAGE, pageOffset)
  end

	for index = 1, NUM_PER_PAGE, 1 do
		local field = fields[pageOffset+index]
		if field == nil then
		  break
		end		
    
    drawText(hWin, index-1, field[1], TA_LEFT)
    
		if field[4] == nil then
			if field[2] == VALUE then
				drawEdit(hWin, index-1, "---")
			elseif field[2] == COMBO then			
				drawDropdown(hWin, index-1, 0, "---")
			end	
		else
      if field[2] == VALUE then
        drawEdit(hWin, index-1, field[4], field[5], field[6], 0) 
      elseif field[2] == COMBO then
        if field[4] >= 0 and field[4] < #(field[5]) then		
          local attr = field[5][1].."|"
          for index2 = 2,  #(field[5]), 1 do
            attr = attr..field[5][index2]
            if index2 <= #(field[5]) then
              attr = attr.."|"
            end
          end		
        drawDropdown(hWin, index-1, field[4], attr)
        end
      end
    end
  end
end

local function refreshNext()  
  if refreshState == 0 then  
    if calibrationState == 1 then
      if telemetryWrite(0x9D, calibrationStep) == true then   
        refreshState = 1
        calibrationState = 2
        telemetryPopTimeout = getTime() + 500 -- normal delay is 500ms
      end
    elseif #modifications > 0 then                 
        if true == telemetryWrite(modifications[1][1], modifications[1][2]) then
          table.remove(modifications,1)--modifications[1] = nil
          refreshIndex = 0
        end
    elseif refreshIndex < #fields then
			local field = fields[refreshIndex + 1]      
			if telemetryRead(field[3]) == true then     
				refreshState = 1
				telemetryPopTimeout = getTime() + 500 -- normal delay is 500ms
			end
    end
	elseif refreshState == 1 then
		local appId, primId, value = sport.TelemetryPop()    
    if appId == 0x0C30 and primId == 0x32 then          
      local fieldId = value % 256            
      if calibrationState == 2 then        
        if fieldId == 0x9D then
          refreshState = 0
          calibrationState = 3
        end
      else
        local field = fields[refreshIndex + 1]
        
        if fieldId == field[3] then 
          local value = math.floor(value / 256)      
                  
          if field[3] >= 0x9E and field[3] <= 0xA0 then  
            local b1 = value % 256
            local b2 = math.floor(value / 256)
            value = b1*256 + b2
            value = value - bit32.band(value, 0x8000) * 2
            
            if 3 == calibrationState then              
              calibrationState = 0
              calibrationStep = (calibrationStep + 1) % 6
            end
          end         
          
          if field[2] == COMBO and #field == 6 then  
            for index = 1, #(field[6]), 1 do
              if value == field[6][index] then
                value = index - 1
                break
              end
            end
          elseif field[2] == VALUE and #field == 8 then 
            value = value - field[8] + field[5]
          end
          
          fields[refreshIndex + 1][4] = value
          refreshIndex = refreshIndex + 1
          refreshState = 0
        end
      end
      
		elseif getTime() > telemetryPopTimeout then 
			refreshState = 0
			calibrationState = 0
		end
	end
end

-- Main
local function runFieldsPage(hWin, Key)  
  redrawFieldsPage(hWin)
  return 0
end

local wingBitmaps = { "1:/IMAGES/S6RScript/plane.bmp", "1:/IMAGES/S6RScript/delta.bmp", "1:/IMAGES/S6RScript/vtail.bmp", 0 }
local mountBitmaps = { "1:/IMAGES/S6RScript/horz.bmp", "1:/IMAGES/S6RScript/horz-r.bmp", "1:/IMAGES/S6RScript/vert.bmp", "1:/IMAGES/S6RScript/vert-r.bmp", 0 }

local function runConfigPage(hWin, Key)

  fields = configFields
  local result
  if false == editMode then
    result = runFieldsPage(hWin, Key)    
    
    if fields[1][4] ~= nil then
      local imageId = drawBitmap(hWin, wingBitmaps[#wingBitmaps], 30, 90, 132, 68, wingBitmaps[1 + fields[1][4]])
      wingBitmaps[#wingBitmaps] = imageId
    end
    
    if fields[2][4] ~= nil then
      local imageId = drawBitmap(hWin, mountBitmaps[#mountBitmaps], 270, 90, 132, 68, mountBitmaps[1 + fields[2][4]])
      mountBitmaps[#mountBitmaps] = imageId
    end      
       
  end
  return result
end

local function runSettingsPage(hWin, Key)

  fields = settingsFields    
  
  local result
  
  if false == editMode then
    result = runFieldsPage(hWin, Key) 
  end
  
  return result
end

local calibrationPositions = {"upright","upside-down","nose down","nose up","on its left side","on its right side"};
local calibrationImages = { "up", "down", "left", "right", "forward", "back" }
local calTextId = {0, 0, 0, 0, 0}
local bitmapId = 0
local buttonId = 0
local function initCaliData()
   calTextId = {0, 0, 0, 0, 0}
   bitmapId = 0
   buttonId = 0
end
local function runCalibrationPage(hWin, key)
  fields = calibrationFields
  if refreshIndex == #fields then
    refreshIndex = 0
  end
  
  local position = calibrationPositions[1 + calibrationStep]
  calTextId[1] = createText(hWin, calTextId[1], 30, 30, 240, 20, "Turn the S6R " .. position, TA_LEFT)
  local image = calibrationImages[1 + calibrationStep]
  bitmapId = drawBitmap(hWin, bitmapId, 30, 60, 132, 68, "1:/IMAGES/S6RScript/"..image .. ".bmp")
  
  buttonId = createButton(hWin, buttonId, 30, 165, 180, 20,"press ENTER when ready", 1)
  
  for index = 1, 3, 1 do
    local field = fields[index]
    
    calTextId[index+1] = createText(hWin, calTextId[index+1], 270, 30+30*index,180, 20, field[1].."  "..(field[4]/1000), TA_LEFT)
  end
 
  if key == KEY_ENT_R and 0 == calibrationState then
    calibrationState = 1
  end  
  return 0
end

-- Select the next or previous page
local function selectPage(step)
  page = 1 + ((page + step - 1 + #pages) % #pages)
  
	current, edit, refreshState, refreshIndex, pageOffset, calibrationStep, calibrationState = 1, false, 0, 0, 0, 0, 0
  
  wingBitmaps[#wingBitmaps] = 0
  mountBitmaps[#mountBitmaps] = 0
  
  initCaliData()
  
  clearAll(hPWin)  
end

-- Select the next or previous editable field
local function selectField(step)
  local retValue = 1
  current = current + step  
  
  if current > #fields then
    current = #fields 
  elseif current < 1 then  
    current = 1
  elseif current > NUM_PER_PAGE + pageOffset then
    pageOffset = current - NUM_PER_PAGE
  elseif current <= pageOffset then
    pageOffset = current - 1 
  else
    retValue = 0
  end
  
  return retValue
end


local function updateField(field)
  local value = field[4]
  if nil ~= value then
    value = getWValue(current-pageOffset-1, field[2])
    
    if field[2] == COMBO and #field == 6 then
      value = field[6][1+value]
    elseif field[2] == VALUE and #field == 8 then
      value = value + field[8] - field[5]
    end
    
    modifications[#modifications+1] = { field[3], value }
    
    if 3 ~= page then
      if field[2] == COMBO and #field == 6 then  
        for index = 1, #(field[6]), 1 do
          if value == field[6][index] then
            field[4] = index - 1
            break
          end
        end
      elseif field[2] == VALUE and #field == 8 then 
        field[4] = value - field[8] + field[5]
      else
        field[4] = value
      end 
    end
  end
end

-- Init
function init()
	current, edit, refreshState, refreshIndex = 1, false, 0, 0
  
	pages = {
		runConfigPage,
		runSettingsPage,
		runCalibrationPage
	}  
end

--run
function runLua(hWin, Key)
  hPWin = hWin
  local result = 0
    
	if Key == 0 then
		result = 0
	elseif Key == 1 then     
    --result = runConfigPage(hWin,Key)
  elseif Key == KEY_ENT then 
      if true == editMode then      
        updateField(fields[current])
      end   
      editMode = not editMode 
  elseif Key == KEY_TAB then
    result = selectField(1)
  elseif Key == KEY_BACKTAB then
    result = selectField(-1)    
  elseif Key == KEY_PGDN_R then
    selectPage(1)
  elseif Key == KEY_PGUP_R then
    selectPage(-1)
  elseif Key == KEY_RTN_R then 
    if true == editMode then
      editMode = not editMode
    else           
      clearAll(hWin)
    end 
  else 
    
	end  
  
  drawTitle(hPWin, "SXR", page, #pages)
  
  pages[page](hWin,Key)
  
	refreshNext()

	return result
 end
