{
    This file is part of Chentrah,
    Copyright (C) 2004-2010 Anton Rzheshevski (chebmaster@mail.ru).

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see http://www.gnu.org/licenses/

 **********************************************************************}

{
    Note: the rollback is irreversible. Any "Redo" functions in the editors
    are implemented by repeating the chain of input commands (as the world
    state should be 100% reproducible)

}


  {$include mo_globaldefs.h}
  {$typeinfo on}

unit mo_rollback;

interface
  uses mo_hub, typinfo, chepersy;

  const
    CPS_ROLLBACK_COPY_MASK_BIT = 29; //this is a backup copy of an object
    CPS_ROLLBACK_COPY_MASK = $20000000;
    CPS_ROLLBACK_COPY_JUST_LOADED_MASK_BIT = 28; //this backup copy was loaded without calling AfterLoading
    CPS_ROLLBACK_COPY_JUST_LOADED_MASK = $10000000;


  Type
    TTick = longint; //could be seamlessly upgraded to int64;
(*
    TAbstractWorld = class;

    TUndoableObject = class (TManagedObject)
    strict protected
      World: TAbstractWorld;
      Next, Previous: TUndoableObject;
      f_LastChanged: TTick;
    public
      procedure RegisterFields; override;
      procedure SetChanged();
      procedure Scrape; override;
      constructor Create(ParentWorld: TAbstractWorld);

      property LastChanged: TTick read f_LastChanged;
    end;

    TUndoableObjectArray = array of TUndoableObject;

    TAbstractWorldCommand = class(TManagedObject)
    public
      Tick: TTick;
      Next: TAbstractWorldCommand;
      procedure Execute(World: TAbstractWorld); virtual; abstract;
      procedure ExecuteChain(World: TAbstractWorld);
      procedure RegisterFields; override;
      procedure AddCommand(c: TAbstractWorldCommand);
      procedure Scrape; override;
    end;

    TUndoableWorldState = record
      ObjectChain: TUndoableObject;
      CommandChain: TAbstractWorldCommand;
    end;

    TRestorePoint = class (TManagedObject)
    public
      Tick: TTick;
      Next: TRestorePoint;
      WorldState: TUndoableWorldState;
      Originals,
      Copies: TUndoableObjectArray;
      procedure RegisterFields; override;
    end;

    { TAbstractWorld }

    TAbstractWorld = class (TManagedObject)
    protected
      f_tick: TTick;
      f_state: TUndoableWorldState;
    public
      RestoreChain: TRestorePoint;
      procedure RegisterFields; override;
      procedure CollapseRestorePoint(for_tick: TTick);
      procedure CreateRestorePoint; //always for the current tick
      procedure AdvanceTick;
      procedure RollBack(for_tick: TTick);

      property ObjectChain: TUndoableObject read f_state.ObjectChain write f_state.ObjectChain;
      property Tick: TTick read f_tick;
    end;
  *)

implementation



(*

{ TUndoableObject }

procedure TUndoableObject.RegisterFields;
begin
  inherited RegisterFields;
  ListFields([
    'World',@World,typeinfo(TAbstractWorld),
    'Next',@Next,
    'Previous',@Previous,typeinfo(TUndoableObject),
    'LastChanged',@f_LastChanged,typeinfo(TTick)
  ]);
end;

procedure TUndoableObject.SetChanged();
begin
  if World.Tick = LastChanged then exit;
  f_LastChanged:= World.Tick;

  //move itself to the top of the chain
  if Assigned(Next) then begin Next.Previous:= Previous; Next.SetChanged() end;
  if Assigned(Previous) then begin Previous.Next:= Next; Previous.SetChanged(); end;
  Next:= World.ObjectChain;
  if Assigned(Next) then begin Next.Previous:= Self; Next.SetChanged; end;
  Previous:= NIL;
  World.ObjectChain:= Self;
end;

procedure TUndoableObject.Scrape;
begin
  //remove itself from the chain
  if Assigned(Next) then begin Next.Previous:= Previous; Next.SetChanged() end;
  if Assigned(Previous) then begin Previous.Next:= Next; Previous.SetChanged(); end;
  if Self = World.ObjectChain then World.ObjectChain:= Next;
  inherited Scrape;
end;

{ TAbstractWorldCommand }

procedure TAbstractWorldCommand.ExecuteChain(World: TAbstractWorld);
begin
  Execute(World);
  if Assigned(Next) then Next.ExecuteChain(World);
end;

procedure TAbstractWorldCommand.RegisterFields;
begin
  inherited;
  ListFields([
    'Tick',@Tick,typeinfo(TTick),
    'Next',@Next,typeinfo(TAbstractWorldCommand)]);
end;

procedure TAbstractWorldCommand.AddCommand(c: TAbstractWorldCommand);
begin
  if Assigned(Next) then Next.AddCommand(c) else Next:=c;
end;

procedure TAbstractWorldCommand.Scrape;
begin
  if Assigned(Next) then Next.Scrape;
  inherited Scrape;
end;

{ TAbstractWorld }

procedure TAbstractWorld.RegisterFields;
begin
  inherited RegisterFields;
end;

procedure TAbstractWorld.CollapseRestorePoint(for_tick: TTick);
begin

end;

procedure TAbstractWorld.CreateRestorePoint;
begin

end;

procedure TAbstractWorld.AdvanceTick;
begin

end;

procedure TAbstractWorld.RollBack(for_tick: TTick);
begin

end;
*)

end.
