unit uDirSync;
{$INCLUDE 'DirSync3.inc'}

interface

uses
  Windows, SysUtils, Classes,
  {$IFDEF FAR3} Plugin3, {$ELSE} PluginW, {$ENDIF} FarKeysW, FarColor,
  uSynchronizeDirectories, uLog, uFAR;

procedure SetStartupInfoW(const Info: TPluginStartupInfo); stdcall;
procedure ExitFARW( {$IFDEF FAR3_UP} const Info: TExitInfo {$ENDIF} ); stdcall;
{$IFDEF FAR3_UP}
procedure GetGlobalInfoW(var Info: TGlobalInfo); stdcall;
function OpenW(var Info: TOpenInfo): THandle; stdcall;
{$ELSE}
function OpenPluginW(OpenFrom: integer; Item: integer): THandle; stdcall;
{$ENDIF}
procedure GetPluginInfoW(var Info: TPluginInfo); stdcall;
function ProcessEditorEventW( {$IFDEF FAR3_UP} const Info: TProcessEditorEventInfo {$ELSE} Event: integer; Param: Pointer {$ENDIF} ): TIntPtr; stdcall;
function ProcessEditorInputW( {$IFDEF FAR3_UP} const Info: TProcessEditorInputInfo {$ELSE} Info: PInputRecord {$ENDIF} ): TIntPtr; stdcall;
function ConfigureW( {$IFDEF FAR3_UP} var Info: TConfigureInfo {$ELSE} ItemNumber: integer {$ENDIF} ): TIntPtr; stdcall;

implementation

uses
  uSystem, uDirSyncConsts, uMessages, uDiscoverDifferences,
  uOptions, uOptionsDialog, uEditorTasks;

const
  PLUGIN_TITLE = 'DirSync3';
  PLUGIN_DESCRIPTION = 'Synchronize directories';
  PLUGIN_AUTHOR = 'Pepak, http://www.pepak.net';

procedure SetStartupInfoW(const Info: TPluginStartupInfo);
begin
  FarApi := Info;
  FSF := Info.FSF^;
  FarApi.FSF := @FSF;
end;

procedure ExitFARW( {$IFDEF FAR3_UP} const Info: TExitInfo {$ENDIF} );
begin
end;

{$IFDEF FAR3_UP}
procedure GetGlobalInfoW(var Info: TGlobalInfo);
var
  FN: string;
  VerHigh, VerLow, VerBuild: LongWord;
begin
  FillChar(Info, Sizeof(Info), 0);
  Info.StructSize := Sizeof(Info);
  Info.MinFarVersion := MakeFarVersion( {$IFDEF FAR3_UP} 3, 0, 0, 0, 0 {$ELSE} 2, 0, 1807 {$ENDIF} );
  FN := GetModuleName(HInstance);
  if GetFileVersion(FN, VerHigh, VerLow, VerBuild) then
    Info.Version := MakeFarVersion( {$IFDEF FAR3_UP} VerHigh, VerLow, 0, VerBuild, 0 {$ELSE} VerHigh, VerLow, VerBuild {$ENDIF} )
  else
    Info.Version := MakeFarVersion( {$IFDEF FAR3_UP} 0, 0, 0, 0, 0 {$ELSE} 0, 0 ,0 {$ENDIF} );
  Info.Guid := PLUGIN_GUID;
  Info.Title := PLUGIN_TITLE;
  Info.Description := PLUGIN_DESCRIPTION;
  Info.Author := PLUGIN_AUTHOR;
end;
{$ENDIF}

var
  PluginInfoInitialized: boolean = False;
  PanelMenuStrings:  array[0..0] of PFarChar;
  PanelMenuGUIDs:    array[0..0] of TGUID;
  ConfigMenuStrings: array[0..0] of PFarChar;
  ConfigMenuGUIDs:   array[0..0] of TGUID;

procedure GetPluginInfoW(var Info: TPluginInfo);
begin
  // Initialize messages and GUIDs
  if not PluginInfoInitialized then begin
    PanelMenuStrings[0] := GetMsg(MTitle);
    PanelMenuGUIDs[0] := MENU_PANEL_GUID;
    ConfigMenuStrings[0] := GetMsg(MTitle);
    ConfigMenuGUIDs[0] := MENU_CONFIG_GUID;
    PluginInfoInitialized := True;
  end;
  FillChar(Info, Sizeof(Info), 0);
  Info.StructSize := Sizeof(Info);
  Info.Flags := PF_EDITOR;
  {$IFDEF FAR3_UP}
  Info.PluginMenu.Count := Length(PanelMenuStrings);
  Info.PluginMenu.Strings := @PanelMenuStrings[0];
  Info.PluginMenu.Guids := @PanelMenuGUIDs[0];
  Info.PluginConfig.Count := Length(ConfigMenuStrings);
  Info.PluginConfig.Strings := @ConfigMenuStrings[0];
  Info.PluginConfig.Guids := @ConfigMenuGUIDs[0];
  {$ELSE}
  Info.PluginMenuStringsNumber := Length(PanelMenuStrings);
  Info.PluginMenuStrings := @PanelMenuStrings[0];
  Info.PluginConfigStringsNumber := Length(ConfigMenuStrings);
  Info.PluginConfigStrings := @ConfigMenuStrings[0];
  {$ENDIF}
end;

{$IFDEF FAR3_UP}
function OpenW(var Info: TOpenInfo): THandle;
{$ELSE}
function OpenPluginW(OpenFrom: integer; Item: integer): THandle;
{$ENDIF}
var
  Diff: TDiscoverDifferences;
  Edit: TEditorTasks;
