/** 
 *  Yudit Unicode Editor Source File
 *
 *  GNU Copyright (C) 1997-2023  Gaspar Sinai <gaspar@yudit.org>  
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License, version 2,
 *  dated June 1991. See file COPYYING for details.
 *
 *  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, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#ifndef STextEdit_h
#define STextEdit_h

#include "swidget/SYuditInput.h"
#include "swidget/SEditor.h"
#include "swidget/STextEditLS.h"
#include "swidget/SEditorIF.h"
#include "swidget/SPanel.h"
#include "swidget/STextView.h"
#include "swidget/SBorder.h"
#include "swidget/SCaret.h"
#include "stoolkit/SString.h"
#include "stoolkit/SProperties.h"
#include "stoolkit/SEvent.h"
#include "stoolkit/SStringVector.h"
#include "stoolkit/SBinVector.h"
#include "stoolkit/SCursorIndex.h"

class SDClick : public SEventTarget
{
public:
 SDClick(void);
 ~SDClick();

  void              start (unsigned int millisec);
  unsigned int      clickCount;
  unsigned int      timeoutCount;
protected:
  STimer*  timer;
  bool timeout (const SEventSource* s);
};

class STextEdit : public SPanel, public SEditorIF, public SPreEditor
{
public:
  STextEdit (void);
  STextEdit (const SString& utf8);
  virtual ~STextEdit ();
  // This should be the first thing you do
  void setDoubleBuffer (bool yes);

  void setFocus();
  bool isFocused () const;

  const SDimension& getPreferredSize();

  void addTextEditLS (STextEditLS* ls);
  void removeTextEditLS (STextEditLS* ls);
  void setEditor (const SEditor& editor);
  void setXIMProperties (const SProperties& props);
  void addSyntaxListener (SSyntaxListener* _listener)
     { textView.addSyntaxListener (_listener); }
  // only SSyntax.
  SString getSyntaxName () const
     { return SString (textView.getSyntaxName ()); }
  // internal included
  SString getHighlightName () const
     { return SString (textView.getHighlightName ()); }

  virtual void setBackground (const SColor& bg);
  virtual void setTextBackground (const SColor& bg);
  void setForeground (const SColor& lrfg, const SColor& rlfg);
  void setCaretForeground (const SColor& lrfg, const SColor& rlfg);

  virtual void lostKeyboardFocus (SWindow* w);
  virtual void lostClipSelection (SWindow* w);
  virtual bool gainedKeyboardFocus (SWindow* w);
  virtual void redraw (SCanvas *canvas, int x, int y, 
     unsigned int width, unsigned int height);

  virtual void keyPressed (SWindow * w, SKey key, const SString& s,
          bool ctrl, bool shift, bool meta);
  virtual void keyReleased (SWindow * w, SKey key, const SString& s,
          bool ctrl, bool shift, bool meta);
  virtual void buttonPressed (SWindow * w, int button, int x, int y);
  virtual void buttonReleased (SWindow * w, int button, int x, int y);
  virtual void buttonDragged (SWindow * w, int button, int x, int y);

  virtual void resize (const SDimension& size);
  void   resizeTextView (bool scrool);
  virtual void move (const SLocation& loc);

  void setAlignment (bool align);
  void setMultiline (bool multiline);
  bool isMultiline () const;
  void setLineEndMark (bool lineend);
  bool getLineEndMark () const;

  void scrollVertical (int value, bool notofy);
  void scrollHorizontal (int value, bool notofy);

  virtual void setFont (const SString& font, double fontSize);
  virtual void setFontSize (double size);


  virtual void setFont (const SString& font);
  virtual void setInputMethod (const SString& im);

  virtual void insertClipboardText (bool isPrimary);
  virtual void insertText (const SString& str, bool embed=true);
  virtual void insertDirtyText (const SString& str, bool embed=true);
  virtual void insertPreEditText (const SString& utf8t, 
        SPreEditor::SStyle style);


  virtual SString eraseText (const STextIndex& till);

  virtual void pageUp ();
  virtual void pageDown ();

  virtual const SCursorIndex& getCursorIndex () const;
  virtual void setCursorIndex (const SCursorIndex& index);

  virtual void caretUp ();
  virtual void caretDown ();
  virtual void caretLeft ();
  virtual void caretRight ();

  virtual void startSelect ();
  virtual void endSelect ();
  virtual void clipSelect (bool isPrimary);

  virtual void selectText (const SCursorIndex& till); 
  virtual void selectWord ();
  virtual void selectLine ();
  virtual void deselectText ();

  virtual SString eraseSelectedText ();
  virtual STextIndex getSelectedIndex (bool hi);
  virtual STextIndex getIndexAfterLineBreak ();

  virtual SString backspace ();
  virtual SString erase ();

  virtual bool addComposing(SS_UCS4 c);
  virtual SS_UCS4 removeComposing();

  virtual void setDirection (SS_DR_Dir dir);
  virtual SS_DR_Dir getDirection () const;
  virtual bool changeDirection (SS_DR_Dir dir);

  virtual void focusOut ();
  virtual void setEditable (bool editable);
  virtual bool isEditable () const;
  virtual bool isSelecting() const;

  virtual SString getText (const STextIndex& from, const STextIndex& till);
  virtual void clear();
  virtual bool clearState();

  virtual void setDocumentEmbedding (SS_Embedding e);
  virtual SS_Embedding getDocumentEmbedding () const;

  void setUnderlineColor (const SColor& c);
  void setText (const SString& text);

  SString getText ();
  bool undo();
  bool redo();
  void setParagraphSeparator (const SString& lineBreak, bool change);

  void setSyntax (const SString& hlMode);
  const SString& getSyntax () const;

  void setSyntaxColors (const SSyntaxColors& attr);
  const SSyntaxColors&  getSyntaxColors () const;

  void setWordWrap (bool lbm);
  bool getWordWrap () const;

  const SStringVector& getHistory();
  void putHistory (const SString& str);
  void setHistorySize (unsigned int siz);
  void historyUp ();
  void historyDown ();
  void historyEnd ();
  bool find(const SString& str);
  bool replace(const SString& orig, const SString& str);

  const SGlyph* glyphAt(const STextIndex & ti) const;
  STextIndex getCaretArrowFrom ();

  /* new text through editor */
  void insertEditorText (const SString& text);

  bool isEmbedStateLR() const;

  /* encode with current keymap */
  SString encode (const SV_UCS4& g) const;
  SString getSelectedText ();

  void setAutoClipboard(bool is);
  void setHideText(bool is);


