// Scintilla source code edit control
/** @file CellBuffer.h
 ** Manages the text of the document.
 **/
// Copyright 1998-2004 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#ifndef CELLBUFFER_H
#define CELLBUFFER_H

#ifdef SCI_NAMESPACE
namespace Scintilla {
#endif

// Interface to per-line data that wants to see each line insertion and deletion
class PerLine {
public:
    virtual ~PerLine() {}
    virtual void Init()=0;
    virtual void InsertLine(int)=0;
    virtual void RemoveLine(int)=0;
};

/**
 * The line vector contains information about each of the lines in a cell buffer.
 */
class LineVector {

    Partitioning starts;
    PerLine *perLine;

public:

    LineVector();
    ~LineVector();
    void Init();
    void SetPerLine(PerLine *pl);

    void InsertText(int line, int delta);
    void InsertLine(int line, int position, bool lineStart);
    void SetLineStart(int line, int position);
    void RemoveLine(int line);
    int Lines() const {
        return starts.Partitions();
    }
    int LineFromPosition(int pos) const;
    int LineStart(int line) const {
        return starts.PositionFromPartition(line);
    }

    int MarkValue(int line);
    int AddMark(int line, int marker);
    void MergeMarkers(int pos);
    void DeleteMark(int line, int markerNum, bool all);
    void DeleteMarkFromHandle(int markerHandle);
    int LineFromHandle(int markerHandle);

    void ClearLevels();
    int SetLevel(int line, int level);
    int GetLevel(int line);

    int SetLineState(int line, int state);
    int GetLineState(int line);
    int GetMaxLineState();

};

enum actionType { insertAction, removeAction, startAction, containerAction };

/**
 * Actions are used to store all the information required to perform one undo/redo step.
 */
class Action {
public:
    actionType at;
    int position;
    char *data;
    int lenData;
    bool mayCoalesce;

    Action();
    ~Action();
    void Create(actionType at_, int position_=0, char *data_=0, int lenData_=0, bool mayCoalesce_=true);
    void Destroy();
    void Grab(Action *source);
};

/**
 *
 */
class UndoHistory {
    Action *actions;
    int lenActions;
    int maxAction;
    int currentAction;
    int undoSequenceDepth;
    int savePoint;

    void EnsureUndoRoom();

public:
    UndoHistory();
    ~UndoHistory();

    void AppendAction(actionType at, int position, char *data, int length, bool &startSequence, bool mayCoalesce=true);

    void BeginUndoAction();
    void EndUndoAction();
    void DropUndoSequence();
    void DeleteUndoHistory();

    /// The save point is a marker in the undo stack where the container has stated that
    /// the buffer was saved. Undo and redo can move over the save point.
    void SetSavePoint();
    bool IsSavePoint() const;

    /// To perform an undo, StartUndo is called to retrieve the number of steps, then UndoStep is
    /// called that many times. Similarly for redo.
    bool CanUndo() const;
    int StartUndo();
    const Action &GetUndoStep() const;
    void CompletedUndoStep();
    bool CanRedo() const;
    int StartRedo();
    const Action &GetRedoStep() const;
    void CompletedRedoStep();
};

/**
 * Holder for an expandable array of characters that supports undo and line markers.
 * Based on article "Data Structures in a Bit-Mapped Text Editor"
 * by Wilfred J. Hansen, Byte January 1987, page 183.
 */
class CellBuffer {
private:
    SplitVector<char> substance;
    SplitVector<char> style;
    bool readOnly;

    bool collectingUndo;
    UndoHistory uh;

    LineVector lv;

    /// Actions without undo
    void BasicInsertString(int position, const char *s, int insertLength);
    void BasicDeleteChars(int position, int deleteLength);

public:

    CellBuffer();
    ~CellBuffer();

    /// Retrieving positions outside the range of the buffer works and returns 0
    char CharAt(int position) const;
    void GetCharRange(char *buffer, int position, int lengthRetrieve) const;
    char StyleAt(int position) const;
    void GetStyleRange(unsigned char *buffer, int position, int lengthRetrieve) const;
    const char *BufferPointer();

    int Length() const;
    void Allocate(int newSize);
    void SetPerLine(PerLine *pl);
    int Lines() const;
    int LineStart(int line) const;
    int LineFromPosition(int pos) const { return lv.LineFromPosition(pos); }
    void InsertLine(int line, int position, bool lineStart);
    void RemoveLine(int line);
    const char *InsertString(int position, const char *s, int insertLength, bool &startSequence);

    /// Setting styles for positions outside the range of the buffer is safe and has no effect.
    /// @return true if the style of a character is changed.
    bool SetStyleAt(int position, char styleValue, char mask='\377');
    bool SetStyleFor(int position, int length, char styleValue, char mask);

    const char *DeleteChars(int position, int deleteLength, bool &startSequence);

    bool IsReadOnly() const;
    void SetReadOnly(bool set);

    /// The save point is a marker in the undo stack where the container has stated that
    /// the buffer was saved. Undo and redo can move over the save point.
    void SetSavePoint();
    bool IsSavePoint();

    bool SetUndoCollection(bool collectUndo);
    bool IsCollectingUndo() const;
    void BeginUndoAction();
    void EndUndoAction();
    void AddUndoAction(int token, bool mayCoalesce);
    void DeleteUndoHistory();

    /// To perform an undo, StartUndo is called to retrieve the number of steps, then UndoStep is
    /// called that many times. Similarly for redo.
    bool CanUndo();
    int StartUndo();
    const Action &GetUndoStep() const;
    void PerformUndoStep();
    bool CanRedo();
    int StartRedo();
    const Action &GetRedoStep() const;
    void PerformRedoStep();
};

#ifdef SCI_NAMESPACE
}
#endif

#endif
