// -*- C++ -*-
/* This file is part of
 * ======================================================
 * 
 *           LyX, the High Level Word Processor
 * 	 
 *	    Copyright (C) 1995 Matthias Ettrich
 *
 *======================================================*/
#ifndef _LYXTEXT_H
#define _LYXTEXT_H

#include "lyxparameters.h"
#include "lyxparagraph.h"
#include "definitions.h"
#include "layout.h"
#include "lyxfont.h"

class LyXText {
private:
  Row* firstrow;
  Row* lastrow;
   
  /* the currentrow is needed to access rows faster*/ 
  Row* currentrow;		       /* pointer to the current row  */
  long  currentrow_y;		       /* position in the text   */
   
  unsigned short  paperwidth; /* width of the paper */
   
   
  /* inserts a new row behind the specified row, increments
   * the touched counters */
  void InsertRow(Row *row, LyXParagraph *par, int pos );

  /* removes the row and reset the touched counters */
  void RemoveRow(Row *row);
   
  /* remove all following rows of the paragraph of the specified row. */
  void RemoveParagraph(Row *row);
   
  /* insert the specified paragraph behind the specified row */
  void InsertParagraph(LyXParagraph *par, Row *row);
   
  /* appends  the implizit specified paragraph behind the specified row,
   * start at the implizit given position */
  void AppendParagraph(Row *row);
   
   
  void BreakAgain(Row *row);
   
  void BreakAgainOneRow(Row *row);
   
  void SetHeightOfRow(Row *row_ptr); /* calculate and set the height 
				      * of the row */
   
  /* this calculates the specified parameters. needed when setting
   * the cursor and when creating a visible row */ 
  void PrepareToPrint(Row *row, float &x, float &fill_separator, 
		      float &fill_hfill, float &fill_label_hfill);

  void DeleteEmptyParagraphMechanism(LyXCursor old_cursor);

  /* Updates all counters starting BEHIND the row. Changed paragraphs
   * with a dynamic left margin will be rebroken. */ 
  void UpdateCounters(Row *row);

  void SetCounter(LyXParagraph *par);
   
   
  /* some low level functions */ 
  int SingleWidth(LyXParagraph *par, int pos);
  void Draw(Row *row, int &pos, unsigned long  pm, int offset, float &x);
  /* get the next breakpoint in a given paragraph */
  int NextBreakPoint(Row* row, int width);
  /* returns the minimum space a row needs on the screen in pixel */
  int Fill(Row *row, int paperwidth);
  /* returns the minimum space a manual label needs on the screen in pixel */ 
  int LabelFill(Row *row);
  int BeginningOfMainBody(LyXParagraph *par);
  /* Returns the left beginning of the text. 
   * This information cannot be taken from the layouts-objekt, because in 
   * LaTeX the beginning of the text fits in some cases (for example sections)
   * exactly the label-width. */
  int LeftMargin(Row *row);
  int RightMargin(Row *row);
  int LabelEnd (Row *row);
   
  /* returns the number of separators in the specified row. The separator 
   * on the very last column doesnt count */ 
  int NumberOfSeparators(Row *row);
   
  /* returns the number of hfills in the specified row. The LyX-Hfill is
   * a LaTeX \hfill so that the hfills at the beginning and at the end were 
   * ignored. This is *MUCH* more usefull than not to ignore!  */
  int NumberOfHfills(Row *row);
   
  /* like NumberOfHfills, but only those in the manual label! */ 
  int NumberOfLabelHfills(Row *row);
   
  /* returns true, if a expansion is needed. Rules are given by 
   * LaTeX */ 
  bool HfillExpansion(Row *row_ptr, int pos);
   
   
  /* returns the paragraph position of the last character in the 
   * specified row */
  int RowLast(Row *row);

   
public:
  LyXTextParameters *parameters; //points to Buffer.parameters
   
  int number_of_rows;
  long height;
   
  LyXFont current_font;	       /* the current font settings */
  LyXFont real_current_font;	       /* the current font  */

  LyXFont GetFont(LyXParagraph* par, int pos);
  void SetCharFont(LyXParagraph *par, int pos, LyXFont font);
   
  /* returns a pointer to the very first LyXParagraph */ 
  LyXParagraph *FirstParagraph();
  
