(*******************************************************************************
	Elysion Thorium Kronos App
*******************************************************************************)
program elysionkronosapp;

{$mode objfpc}{$H+}

{.$define use_horde3d}

uses
  Classes, 
  SysUtils, 
  Thorium, 
  ThoriumLibStd, 
  ThoriumLibStdIO, 
  ThoriumElysionKronos,
  {$ifdef use_horde3d}
  ThoriumHorde3D,
  {$endif}
  ElysionKronos;

// Default init values
const
  WIDTH = 800;
  HEIGHT = 480;
  BITS = 16;
  FULLSCREEN = false;
  
var
  Engine: TThorium;
  Module: TThoriumModule;
  ScriptName: String;

function RenameExecFile(Extension: String): String;
var
  LongFilename, ResultFilename: String;
begin
  LongFilename := ExtractFileName(ParamStr(0));

  if Pos('.', LongFilename) <> 0 then
    ResultFilename := Copy(LongFilename, 0, Pos('.', LongFilename) - 1)
  else
    ResultFilename := LongFilename;

  Result := ResultFilename + '.' + Extension;
end;

function LoadConfigFile(): Boolean;

  procedure InitConfigApp(Filename: String);
  var
    ConfigFile: TStringList;
    _Width, _Height, _Bits: Integer;
    _Fullscreen: Boolean;
  begin
    ConfigFile := TStringList.Create;
    ConfigFile.LoadFromFile(Filename);
	
    _Width := StrToIntDef(ConfigFile.Strings[0], WIDTH);
    _Height := StrToIntDef(ConfigFile.Strings[1], HEIGHT);
    _Bits := StrToIntDef(ConfigFile.Strings[2], BITS);
    _Fullscreen := StrToBoolDef(ConfigFile.Strings[3], FULLSCREEN);
	
    ConfigFile.Free;
	
    Application.Initialize(_Width, _Height, _Bits, _Fullscreen);
  end;
  
  function GetConfigFilename(): String;
  begin
    Result := RenameExecFile('cfg');
  end;

begin
  Result := false;

  if FileExists(GetConfigFilename()) then 
  begin
    InitConfigApp(GetConfigFilename());
    Result := true;
  end else begin
    if FileExists('config.cfg') then
    begin
      InitConfigApp('config.cfg');
      Result := true;
    end;
  end;
end;  

function LoadScript(): Boolean;
begin
  Result := false;

  if ParamStr(1) <> '' then
  begin
    ScriptName := ParamStr(1);
    Result := true;
  end else
  begin
    if FileExists(RenameExecFile('tss')) then
    begin
      ScriptName := RenameExecFile('tss');
      Result := true;
    end else
    begin
      if FileExists('main.tss') then
      begin
        ScriptName := 'main.tss';
        Result := true;
      end;
    end;
  end;
end;
  
begin
  // Check for script
  if not LoadScript then raise Exception.Create('No script file specified.');

  // Create a thorium context
  Engine := TThorium.Create;
  
  // Check for config files
  if not LoadConfigFile then Application.Initialize(WIDTH, HEIGHT, BITS, FULLSCREEN);
  
  try
    // Load the standard libraries
    Engine.LoadLibrary(TThoriumLibStd);
    Engine.LoadLibrary(TThoriumLibStdIO);
    // Load custom library
    Engine.LoadLibrary(TLibElysionKronos);
	
	{$ifdef use_horde3d}
	Engine.LoadLibrary(TLibHorde3D);
	{$endif}
	
    // Load the script
    Module := Engine.LoadModuleFromFile(ScriptName);
    //Module.Dump();
    //Halt(0);
    // No need for a try-finally section since the module will be freed by the
    // engine afterwards.
    // Initialize the virtual machine.
    Engine.InitializeVirtualMachine;

    // Execute the function main without any parameters
    Module.FindPublicFunction('INITIALIZE').SafeCall([]);

    while Application.Run do
    begin
      ActiveWindow.BeginScene;

      Module.FindPublicFunction('RENDER').SafeCall([]);
      Module.FindPublicFunction('UPDATE').SafeCall([ThoriumCreateFloatValue(ActiveWindow.DeltaTime)]);

      ActiveWindow.EndScene;
    end;
  finally
    // This can be called even if the vm has not been initialized yet.
    Engine.ReleaseVirtualMachine;
    Engine.Free;
  end;
end.