protected:
  bool autoClipboard;
  void autoClipSelection ();

  unsigned int historySize;
  unsigned int currentHistorySize;
  SStringVector      history;
  SProperties        ximProperties;

  SDClick    clicks;
  bool       focused;
  bool       editable;
  bool       selecting;
  STextIndex startSelection;
  STextIndex endSelection;

  void atutoClipSelection ();
  void setCaretLocationVisible ();
  void setCaretVisibleVertical();
  void setCaretVisibleHorizontal();

  void centerCaretVertical();

  void       updateCaretLocation(bool setvisible=true);
  void       updateCaretPosition(bool updateColumn=true);

  SCaret     caret;
  SBorder    border;
  STextView  textView;

  /* This is from SSliderListener */
  virtual void valueChanged (SSlidable* slidable, SSlideType type);

  /* This is from component */
  virtual SSlidable* setSliderListener (SSliderListener* l);

  // SPreeditor
  virtual void preEditClearMarkedText ();
  virtual void preEditInsertMarkedText(const SString& utf8, SStyle style);
  virtual SRectangle preEditGlyphRectangleUTF16(unsigned int charPos);

  STimer*  eventMergeTimer;


private:
  SRectangle getGlyphRectangle (const STextIndex& ti);
  //
  SCursorIndex preEditStartIndex;
  SCursorIndex preEditEndIndex;
  SS_DR_Dir    preEditStartDirection; 
  unsigned int preEditSize;

  SString cleanEmbed(const SString str) const;

  SString          imWaiting;
  SString          inputMethod;
  SSlidable        slidable;
  SSliderListener* sliderListener;

  SYuditInput* yuditInput;
  void         notifySlider ();
  void         fireTextChanged (); 
  void         fireCaretMoved (); 
  void         redrawInternal ();

  SBinVector<STextEditLS*> listeners;

  SEditor  editor;
  SProperties  getProperties ();
  void internalMoveCaret (const SCursorIndex& realIndex);

  void clip (bool on);
  unsigned int column; /* this is to align up-down movements of cursor. */
  bool resized;
  unsigned int statusHeight; /* status area for 'over-the-spot-off'  */
};

#endif /* STextEdit_h */