  /* Konstruktor */
  LyXText(int pw, LyXTextParameters *p);
   
  /* Destruktor */ 
  ~LyXText();
   
  /* what you expect when pressing <enter> at cursor position */ 
  void BreakParagraph(char keep_layout = 0);
   
  /* set layout over selection and make a total rebreak of those  paragraphs */
  void SetLayout(char layout);
  /* used in setlayout */
  void MakeFontEntriesLayoutSpecific(LyXParagraph *par);
   
  /* increment depth over selection and make a total rebreak of those 
   * paragraphs */
  void IncDepth();
  /* decrement depth over selection and make a total rebreak of those  
   * paragraphs */
   void DecDepth();
  /* set font over selection and make a total rebreak of those paragraphs */
  void SetFont(LyXFont font);
   
  /* deletes and inserts again all paragaphs between the cursor
   * and the specified par .The Cursor is needed to set the refreshing
   * parameters. 
   * This function is needed after SetLayout and SetFont etc. */
  void RedoParagraphs(LyXCursor cursor, LyXParagraph *end_par);
   
   void RedoParagraph();
   
  void ToggleFree(LyXFont font, const char* stylename);
   
  /* recalculates the heights of all previous rows of the specified paragraph.
   * needed, if the last characters font has changed. */ 
  void RedoHeightOfParagraph(LyXCursor cursor);
   
  /* forces the redrawing of a paragraph. Needed when manipulating a 
   * right address box */ 
  void RedoDrawingOfParagraph(LyXCursor cursor);
   
  /* insert a character, moves all the following breaks in the 
   * same Paragraph one to the right and make a little rebreak */
  void InsertChar(char c);
  void InsertInset(Inset *inset);
   
  /* completes the insertion with a full rebreak */ 
  int FullRebreak();
   
  /* may be important for the menu */
  char* GetLayout(int row);
  char GetFootnoteFlag(int row);

  Row* need_break_row;
   
  long  refresh_y;
  int refresh_height;
  int refresh_width;
  int refresh_x;
  Row *refresh_row;
   
  int refresh_pos;
  char status; /* wether the screen needs a refresh,
		* starting with refresh_y */
  
  /* returns a pointer to the row near the specified y-coordinate
   * (relative to the whole text). y is set to the real beginning
   * of this row */ 
  Row* GetRowNearY(long &y);

  /* returns the column near the specified x-coordinate of the row 
   * x is set to the real beginning of this column  */ 
  int GetColumnNearX(Row *row, int& x);
   
  /* returns a pointer to a specified row. y is set to the beginning
   * of the row */
  Row* GetRow(LyXParagraph *par, int pos, long &y);

  /* returns the height of a default row, needed  for scrollbar */
  int DefaultHeight();
   
  /* the cursor */
  LyXCursor cursor;
   
  /* the selection cursor */
  char selection;	       /* just a boolean flag*/
  char mark_set; 	       /* just a boolean flag*/
   
  LyXCursor sel_cursor;
  LyXCursor sel_start_cursor;
  LyXCursor sel_end_cursor;
  LyXCursor last_sel_cursor; /* needed for the toggling */ 
  LyXCursor toggle_cursor;
  LyXCursor toggle_end_cursor;
   
  /* need the selection cursor: */ 
  void SetSelection();
  void ClearSelection();

  /* just selects the word the cursor is in */ 
  void SelectWord();
   
  /* 'selects" the next word, where the cursor is not in 
   * and returns this word as string. THe cursor will be moved 
   * to the beginning of this word. 
   * With SelectSelectedWord can this be highlighted really */ 
  char* SelectNextWord(float &value);
  void SelectSelectedWord();
   
  void SetCursor(LyXParagraph *par, int pos);
  void SetCursorIntern(LyXParagraph *par, int pos);
  void SetCursorFromCoordinates(int x, long y);
   
  void CursorUp();
  void CursorDown();
  void CursorLeft();
  void CursorRight();
  void CursorLeftOneWord();
  void CursorRightOneWord();
  void CursorHome();
  void CursorEnd();
  void CursorTab();
  void CursorTop();
  void CursorBottom();
  void Delete();
  void Backspace();
  void DeleteWordForward();
  void DeleteWordBackward();
  void DeleteLineForward();
  int SelectWordWhenUnderCursor();
  void UpcaseWord();
  void LowcaseWord();
  void CapitalizeWord();
  /* returns a printed row in a pixmap. The y value is needed to decide, 
   * wether it is selected text or not. This is a strange solution but
   * faster. */ 
  void GetVisibleRow(unsigned long pixmap, int offset, 
			      Row *row_ptr, long y);
					   
