unit FrontEndProps;

interface

uses
  Windows, Messages, SysUtils, Types, Classes, UITypes, Forms, Controls,
  Graphics, Generics.Defaults, Generics.Collections, ASObjects, ASPropMan,
  MainForm, TextEditor, ASKernelDefs;

type
  TFrontEndProperties = class(TMultiProcPropertyStore)
  strict protected
    function Maximized: TAlgosimObject;
    function Fullscreen: TAlgosimObject;
    function FormLeft: TAlgosimObject;
    function FormTop: TAlgosimObject;
    function FormWidth: TAlgosimObject;
    function FormHeight: TAlgosimObject;
    function Caption: TAlgosimObject;
    function Window: TAlgosimObject;
    function ExeName: TAlgosimObject;
    function ProcessID: TAlgosimObject;
    function StartTime: TAlgosimObject;
    function BuildTime: TAlgosimObject;
    function Version: TAlgosimObject;
    function Layout: TAlgosimObject;
    function Windows: TAlgosimObject;
    function ScriptDir: TAlgosimObject;
    function FECmdLine: TAlgosimObject;
  strict private
    FFrontEnd: TAlgosimMainForm;
    function GetFrontEnd: TAlgosimMainForm;
  protected
    property FrontEnd: TAlgosimMainForm read GetFrontEnd;
  public
    constructor Create; overload; override;
    constructor Create(AFrontEnd: TAlgosimMainForm); reintroduce; overload;
  end;

  TTextEditorProperties = class(TMultiProcPropertyStore)
  strict protected
    function Enabled: TAlgosimObject;
    function EditMode: TAlgosimObject;
    function ZoomLevel: TAlgosimObject;
    function Window: TAlgosimObject;
    function HiddenCharacters: TAlgosimObject;
    function CaretBeyondEOL: TAlgosimObject;
    function OverwriteMode: TAlgosimObject;
    function MultiCharSelect: TAlgosimObject;
    function AutoReplace: TAlgosimObject;
    function AutoIndent: TAlgosimObject;
    function LineHighlight: TAlgosimObject;
    function BracketHighlight: TAlgosimObject;
    function MultiSize: TAlgosimObject;
    function SelText: TAlgosimObject;
    function SelLength: TAlgosimObject;
    function SelStart: TAlgosimObject;
    function CaretPos: TAlgosimObject;
    function SelWord: TAlgosimObject;
    function SelURL: TAlgosimObject;
    function SelChar: TAlgosimObject;
    function Text: TAlgosimObject;
    function TextLength: TAlgosimObject;
    function LineCount: TAlgosimObject;
    function CharCount: TAlgosimObject;
    function IndentSize: TAlgosimObject;
    function FormattingProcessor: TAlgosimObject;
    function FileName: TAlgosimObject;
    function FileModified: TAlgosimObject;
    function AutoReplaceList: TAlgosimObject;
    function MathInputMode: TAlgosimObject;
    function FontName: TAlgosimObject;
    function EditorClass: TAlgosimObject;
  strict private
    FEditor: TTextEditor;
    function GetEditor: TTextEditor;
  protected
    property Editor: TTextEditor read GetEditor;
  public
    constructor Create; overload; override;
    constructor Create(AConsole: TTextEditor); reintroduce; overload;
  end;

function FormTypeStr(AForm: TCustomForm): string;
function GetFrontEndVersion: TVersionData;

implementation

uses
  Math, StrUtils, DateUtils, ASStructs, DocEd, DocSrc, Gallery,
  ClientVisuals, IOUtils, ASConsole;

function FormTypeStr(AForm: TCustomForm): string;
begin
  Result := 'form';
end;

function GetFrontEndVersion: TVersionData;
var
  len, dummy: Cardinal;
  verdata: Pointer;
  verstruct: Pointer;
