require "luamodules.strict"

_platform = nil
_compiler = nil

platform = nil

function detectPlatform()
  if _platform and _compiler then return _platform, _compiler end
  if rawget(_G, "SCAPE_PLATFORM") then
    local platformNames = {
      SCAPE_WIN32 = "windows",
      SCAPE_LINUX = "linux",
      SCAPE_MACOS = "macosx"
    }
    _platform = platformNames[SCAPE_PLATFORM]
  end  
  if rawget(_G, "SCAPE_COMPILER") then
    local compilerNames = {
      SCAPE_MSVC = "vs2008",
      SCAPE_GCC = "gmake"
    }
    _compiler = compilerNames[SCAPE_COMPILER]
  end
  if _platform and _compiler then return _platform, _compiler end

  local platform = os.getenv("OS")
  if platform == "Windows_NT" or os.getenv("WINDIR") then
    -- must be windows
    _platform, _compiler = "windows", "vs2008"
  else
    local scapeBinDir = os.getenv("SCAPE_BIN_DIR")
    if scapeBinDir then
      if string.find(scapeBinDir, "linux") then
        _platform, _compiler = "linux", "gmake"
      elseif string.find(scapeBinDir, "macosx") then
        _platform, _compiler = "macosx", "gmake"
      end
    end
    if not _platform then
      -- last resort: try to distinguish between Linux and MacOS by $HOME
      local home = os.getenv("HOME")
      if not home then
        error "Unable to detect platform: uname failed and SCAPE_BIN_DIR is not set!"
      elseif string.sub(home, 0, 6) == "/Users" then
        _platform, _compiler = "macosx", "gmake"
      else
        _platform, _compiler = "linux", "gmake"
      end      
    end
  end
  return _platform, _compiler
end

function getScapeBinDir(build)
  local executablePath = rawget(_G, "SCAPE_EXECUTABLE_PATH")
  if executablePath then
    local path = executablePath:gsub("\\", "/")
    local pos = path:reverse():find("/")
    if pos then path = path:sub(1, path:len()-pos) end
    return path
  end

  if not build then build = "debug" end

  local scapeBinDirEnv = "SCAPE_BIN_DIR"
  local scapeBinDir = os.getenv(scapeBinDirEnv)
  if scapeBinDir then
    return scapeBinDir
  end
  
  local scapeOutputDirEnv = "SCAPE_OUTPUT_DIR"
  local scapeOutputDir = os.getenv(scapeOutputDirEnv)
  if not scapeOutputDir then
    local scapeDirEnv = "SCAPE_DIR"
    local scapeDir = os.getenv(scapeDirEnv)
    if scapeDir then
      scapeOutputDir = scapeDir
    else
      scapeOutputDir = "../.."
    end
  end

  local platform, compiler = detectPlatform()
  local result = pcall(require, "scape")
  if result then
    if scape.system.Platform.instance():isDebugBuild() then
      build = "debug"
    else
      build = "release"
    end
  end
  return scapeOutputDir .. "/bin/" .. platform .. "/" .. compiler .. "/" .. build
end

function getLibraryExtension()
  local platform = detectPlatform()
  if platform == "linux" then
    return "so"
  elseif platform == "macosx" then
    return "dylib"
  elseif platform == "windows" then
    return "dll"
  else
    error("Unknown platform!")
  end
end

function getScapeLibraryFilename(libraryName)
  local platform = detectPlatform()
  local extension = "."..getLibraryExtension()
  if platform == "linux" or platform == "macosx" then
    return "libscape_"..libraryName..extension
  elseif platform == "windows" then
    return "scape_"..libraryName..extension
  else
    error "Unknown platform!"
  end
end
  
function getModuleFilename(moduleName)
  local platform = detectPlatform()
  local extension = "."..getLibraryExtension()
  if platform == "linux" or platform == "macosx" then
    return "libmod_"..moduleName..extension
  elseif platform == "windows" then
    return "mod_"..moduleName..extension
  else
    error "Unknown platform!"
  end
end

function getScapeModulePath()
  local moduleFilename = getModuleFilename("lua")
  return getScapeBinDir().."/"..moduleFilename
end

function loadModules()
  if not rawget(_G, "scape") then require "scape" end
  local moduleRegistry = scape.system.Platform.instance().moduleRegistry
  moduleRegistry:registerModuleDirectory(getScapeBinDir())
  moduleRegistry:loadModules()
end

function findLibrary(filename)
  local assetManager = scape.io.AssetManager.instance()
  return assetManager:findFile(filename)
end

-- Attempts to load the library of the given name
function loadLibrary(filename)
  if not rawget(_G, "scape") then require "scape" end
  local success, path = pcall(findLibrary, filename)
  if not success or path == "" then path = getScapeBinDir().."/"..filename end
  local platform = scape.system.Platform.instance()
  if not platform:loadLibrary(path) then
    error("Library '"..filename.."' could not be loaded!")
  end
end

function loadModule(name)
  if rawget(_G, "SCAPE_STATIC") and SCAPE_STATIC then return end 
  loadLibrary(getModuleFilename(name))
end

function loadScapeLibrary(name)
  if rawget(_G, "SCAPE_STATIC") and SCAPE_STATIC then return end 
  loadLibrary(getScapeLibraryFilename(name))
end

function loadReflectors(name)

end

system = {
  loadModule = loadModule
}