  /* footnotes: */
   
  void ToggleFootnote();
  void OpenStuff();
  
  void OpenFootnotes();
  void OpenFootnote();
  void CloseFootnotes();
  void CloseFootnote();
   
  /* turn the selection into a new environment. If there is no selection,
   * create an empty environment */ 
  void InsertFootnoteEnvironment(char kind);
  void MeltFootnoteEnvironment();
   
  void CutSelection();
  void CopySelection();
  void PasteSelection();
   
  void InsertFootnote();
  void InsertMarginpar();
  void InsertFigure();
  void InsertTabular();
   
  /* the DTP switches for paragraphs. LyX will store the top settings
   * always in the first physical paragraph, the bottom settings in the
   * last. When a paragraph is broken, the top settings rest, the bottom 
   * settings are given to the new one. So I can make shure, they do not
   * duplicate themself (and you cannnot make dirty things with them! ) */ 
  void SetParagraph(char line_top, char line_bottom,
		    char pagebreak_top, char pagebreak_bottom,
		    float space_top, float space_bottom,
		    char fill_top, char fill_bottom,
		    char align, 
		    const char* labelwidthstring,
		    char noindent);

  /* these things are for search and replace */
   
  /* returns true if the specified string is at the specified position */
  bool IsStringInText(LyXParagraph *par, int pos, char* string);

  /* sets the selection over the number of characters of string, no check!! */
  void SetSelectionOverString(char* string);

  /* simple replacing. The font of the first selected character is used */
  void ReplaceSelectionWithString(char* string);

  /* if the string can be found: return true and set the cursor to the new 
   * position */
  bool SearchForward(char* string);
  bool SearchBackward(char* string);
 
  /* needed to insert the selection */
  void InsertStringA(char* string);
  void InsertStringB(char* string);
   
  /* usefull when texing from within lyrix */ 
  bool GotoNextError();

  /* just another features :) */
  bool GotoNextNote();

  /* needed to switch between different classes 
   * this works for a list of paragraphs beginning with the specified par 
   * return value is the number of wrong conversions */ 
  int SwitchLayoutsBetweenClasses(char class1, char class2, LyXParagraph *par);

  /* for the greater insets */
  
  /* returns 0 if inset wasn't found */
  int UpdateInset(Inset* inset);

  void CheckParagraph(LyXParagraph* par, int pos);

   /* table stuff -- begin*/ 
   void TableFeatures(int feature); /* all table features of the text-class 
				       are put together in this function. Possible values
				       of feature are defined in table.h */ 
   int NumberOfCell(LyXParagraph *par, int pos);
   int WidthOfCell(LyXParagraph *par, int &pos); /* pos points at the
						  * beginning of the
						  * next cell (if there is one) */
   void InsertCharInTable(char c);
   void BackspaceInTable();
   void CheckParagraphInTable(LyXParagraph* par, int pos);
  char HitInTable(Row* row, int x);
   /* table stuff -- end*/

  LyXParagraph* GetParFromID(int id);

   // undo functions
   bool  TextUndo(); // returns False if no undo possible
   bool  TextRedo(); // returns False if no redo possible
   bool TextHandleUndo(Undo* undo); // used by TextUndo/TextRedo
   void FinishUndo(); // makes sure the next operation will be stored
   void FreezeUndo();// this is dangerous and for internal use only
   void UnFreezeUndo();// this is dangerous and for internal use only
   Bool undo_finished; // the flag used by FinishUndo();
   Bool undo_frozen; // a flag
   void SetUndo(char kind, LyXParagraph *before, LyXParagraph *end);
   void SetRedo(char kind, LyXParagraph *before, LyXParagraph *end);
   Undo *CreateUndo(char kind, LyXParagraph *before, LyXParagraph *end);
   void SetCursorParUndo(); // for external use in lyx_cb.C
   void CursorLeftIntern();
   void CursorRightIntern();
};


#endif
