unit marks;

interface
uses interfaces;

type
  // TODO maybe just represent this as an integer "size" of the character.
  TTextMarkAffinity = (afBeginning, afEnd, afAnchoredToNextCharacter); // afAnchoredToNextCharacter: means "delete mark once the character to the right of the mark is deleted" (for paragraph marks etc).

  TTextMarkPositionChanged = procedure(Sender : TObject) of object;
  ITextMark = interface(ICloneable)
    ['{774226dc-b31a-11dd-bfbc-2dc1e748ab45}']

    { TODO name? }
    { TODO reconstructable marks: marks which can reconstruct their "Position" by asking them (and looking in the buffer itself)? }
    function GetPosition : Cardinal;
    procedure SetPosition(value : Cardinal);
    function GetAffinity : TTextMarkAffinity;
    procedure SetAffinity(value : TTextMarkAffinity);

    {
      "Position" does not change as long as the data in the text blocks (fBeginning, fGapStart) and (fGapEnd, fBufferSize) does not move.
      "Position" does change as soon as the data in the text blocks (fBeginning, fGapStart) and (fGapEnd, fBufferSize) does move.
    }
    property Position : Cardinal read GetPosition write SetPosition; // non-gap-aware so doesn't change continuously.
    property Affinity : TTextMarkAffinity read GetAffinity write SetAffinity;
    function GetPositionChanged : TTextMarkPositionChanged;
    procedure SetPositionChanged(value : TTextMarkPositionChanged);
    
    // TODO use proper Observer pattern?
    property PositionChanged : TTextMarkPositionChanged read GetPositionChanged write SetPositionChanged;
  end;
  
  TTextBufferAction = (baInsert, baDelete, baModifyInplace);
  TTextBufferModified = procedure(Sender : TObject; aAction : TTextBufferAction; aPosition : Cardinal; aCount : Cardinal; aValue : PChar) of object;

  IModificationMonitorTextMark = interface(ITextMark)
    ['{5c0a6d70-b31f-11dd-9817-812a53b91110}']

    { callback based. If you want to signal that something has been modified, call Modified(Self, baInsert, ...). }
    function GetModified : TTextBufferModified;
    procedure SetModified(aCallback : TTextBufferModified);
    property Modified : TTextBufferModified read GetModified write SetModified; 

    { "Owner" is there in order for the buffer to know when it's done notifying all the interested views. 
      The buffer will usually contain ViewModificationMarks of multiple views. 
      However, the only ViewModificationMark per view that should be notified of a modification is the mark that is to the left of the modification point and closest. }
    function GetOwner : Pointer{TTextView};
    property Owner : Pointer{TTextView} read GetOwner;
  end;

  { These are marks that aren't used that often and so can have a position that is wrong for some time.  
    When the position is needed, it will first check whether it's still current and if not, call "Recover" to make it recover its own Position. 
    
    Example uses: paragraph marks, breakpoints?, ... everything that can be backtracked using the buffer if shit hits the fan. }
  IReconstructableTextMark = interface(ITextMark)
    procedure Recover;
  end;

  
implementation

end.