-- Should be lighter than V1

local Commands={}

-- Provided global vars

Global={["Key"]={}}
Global.Key.pressed=""
Global.Key.released=""
Global.Key.list={}
Global.Key.longlist={} -- For longpresses

function Commands.new(pmtlist)

  local devices={["keyboard"]={},["gamepad"]={},["touchscreen"]={},["mouse"]={}}
  local istouch,isgamepad,ismouse,iskeyboard=pmtlist.touchscreen or false,pmtlist.gamepad or true,pmtlist.mouse or false,pmtlist.keyboard or true
  local diagonals,longkeys,lists=pmtlist.diagonals or true,pmtlist.longkeys or true,pmtlist.lists or true -- Lists desactivate everything
  local state,timer=false,0
  
  function devices.modifyperms(newpmtlist)
  
    istouch,isgamepad=newpmtlist.touchscreen or istouch,newpmtlist.gamepad or isgamepad
    ismouse,iskeyboard=newpmtlist.mouse or ismouse,newpmtlist.keyboard or iskeyboard
    diagonals,longkeys,lists=newpmtlist.diagonals,newpmtlist.longkeys,newpmtlist.lists or lists
  
  end
  
  function devices.mapping(dv,method,arg)
  
    -- Add a key
  
    if method=="add" then
    
      if dv=="keyboard" then
      
        --[[ example : key={syml={"w","up"},cmd="up",locked=false,type="movement"}
        cmd is the real key, syml is the symslink, 
        locked if bindable, only for first key in index of cmd, other are locked
        cmd and syml should be one of those keys : https://love2d.org/wiki/Scancode 
        The primordial type is "movement", good for diagonals. 
        Structure of the key is different when added--]]
        
        for o=1,#arg.syml do

          devices.keyboard[arg.syml[o]]=arg
          
          if o>1 then
          
            devices.keyboard[arg.syml[o]].locked=true
          
          end
         
        end
        
        -- Call those keys with number index, e.g foo[x]
      
      elseif dv=="gamepad" then
      
      end
      
    -- Bind or swap a key, a table with the input and the target is awaited ({input="i",target="t"}) Still unchecked for bugs
      
    elseif method=="bind" then
    
      if dv=="keyboard" then
      
        local a,b
      
        for i in pairs(devices.keyboard) do
        
          if devices.keyboard[i].syml[1]==arg.input and devices.keyboard[i].locked then
          
            return -1
            
          elseif devices.keyboard[i].syml[1]==arg.target and devices.keyboard[i].locked then
          
            return -1
          
          end
          
          for o in pairs(devices.keyboard[i].syml) do
          
            -- You can't bind secondary keys
          
            if devices.keyboard[i].syml[o]==arg.input and o>1 then
            
              return -1
            
            elseif devices.keyboard[i].syml[o]==arg.input then
            
              a={i,o}
            
            elseif devices.keyboard[i].syml[o]==arg.target and o>1 then
            
              return -1
            
            elseif devices.keyboard[i].syml[o]==arg.target then
            
              b={i,o}
            
            end
        
          end
          
        end
          
        if a then

          if b then
            
            -- Swap keys
            
            devices.keyboard[a[1]].syml[a[2]],devices.keyboard[b[1]].syml[b[2]]=devices.keyboard[b[1]].syml[b[2]],devices.keyboard[a[1]].syml[a[2]]
            return 1
            
          end
            
          devices.keyboard[a[1]].syml[a[2]]=arg.target
          return 1
          
        end
          
        return -1
      
      elseif dv=="gamepad" then
      
      end
      
    -- Export mapping to a file, this time, arg is a string pointing to a file
    
    elseif method=="export" then
    
      if dv=="keyboard" then
    
        File.ectotoml(devices.keyboard,arg)
        
      elseif dv=="gamepad" then
      
      end
      
    -- Import the mapping of a file
    
    elseif method=="import" then
    
      if dv=="keyboard" then
         
        local a=File.dcfromtoml(arg)
        
        -- There can't be integers in toml. Therefore, they are all strings and needed to be converted
        
        for i in pairs(a) do
        
          for o in pairs(a[i]) do
          
            -- foo["x"] becomes foo[x]

            devices.keyboard[tonumber(i)]=a[i]
            
          end
          
        end
        
      elseif dv=="gamepad" then
      
      end
    
    end
  
  end
  
  -- Redirect to real key
  
  function devices.keylink(key)
  
    for i in pairs(devices.keyboard) do
    
      for o in pairs(devices.keyboard[i].syml) do

        if devices.keyboard[i].syml[o]==key then
        
          return devices.keyboard[i].cmd
        
        end
      
      end
    
    end
  
  end
  
  -- List all actives keys in lists
  
  function devices.list(listn) -- Has a complexity of O(n^2)
  
    Global.Key.list={}
    Global.Key.longlist={}
    
    local dict={"up","right","down","left","up"}
    local a,b={}
  
    for i in pairs(devices.keyboard) do
    
      for o in pairs(devices.keyboard[i].syml) do
      
        if love.keyboard.isScancodeDown(devices.keyboard[i].syml[o]) then
        
          if listn=="timed" then
          
            table.insert(Global.Key.longlist,devices.keyboard[i].cmd) 
          
          end
          
          if diagonals then
          
            if devices.keyboard[i].type=="movement" then
            
              table.insert(a,devices.keyboard[i].cmd)

              if #a<2 then
              
                b=a[1].."-"..a[1]
               
              else
              
                b=a[1].."-"..a[2]
              
              end
            
              for n=1,4 do
              
                if b==dict[n].."-"..dict[n+1] or b==dict[n+1].."-"..dict[n] then
                
                  table.insert(Global.Key.list,b)
                  table.remove(Global.Key.list,1)
                  
                  -- up-right, right-down, down-left or left-up
                  
                end
              
              end
              
              -- If it failed, normal moves
              
              table.insert(Global.Key.list,a[1])
            
            else
            
              table.insert(Global.Key.list,devices.keyboard[i].cmd)
            
            end
          
          else 
        
            table.insert(Global.Key.list,devices.keyboard[i].cmd)
            
          end
        
        end
      
      end
      
    end

  end
  
  function devices.detect(key,arg) -- O(n)
  
    if arg=="timed" then
    
      for i in pairs(Global.Key.list) do
      
        if key==Global.Key.longlist[i] then
        
          return true
        
        end
      
      end
      
      return false
    
    else
    
      for i in pairs(Global.Key.list) do
      
        if key==Global.Key.list[i] then
        
          return true
        
        end
      
      end
      
      return false
    
    end
  
  end
  
  function devices.update(dt)
  
    if iskeyboard then
    
      function love.keypressed(key,scancode)

        Global.Key.pressed=devices.keylink(scancode)
        state=true

      end

      function love.keyreleased(key,scancode)

        Global.Key.released=devices.keylink(scancode)
        state=false
        timer=0

      end
      
      if lists then
      
      -- To avoid workload for analyzing keyboard
    
        if Global.Key.pressed~="" or #Global.Key.list~=0 then

          devices.list()
      
          if state and longkeys then
        
            timer=timer+7.5*dt
     
            if timer>3 then
        
              devices.list("timed")
              timer=0
            
            end
        
          end
        
        end
      
      end
    
    end
    
    Global.Key.pressed,Global.Key.released="",""
  
  end
  
  return devices
  
end

return Commands
