local VALUE = 0
local COMBO = 1
local OREAD = 2  -- read only 

local printText = (0x800 + 0x02)
local hPWin = 0

local TA_LEFT = 0
local TA_RIGHT = 1

local fields = {}
local field
local pages = {}
local page = 1

local modifications = {}
local current
local editMode = false
local refreshState = 0
local refreshIndex = 0
local pageOffset = 0

local configFields = {
  {"CDI off speed limit(*100RPM)", VALUE, 0x81, nil, 10,10000},--100
  {"Milliliter per pulse(*0.001mL/pul)", VALUE, 0x80, nil, 1, 2000},--100
  {"Volume(mL)", VALUE, 0x83, nil, 10,60000},--1000
  --{"Flow trigger(mL/min)", VALUE, 0x84, nil, 5, 50 },--10
  --{"Auto Reset", COMBO, 0x85, nil, { "ON", "OFF" }, {1 , 0}},  -- 0
  {"Auto Reset", COMBO, 0x8d, nil, { "ON", "OFF" }, {0 , 1}},  -- 0
  {"Rset to factory settings", COMBO, 0x86, nil,{ "YES", "NO" }, {1 , 0} }, -- 1
  {"Volume alarm(%)", VALUE, 0x87, nil, 0, 90 },
  {"Max.Flow alarm(mL/min)", VALUE, 0x88, nil, 0, 2000 },--mL/min      4AMT
  {"Over speed alarm(*100RPM)", VALUE, 0x89, nil, 0, 10000 },--100r/min   4AMT
  {"Over temperature1 alarm(C/F)", VALUE, 0x8a, nil, 0, 600 },
  {"Over temperature2 alarm(C/F)", VALUE, 0x8b, nil, 0, 600 },
  {"Temperature Celsius/Fahrenheit", COMBO, 0x8c, nil,{ "C", "F" }, {0 , 1} },
}--{"FLOW_2_RPM", COMBO, 0x82, nil, { "FLOW", "RPM" }, {0 , 1}},

local settingsFields = {
  {"Software version", OREAD, 0x0c, nil, 1, 100 },--only read
  {"Physical ID", VALUE, 0x01, nil, 0, 26 },
  {"Application IDgroup", VALUE, 0x0D, nil, 0, 15 },
  {"Data rate(*100ms)", VALUE, 0x22, nil, 1, 255 },
 -- {"Temp rate(*10ms)", VALUE, 0x23, nil, 10, 255 },
 -- {"Fuel rate(*10ms)", VALUE, 0x24, nil, 10, 255 },
}

local telemetryFields = {
  {"TEMP1(C/F)", VALUE, 0x90, nil, -20, 310},  --"..string.char(0x7f).."
  {"TEMP2(C/F)", VALUE, 0x91, nil, -20, 310},
  {"SPEED(r/min)", VALUE, 0x92, nil, 0, 100000},
  {"Residual Volume(mL)", VALUE, 0x93, nil, 0, 60000},
  {"Residual Percent(%)", VALUE, 0x94, nil, 0, 100},
  {"FLOW(mL/min)", VALUE, 0x95, nil, 0, 2000},
  {"Max Flow(mL/min)", VALUE, 0x96, nil, 0, 2000},  --"Maximal Flow(mL/min)"
  {"Avg Flow(mL/min)", VALUE, 0x97, nil, 0, 2000},  --"Average Flow(mL/min)"
}



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

local function telemetryListen(fieldx)
  return sport.TelemetryPush(0x1b,  0,  0, 0)
end

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


