/** 
 *  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 SSyntax_h
#define SSyntax_h

#include "stoolkit/STextData.h"
#include "stoolkit/SBinVector.h"
#include "stoolkit/SBinHashtable.h"
#include "stoolkit/SVector.h"
#include "stoolkit/SString.h"
#include "stoolkit/SStringVector.h"
#include "stoolkit/SLineTracker.h"
#include "stoolkit/SEvent.h"
#include "stoolkit/syntax/SMatcher.h"
#include "stoolkit/syntax/SSyntaxMarker.h"

// This many characters are processed, or this many unit works
// are performed in each timer call.
#define SD_UNIT_WORK_COUNT 100

class SSyntaxListener
{
public:
  enum SS_EventType { SD_PARSING_STARTED, SD_PARSING_INSERT, SD_PARSING_DONE };
  SSyntaxListener (void) {}
  virtual ~SSyntaxListener () {}
  virtual void syntaxChanged (SS_EventType _evnt)=0;
};

class SSyntaxState
{
public:
  // Context will delete the objects in args when destructed
  SSyntaxState (SMatcher* _matcher, SSyntaxMarker* _marker, STimer* _timer)
    : matcher (_matcher), marker (_marker), timer (_timer) 
    {
    }
  ~SSyntaxState ()
    { delete timer; delete marker; delete matcher; }
  STextIndex getCurrentIndex  ()
    { return marker->getCurrentIndex (); }
  SMatcher*       matcher;
  SSyntaxMarker*  marker;
  STimer*         timer;
};

// SExentTarget is for crawling timeout
class SSyntax : public SLineTracker, public SEventTarget
{
public:
  // color is a precious resource, we have only 
  // a limited number of them here.
  // The number of charactrers that are cached are
  // determined by SAwt constructor cacheSize=2000

  // We have a shadow version of these in  SSyntaxMarker
  enum SS_Tag { SD_NONE=0, SD_ERROR, 
       SD_NUMBER, SD_STRING, SD_COMMENT, SD_KEYWORD, 
       SD_VARIABLE, SD_DEFINE, SD_CONTROL, SD_OTHER, SD_MAX };
  SSyntax (void);
  ~SSyntax ();

  bool setSyntax (const SString&  ps); 
  const SString& getParser () const; 

  void setTextData (const STextData* td); 

  /* by lines raw index */
  SS_Tag getTag (const STextIndex& index);
  /* get text data index */
  SS_Tag getTagByTDI (const STextIndex& index);

  virtual void lineRemoved (void* src, unsigned int index);
  virtual void lineInserted (void* src, unsigned int index);
  virtual void lineChanged (void* src, unsigned int index);

  // The patch for the syntax files.
  static void setPath(const SStringVector &p);
  static void guessPath();
  static const SStringVector& getPath();

  static bool isSupported (const SString& syn);

  // This will get called from time-to-time 
  // when this class crawls text and parses
  // Only whole lines will changed.
  void addTextDataListener (STextDataListener* _listener);
  void addSyntaxListener (SSyntaxListener* _listener);

  static SString       getMissingFile (const SString& name);
  static SString       getFolderFor (const SString& name);
  static SStringVector getCategories ();
  static SStringVector getAvaliableList (const SString& category);

private:
  STextDataListener*       listener;
  SSyntaxListener*         syntaxListener;
  const STextData*         textData;
  SSyntaxState*            syntaxState;

  void clear ();
  void clearIterator ();
  void lineGlobalChange ();
  void applyActions ();

  // do another iteration of syntax checking
  virtual bool timeout (const SEventSource* s);

  // if ndx is a move back restart parsing.
  // if parse is "" delete parsing
  // ndx is our index, not datamodel index.
  void updateSyntaxState (const STextIndex ndx);

  SString                 parser;
  SPattern*               pattern;

  // These two are in sync. They contain the full expanded line
  SSyntaxData             syntaxLines;
  SUnicodeData            dataLines;
  // for consecutive getTagByTDI
  STextIndex              iteratorSyntaxIndex;  // syntaxLines, dataLines
  STextIndex              iteratorDataIndex;    // textData
  
};

#endif /* SSyntax */