begin
  FillChar(Result, SizeOf(Result), 0);
  len := GetFileVersionInfoSize(PWideChar(Application.ExeName), dummy);
  if len = 0 then
    Exit;
  GetMem(verdata, len);
  try
    if not GetFileVersionInfo(PWideChar(Application.ExeName), 0, len, verdata) then
      Exit;
    if not VerQueryValue(verdata, '\', verstruct, dummy) then
      Exit;
    Result.Major := HiWord(TVSFixedFileInfo(verstruct^).dwFileVersionMS);
    Result.Minor := LoWord(TVSFixedFileInfo(verstruct^).dwFileVersionMS);
    Result.Release := HiWord(TVSFixedFileInfo(verstruct^).dwFileVersionLS);
    Result.Build := LoWord(TVSFixedFileInfo(verstruct^).dwFileVersionLS);
  finally
    FreeMem(verdata);
  end;
end;

{ TFrontEndProperties }

constructor TFrontEndProperties.Create;
begin
  inherited;
  FName := 'FrontEnd';
  AddValue('maximized', Maximized);
  AddValue('fullscreen', Fullscreen);
  AddValue('FormLeft', FormLeft);
  AddValue('FormTop', FormTop);
  AddValue('FormWidth', FormWidth);
  AddValue('FormHeight', FormHeight);
  AddValue('caption', Caption);
  AddValue('window', Window);
  AddValue('ExeName', ExeName);
  AddValue('PID', ProcessID);
  AddValue('StartTime', StartTime);
  AddValue('BuildTime', BuildTime);
  AddValue('version', Version);
  AddValue('layout', Layout);
  AddValue('windows', Windows);
  AddValue('ScriptDir', ScriptDir);
  AddValue('CmdLine', FECmdLine);
end;

function TFrontEndProperties.FECmdLine: TAlgosimObject;
begin
  Result := ASO(System.CmdLine);
end;

function TFrontEndProperties.BuildTime: TAlgosimObject;
begin
  Result := ASODateTime(ASKernelDefs.LinkerTimestamp);
end;

function TFrontEndProperties.Caption: TAlgosimObject;
begin
  Result := ASO(FrontEnd.Caption);
end;

constructor TFrontEndProperties.Create(AFrontEnd: TAlgosimMainForm);
begin
  Create;
  FFrontEnd := AFrontEnd;
  if not TConsoleForm.ConsolePropStoresOwnershipTransferred then
    AddSubstore(TConsoleForm.ConsolePropStoresOwnership, 'consoles');
  AddSubstore(TTextEditorProperties.Create(TTextEditor.Create(AFrontEnd)), 'console');
end;

function TFrontEndProperties.ExeName: TAlgosimObject;
begin
  Result := ASO(Application.ExeName);
end;

function TFrontEndProperties.FormHeight: TAlgosimObject;
begin
  Result := ASOInt(FrontEnd.Height);
end;

function TFrontEndProperties.FormLeft: TAlgosimObject;
begin
  Result := ASOInt(FrontEnd.Left);
end;

function TFrontEndProperties.FormTop: TAlgosimObject;
begin
  Result := ASOInt(FrontEnd.Top);
end;

function TFrontEndProperties.FormWidth: TAlgosimObject;
begin
  Result := ASOInt(FrontEnd.Width);
end;

function TFrontEndProperties.Fullscreen: TAlgosimObject;
begin
  Result := ASO(
    (FrontEnd.BorderStyle = bsNone) and
    (FrontEnd.BoundsRect = Screen.MonitorFromWindow(AlgosimMainForm.Handle, mdNearest).BoundsRect)
  );
end;

function TFrontEndProperties.GetFrontEnd: TAlgosimMainForm;
resourcestring
  SNoFrontEnd = 'No front end assigned.';
begin
  if Assigned(FFrontEnd) then
    Result := FFrontEnd
  else
    raise Exception.Create(SNoFrontEnd);
end;

function TFrontEndProperties.Layout: TAlgosimObject;
begin
  Result := ASO(null);
end;

function TFrontEndProperties.Maximized: TAlgosimObject;
begin
  Result := ASO(FrontEnd.WindowState = wsMaximized);
end;

function TFrontEndProperties.ProcessID: TAlgosimObject;
begin
  Result := ASOInt(GetCurrentProcessId);
end;

function TFrontEndProperties.ScriptDir: TAlgosimObject;
begin
  Result := ASO(FrontEnd.StoragePath);
end;

function TFrontEndProperties.StartTime: TAlgosimObject;
var
  ct, et, kt, ut: TFileTime;
  SystemTime: TSystemTime;
begin
  if not GetProcessTimes(GetCurrentProcess, ct, et, kt, ut) then
    Exit(ASO(null));
  if not FileTimeToSystemTime(ct, SystemTime) then
    Exit(ASO(null));
  Result := ASODateTime(TTimeZone.Local.ToLocalTime(SystemTimeToDateTime(SystemTime)));
end;

function TFrontEndProperties.Version: TAlgosimObject;
begin
  Result := ASOVersionData(GetFrontEndVersion);
end;

function TFrontEndProperties.Window: TAlgosimObject;
begin
  Result := ASOInt(FrontEnd.Handle, 16);
end;

function TFrontEndProperties.Windows: TAlgosimObject;
var
  i: Integer;
  frm: TForm;
begin
  Result := TAlgosimArray.Create;
  try
    for i := 0 to Screen.FormCount - 1 do
    begin
      frm := Screen.Forms[i];
      Result.AddElement(
        TAlgosimStructure.CreateWithValue(
          [
            sm('caption', ASO(frm.Caption)),
            sm('type', ASO(FormTypeStr(frm)))
          ]
        )
      )
    end;
  except
    Result.Free;
    raise;
  end;
end;

{ TTextEditorProperties }

constructor TTextEditorProperties.Create;
begin
  inherited;
  FName := 'editor';
  AddValue('enabled', Enabled);
  AddValue('EditMode', EditMode);
  AddValue('window', Window);
  AddValue('zoom', ZoomLevel);
  AddValue('overwrite', OverwriteMode);
  AddValue('CaretBeyondEOL', CaretBeyondEOL);
  AddValue('ShowHiddenCharacters', HiddenCharacters);
  AddValue('MultiCharSelect', MultiCharSelect);
  AddValue('AutoReplace', AutoReplace);
  AddValue('AutoIndent', AutoIndent);
  AddValue('LineHighlight', LineHighlight);
  AddValue('BracketHighlight', BracketHighlight);
  AddValue('MultiSize', MultiSize);
  AddValue('SelText', SelText);
  AddValue('SelLength', SelLength);
  AddValue('SelStart', SelStart);
  AddValue('CaretPos', CaretPos);
  AddValue('SelWord', SelWord);
  AddValue('SelURL', SelURL);
  AddValue('SelChar', SelChar);
  AddValue('text', Text);
  AddValue('TextLength', TextLength);
  AddValue('LineCount', LineCount);
  AddValue('CharCount', CharCount);
  AddValue('IndentSize', IndentSize);
  AddValue('FormattingProcessor', FormattingProcessor);
  AddValue('FileName', FileName);
  AddValue('FileModified', FileModified);
  AddValue('AutoReplaceList', AutoReplaceList);
  AddValue('MathInputMode', MathInputMode);
  AddValue('font', FontName);
end;

function TTextEditorProperties.AutoIndent: TAlgosimObject;
begin
  Result := ASO(Editor.AutoIndent);
end;

function TTextEditorProperties.AutoReplace: TAlgosimObject;
begin
  Result := ASO(Editor.AutoReplace);
end;

function TTextEditorProperties.AutoReplaceList: TAlgosimObject;
var
  L: TAlgosimArray;
  i: Integer;
begin
  L := TAlgosimArray.Create;
  try
    L.Capacity := Editor.TextFile.AutoReplaceItemCount;
    for i := 0 to Editor.TextFile.AutoReplaceItemCount - 1 do
      L.Add(TAlgosimStructure.CreateWithValue([
        sm('token', ASO(Editor.TextFile.AutoReplaceItems[i].Token)),
        sm('value', ASO(Editor.TextFile.AutoReplaceItems[i].ReplacedValue))
      ]))
  except
    L.Free;
    raise;
  end;
  Result := L;
end;

function TTextEditorProperties.BracketHighlight: TAlgosimObject;
begin
  Result := ASO(Editor.MatchBrackets);
end;

function TTextEditorProperties.CaretBeyondEOL: TAlgosimObject;
begin
  Result := ASO(Editor.CaretAfterEOL);
end;

function TTextEditorProperties.CaretPos: TAlgosimObject;
begin
  with Editor.CaretPos do
    Result := ASOIntPoint(X + 1, Y + 1);
end;

function TTextEditorProperties.CharCount: TAlgosimObject;
begin
  Result := ASOInt(Editor.TextFile.NumCharacters);
end;

constructor TTextEditorProperties.Create(AConsole: TTextEditor);
begin
  Create;
  FEditor := AConsole;
end;

function TTextEditorProperties.EditMode: TAlgosimObject;
begin
  Result := ASOInt(Ord(Editor.EditMode));
end;

function TTextEditorProperties.EditorClass: TAlgosimObject;
begin
  Result := ASO(Editor.ClassName);
end;

function TTextEditorProperties.Enabled: TAlgosimObject;
begin
  Result := ASO(Editor.Enabled);
end;

function TTextEditorProperties.FileModified: TAlgosimObject;
begin
  Result := ASO(Editor.TextFile.FileModified);
end;

function TTextEditorProperties.FileName: TAlgosimObject;
begin
  Result := ASO(Editor.TextFile.FileName);
end;

function TTextEditorProperties.FontName: TAlgosimObject;
begin
  Result := ASO(Editor.Font.Name);
end;

function TTextEditorProperties.FormattingProcessor: TAlgosimObject;
begin
  if Assigned(Editor.FormattingProcessor) then
    Result := ASO(Editor.FormattingProcessor.ClassName)
  else
    Result := ASO(null);
end;

function TTextEditorProperties.GetEditor: TTextEditor;
resourcestring
  SNoEditor = 'No editor assigned.';
begin
  if Assigned(FEditor) then
    Result := FEditor
  else
    raise Exception.Create(SNoEditor);
end;

function TTextEditorProperties.HiddenCharacters: TAlgosimObject;
begin
  Result := ASO(Editor.ShowHiddenCharacters);
end;

function TTextEditorProperties.IndentSize: TAlgosimObject;
begin
  Result := ASOInt(Editor.IndentSize);
end;

function TTextEditorProperties.LineCount: TAlgosimObject;
begin
  Result := ASOInt(Editor.LineCount);
end;

function TTextEditorProperties.LineHighlight: TAlgosimObject;
begin
  Result := ASO(Editor.LineHighlight);
end;

function TTextEditorProperties.MathInputMode: TAlgosimObject;
begin
  Result := ASO((Editor is TASEditor) and TASEditor(Editor).MathInputMode);
end;

function TTextEditorProperties.MultiCharSelect: TAlgosimObject;
begin
  Result := ASO(Editor.MultiCharSelect);
end;

function TTextEditorProperties.MultiSize: TAlgosimObject;
begin
  Result := ASO(Editor.MultiSize);
end;

function TTextEditorProperties.OverwriteMode: TAlgosimObject;
begin
  Result := ASO(Editor.Overwrite);
end;

function TTextEditorProperties.SelChar: TAlgosimObject;
begin
  Result := ASO(Editor.GetCharAtCaret);
end;

function TTextEditorProperties.SelLength: TAlgosimObject;
begin
  Result := ASOInt(Editor.SelLength);
end;

function TTextEditorProperties.SelStart: TAlgosimObject;
begin
  Result := ASOInt(Editor.SelStart + 1);
end;

function TTextEditorProperties.SelText: TAlgosimObject;
begin
  Result := ASO(Editor.SelText);
end;

function TTextEditorProperties.SelURL: TAlgosimObject;
var
  URL: string;
begin
  if Editor.GetURLAtCaret(URL) then
    Result := ASO(URL)
  else
    Result := ASO(null);
end;

function TTextEditorProperties.SelWord: TAlgosimObject;
begin
  Result := ASO(Editor.GetWord);
end;

function TTextEditorProperties.Text: TAlgosimObject;
begin
  Result := ASO(Editor.PlainText);
end;

function TTextEditorProperties.TextLength: TAlgosimObject;
begin
  Result := ASOInt(Editor.TextFile.VirtualTextLength);
end;

function TTextEditorProperties.Window: TAlgosimObject;
begin
  Result := ASOInt(Editor.Handle, 16);
end;

function TTextEditorProperties.ZoomLevel: TAlgosimObject;
begin
  Result := ASOInt(Editor.Zoom);
end;

end.