-- Redraw the current page
local function redrawFieldsPage()
  
  if #fields > NUM_PER_PAGE then
    drawScrollbar(hPWin, #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(hPWin, index-1, field[1], TA_LEFT)
    
		if field[4] == nil then
			if field[2] == VALUE or field[2] == OREAD then
				drawEdit(hPWin, index-1, "---")
			elseif field[2] == COMBO then			
				drawDropdown(hPWin, index-1, 0, "---")
			end	
		else      
      if field[2] == VALUE then
        if (field[3] == 0x90 or field[3] == 0x91) and field[4] == 500 then
          drawEdit(hPWin, index-1, "---")
        else
          drawEdit(hPWin, index-1, field[4], field[5], field[6], 0)
        end
      elseif field[2] == OREAD then        
        if field[3] == 0x0c then --version show as string
          drawEdit(hPWin, index-1, field[4])
        end
      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(hPWin, index-1, field[4], attr)
        end      
      end
    end
  end
end


local telemetryPopTimeout = 0
local function refreshNext()    
  if refreshState == 0 and page~= 3 then   
    if #modifications > 0 then 
      if modifications[1][1] ~= 0x0c then
        if modifications[1][1] == 0x22 then
          modifications[1][2] = modifications[1][2] + 0xf00
        end
        local modificationstmp = modifications[1][2]
        if modifications[1][1] == 0x8a or modifications[1][1] == 0x8b then
          if configFields[11][4]== 1 then
            modificationstmp = (modifications[1][2] - 32)*10
            modificationstmp = math.floor(modificationstmp/18)
          end
        end
        telemetryWrite(modifications[1][1], modificationstmp)
        refreshIndex = 0
      end
      modifications[1] = nil
    elseif refreshIndex < #fields then
      local field = fields[refreshIndex + 1]
      if telemetryRead(field[3]) == true then
        refreshState = 1
        telemetryPopTimeout = getTime() + 80
      end
    end
  elseif refreshState == 0 and page == 3 then
    if #modifications > 0 then
      if modifications[1][1] == 0x96 or modifications[1][1] == 0x97 or modifications[1][1] == 0x93  then
        telemetryWrite(modifications[1][1], 0)
      end
      modifications[1] = nil
      --refreshIndex = 0
    elseif refreshIndex < #fields then
      local field = fields[refreshIndex + 1]
      if telemetryRead(field[3]) == true then
        refreshState = 1
        telemetryPopTimeout = getTime() + 200 -- normal delay  
      end
    elseif refreshIndex >= #fields then  -- again and again
      refreshIndex = 0
      refreshState = 0
    end
  elseif refreshState == 1  and page ~= 3  then  
    local dataId, primId, value = sport.TelemetryPop()  
    if  primId == 0x32 and dataId >= 0x0d00 and dataId <= 0x0d7f then 
      local fieldId = value % 256 
      field = fields[refreshIndex + 1]
      if fieldId == field[3] then  
        value = math.floor(value / 256)
        
        if field[2] == COMBO then 
          for index = 1, #(field[6]), 1 do
            if value == field[6][index] then
              value = index - 1
              break
            end
          end
        elseif field[2] == VALUE  then
          value = value 
        end              
        if field[3] == 0x0c then
          local flo_string = string.char(value/16%16 + 48).."."..string.char(value%16 + 48)
          fields[refreshIndex + 1][4] = flo_string
        else          
          fields[refreshIndex + 1][4] = value  
        end
        
        refreshIndex = refreshIndex + 1
        refreshState = 0
      --elseif refreshIndex < #fields then 
        --local field = fields[refreshIndex + 1]
        --if telemetryRead(field[3]) == true then
          --refreshState = 1
          --telemetryPopTimeout = getTime() + 200 -- normal delay is 500ms
        --end
      end
    elseif getTime() > telemetryPopTimeout then
      refreshState = 0
    end 
  elseif  refreshState == 1 and page == 3 then --telemetryFields
    local pageID3 = 0
    local dataId3, primId3, value3 = sport.TelemetryPop()
    
    if value3 ~= nil then
     pageID3 = value3 % 256
     value3 = math.floor(value3/0x100)
    end
    
    if primId3 == 0x32 and value3 ~= nil then       
      if pageID3 == fields[refreshIndex + 1][3] then
        local field = fields[refreshIndex + 1]
        if field[2] == COMBO and #field == 6 then
          for index = 1, #(field[6]), 1 do
            if value3 == field[6][index] then
              value3 = index - 1
              break
            end
          end
        elseif field[2] == VALUE  then
          if field[3] == 0x90 or field[3] == 0x91 then
            value3 = math.floor(value3 % 0x10000)
            if value3 > 0xf000 then
              value3 = value3 - 0x10000
            end
            if configFields[11][4]== 1 and (field[3] == 0x90 or field[3] == 0x91) then
              value3 =(value3*18)
              value3 = math.floor(value3/10)+32
            end
          else
            value3 = value3
          end
        end
        fields[refreshIndex + 1][4] = value3
        refreshIndex = refreshIndex + 1
        refreshState = 0
      end
    elseif getTime() > telemetryPopTimeout then 
			refreshState = 0
		end
  end
end

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

local function runConfigPage(Key)
  fields = configFields
  local result
  if false == editMode then
    result = runFieldsPage(Key)          
  end
  return result
end

local function runSettingsPage(Key)
  --setWValue(hPWin, printText, "runSettingsPage")
  fields = settingsFields
  local result
  if false == editMode then
    result = runFieldsPage(Key)          
  end
  return result
end

local function runTelemetryPage(Key)
  fields = telemetryFields
  local result
  if false == editMode then
    result = runFieldsPage(Key)          
  end
  return result
end

-- Select the next or previous page
local function selectPage(step)
  page = 1 + ((page + step - 1 + #pages) % #pages)  
	current, edit, refreshState, refreshIndex, pageOffset = 1, false, 0, 0, 0  
  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 field[2] ~= OREAD and nil ~= value then  
    value = getWValue(current-pageOffset-1, field[2]) 
    if page ~= 3 then    
      if field[2] == COMBO and #field == 6 then
        value = field[6][1+value]        
        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 == 6 then        
        field[4] = value  
      end      
    else   
      if field[3] == 0x93 then
        if nil~=configFields[3][4] then 
          value = configFields[3][4]
          field[4] = configFields[3][4]
        else
          value = 0
          field[4] = 0
        end         
      elseif field[3] == 0x96 or field[3] == 0x97 then
        value = 0
        field[4] = 0
      end      
    end 
    
    --setWValue(hPWin, printText, "num "..#modifications.." "..field[3].." "..value)
    modifications[#modifications+1] = { field[3], value }  
  end    
end


local function background()
  local tonefrq,tonelength
  local thistime = getTime()
  local lastTime = thistime
  
  refreshNext()  
  
  if page == 3  then --alarm
    local alarmnum = 0
    if fields[3][4] ~= nil and configFields[9][4] ~= nil then --telemetryFields
      local speedtest = fields[3][4]
      local speedover = configFields[9][4]*100      
      if speedtest >= speedover then 
        tonefrq = 800 + math.max(0,math.floor((speedtest - speedover)/10))
        tonelength = 50 + math.max(0,(150 - math.floor((speedtest - speedover)/10)))	  
	  tonepause = tonelength
        audio.PlayBeep(tonefrq, tonelength, 2)
        alarmnum = alarmnum + 1
      end	  --PLAY_NOW  PLAY_BACKGROUND
    end 
    if  fields[5][4] ~= nil and configFields[7][4] ~= nil then
      local  Residualtest = fields[5][4]    --%   
      local  Residualline = configFields[6][4]	--fuel volume alarm!    %             fuel volume alarm!
      if Residualtest < Residualline then
        tonefrq = 400
        tonelength = 100
        --tonepause = 1000 + math.floor( Residualline - Residualtest )*30  --%
        --playTone(tonefrq, tonelength, tonepause, PLAY_BACKGROUND,10)         
        audio.PlayBeep(tonefrq, tonelength, 2)
        alarmnum = alarmnum + 1
      end
    end
    if fields[6][4] ~= nil and configFields[8][4] ~= nil then
    local  Flowtest = fields[6][4]    
    local  Flowover = configFields[7][4]
	if Flowtest > Flowover then
        tonefrq = 400
        tonelength = 100
        --tonepause = 200  --
        --playTone(tonefrq, tonelength, tonepause, PLAY_BACKGROUND,10)  
        audio.PlayBeep(tonefrq, tonelength, 2)
        alarmnum = alarmnum + 1
      end
    end
    if fields[1][4] ~= nil and configFields[10][4] ~= nil then
      local  temp1test = fields[1][4]    --  
    local  temp1over = configFields[9][4]
      if temp1test > temp1over and (temp1test ~= 500 and temp1test ~= 932)then  
        tonefrq = 2000
        tonelength = 100
        --tonepause = 900  --
        --playTone(tonefrq, tonelength, tonepause, PLAY_BACKGROUND,10)  
        audio.PlayBeep(tonefrq, tonelength, 2)
        alarmnum = alarmnum + 1
      end
    end 
    if  fields[2][4] ~= nil and configFields[11][4] ~= nil then
      local  temp2test = fields[2][4]    --  
    local  temp2over = configFields[10][4]
      if temp2test > temp2over and (temp2test ~= 500 and temp2test ~= 932) then  
        tonefrq = 2000
        tonelength = 300
        --tonepause = 700  --
        --playTone(tonefrq, tonelength, tonepause, PLAY_BACKGROUND,10)  
        audio.PlayBeep(tonefrq, tonelength, 2)
        alarmnum = alarmnum + 1
      end
    end
    if alarmnum > 1 then 
      --playTone(2000, 100, 100, PLAY_BACKGROUND,10) 
        audio.PlayBeep(2000, 100, 2)
    end 
    alarmnum = 0
  end
end

-- Init
function init()

	current, editMode, refreshState, refreshIndex = 1, false, 0, 0
  
	pages = {
    runConfigPage,
    runSettingsPage,  
    runTelemetryPage,
	}
  
end

--run
function runLua(hWin, Key)
  hPWin = hWin
  
  local result = 0
    
	if Key == 0 then
		result = 0
	elseif Key == 1 then     
    --result = runConfigPage(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(hPWin)
    end 
  else 
    
	end  
  
  drawTitle(hPWin, "GasSuit", page, #pages)
  
  pages[page](Key)
  
	--refreshNext()
  background()
  
	return result
 end