begin
  if {$IFDEF FAR3_UP} Info.OpenFrom = OPEN_EDITOR {$ELSE} OpenFrom = OPEN_EDITOR {$ENDIF} then begin
    Edit := TEditorTasks.Create;
    try
      Edit.EditorID := -1; // active editor
      Result := Edit.Execute;
    finally
      FreeAndNil(Edit);
    end;
  end
  else begin
    Diff := TDiscoverDifferences.Create;
    try
      Result := Diff.Execute;
    finally
      FreeAndNil(Diff);
    end;
  end;
end;

function ProcessEditorEventW( {$IFDEF FAR3_UP} const Info: TProcessEditorEventInfo {$ELSE} Event: integer; Param: Pointer {$ENDIF} ): TIntPtr;
begin
  Result := 0;
  {$IFDEF FAR3_UP}
  if Info.StructSize >= Sizeof(Info) then
  {$ENDIF}
    TFarEditorManaged.ProcessEditorEvent( {$IFDEF FAR3_UP} Info.Event, Info.EditorID {$ELSE} Event, -1 {$ENDIF} , Result);
end;

function ProcessEditorInputW( {$IFDEF FAR3_UP} const Info: TProcessEditorInputInfo {$ELSE} Info: PInputRecord {$ENDIF} ): TIntPtr;

  function RunEditorTask(const EditorTask: TEditorTasks.TEditorTask): TIntPtr;
    var
      Tasks: TEditorTasks;
    begin
      //Log('Running editor task %d', [Integer(EditorTask)]);
      Tasks := TEditorTasks.Create;
      try
        Tasks.EditorID := -1;
        if Tasks.ExecuteTask(EditorTask) then begin
          Result := 1;
          TFarEditor.Refresh(-1);
          //Log('Running editor task %d -> success', [Integer(EditorTask)]);
        end
        else begin
          Result := 0;
          //Log('Running editor task %d -> failure', [Integer(EditorTask)]);
        end;
      finally
        FreeAndNil(Tasks);
      end;
    end;

var
  ShiftFlags: DWORD;
  P: PInputRecord;
begin
  Result := 0;
  {$IFDEF FAR3_UP}
  P := @Info.Rec;
  {$ELSE}
  P := Info;
  {$ENDIF}
  {$IFDEF FAR3_UP}
  if Info.StructSize >= Sizeof(Info) then
  {$ENDIF}
    if P^.EventType = KEY_EVENT then
      if P^.Event.KeyEvent.bKeyDown then begin
        ShiftFlags := P^.Event.KeyEvent.dwControlKeyState and (LEFT_ALT_PRESSED or LEFT_CTRL_PRESSED or RIGHT_ALT_PRESSED or RIGHT_CTRL_PRESSED or SHIFT_PRESSED);
        //Log('Editor input. Char=%d, VirtualKeyCode=%d, VirtualScanCode=%d, ShiftFlags = %x', [Ord(P^.Event.KeyEvent.UnicodeChar), P^.Event.KeyEvent.wVirtualKeyCode, P^.Event.KeyEvent.wVirtualScanCode, ShiftFlags]);
        if (ShiftFlags = LEFT_ALT_PRESSED) or (ShiftFlags = RIGHT_ALT_PRESSED) then begin
          if P^.Event.KeyEvent.wVirtualKeyCode = VK_F1 then
            Result := RunEditorTask(etCopyToLeft)
          else if P^.Event.KeyEvent.wVirtualKeyCode = VK_F2 then
            Result := RunEditorTask(etCopyToRight)
          else if P^.Event.KeyEvent.wVirtualKeyCode = VK_F3 then
            Result := RunEditorTask(etCompare)
          else if P^.Event.KeyEvent.wVirtualKeyCode = VK_F5 then
            Result := RunEditorTask(etFindNextToLeft)
          else if P^.Event.KeyEvent.wVirtualKeyCode = VK_F6 then
            Result := RunEditorTask(etFindNextToRight)
        end
        else if (ShiftFlags = LEFT_CTRL_PRESSED) or (ShiftFlags = RIGHT_CTRL_PRESSED) then begin
          if P^.Event.KeyEvent.wVirtualKeyCode = VK_F1 then
            Result := RunEditorTask(etEditLeft)
          else if P^.Event.KeyEvent.wVirtualKeyCode = VK_F2 then
            Result := RunEditorTask(etEditRight)
          else if P^.Event.KeyEvent.wVirtualKeyCode = VK_F3 then
            Result := RunEditorTask(etFileInfo)
        end
      end;
end;

function ConfigureW( {$IFDEF FAR3_UP} var Info: TConfigureInfo {$ELSE} ItemNumber: integer {$ENDIF} ): TIntPtr;
var
  Dlg: TOptionsDialog;
begin
  Result := 0;
  {$IFDEF FAR3_UP}
  if Info.StructSize >= Sizeof(Info) then begin
  {$ENDIF}
    //if Info.GUID^ = MENU_CONFIG_GUID then begin
      Dlg := TOptionsDialog.Create;
      try
        Dlg.Options := TDirSyncOptions.Create;
        try
          Dlg.Options.Load;
          if Dlg.Execute then
            Result := 1;
        finally
          Dlg.Options.Free;
          Dlg.Options := nil;
        end;
      finally
        FreeAndNil(Dlg);
      end;
    //end;
  {$IFDEF FAR3_UP}
  end;
  {$ENDIF}
end;


exports
  SetStartupInfoW,
  ExitFARW,
  {$IFDEF FAR3_UP}
  GetGlobalInfoW,
  OpenW,
  {$ELSE}
  OpenPluginW,
  {$ENDIF}
  GetPluginInfoW,
  ProcessEditorEventW,
  ProcessEditorInputW,
  ConfigureW;

initialization
  {$IFDEF FAR3_UP}
  uFar.PluginID := PLUGIN_GUID;
  {$ENDIF}

end.
