/***************************************************************************
 *   Copyright (C) 2005 by Thierry CHARLES   *
 *   thierry@les-charles.net   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   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.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#ifndef _TENLIGHTER_H_
#define _TENLIGHTER_H_

#include "lib/commons.h"
#include "components/codeeditor/tdocument.h"
#include "components/codeeditor/tstyle.h"

class TCodeEditor;
class TLineEnlightenmentInformation;

#include <map>
#include <deque>
#include <set>

class TEnlighter : public TDocumentListener
{
    public :
        TEnlighter(TCodeEditor * editor);
        virtual ~TEnlighter();

        /** renvoie les informations de style pour la ligne iLine */
        const TLineEnlightenmentInformation & getLineEnlightenmentInformation(int iLine);

        /**
         * renvoie l'�diteur associ�
         */
        TCodeEditor * getEditor() { return this->editor; }

        /** effectue les mises en valeur n�cessaires pour obtenir les infos de la ligne demand�e */
        void checkEnlightenmentForLine(int iLine);

        /** invalide toutes les informations de mise en valeur */
        void invalidateAll();

    protected :
        /**
         * d�fini les styles d'une ligne pour la mettre en valeur
         * ne pas appeler directement
         * ne jamais faire appel � "setEndLineState" ni "validate" sur le parametre info
         * @param iLine ligne a colorer
         * @param iPreviousLineEndState �tat dans lequel se trouvait l'analyseur lors de la sortie de cette fonction pour la ligne pr�c�dente. La premi�re ligne (0) est appell�e avec 0.
         * @param info informations de mise en valeur a compl�ter. ne jamais faire appel � "setEndLineState" ni "validate"
         * @return �tat de l'analyseur � utiliser pour la ligne suivante.
         */
        virtual int enlightLine(int iLine, int iPreviousLineEndState, TLineEnlightenmentInformation & info) = 0;

        /** renvoie les informations de style pour la ligne iLine */
        TLineEnlightenmentInformation & getLineEnlightenmentInformationRef(int iLine);

        /** signale un changement dans le document. Cet �v�nement intervient syst�matiquement apr�s un autre plus sp�cialis� (documentTextInserted ou documentTextRemoved) */
        virtual void documentChanged(TDocument * doc){}
        /** signale l'insertion de texte dans le document. */
        virtual void documentTextInserted(TDocument * doc, const TPoint & ptFrom, const TPoint & ptTo);
        /** signale la suppression de texte dans le document. */
        virtual void documentTextRemoved(TDocument * doc, const TPoint & ptFrom, const TPoint & ptTo);
        /** signale de grosses modifs sur le document. puis appelle documentChanged */
        virtual void documentHeavilyModified(TDocument * doc);

        typedef std::deque<TLineEnlightenmentInformation> TLineEnlightenmentInformationsList;

        /** renvoie un it�rateur sur une ligne */
        TLineEnlightenmentInformationsList::iterator getLineIterator(uint iLine);

        /** valide ou invalide les lignes correspondantes */
        void setLineValidated(int iLine, bool bValidated);

        /**
         * effectue les mises en valeur n�cessaires pour obtenir les infos de la ligne demand�e
         * @param bDoPrimaryCheck indique si il faut v�rifier ou non que des lignes pr�c�dentes ne sont pas invalid�es
         */
        void checkEnlightenmentForLine(int iLine, bool bDoPrimaryCheck);

    private :
        TCodeEditor * editor;
        TLineEnlightenmentInformationsList enlightenmentInformation;
        typedef std::set<int> TIntSet;
        TIntSet invalidatedLines;
};

class TLineEnlightenmentInformation
{
    public:
        TLineEnlightenmentInformation() : iEndLineState(-1), bIsValid(false) { this->clearStyleInformations(); };

        /**
         * d�fini le style sur une partie de la ligne
         * @param iStyleId ID du style a utiliser sur le segment
         * @param iColStart position de d�but d'application du style (inclu)
         * @param iColEnd  position de fin d'application du style (exclu). Jusqu'a la fin de la ligne si iEnd < 0.
         */
        void setStyle(sbyte iStyleId, int iColStart, int iColEnd = -1);

        /** efface les informations de style pour la ligne */
        void clearStyleInformations() { this->setStyle(DEFAULT_STYLE,0); }

        /** renvoie l'ID du style � une position */
        sbyte getStyleAt(int iCol) const;

        /** renvoie l'index de la colonne (exclue) fermant le segment de style en vigueur � la position iCol ou -1 si celui-ci va jusqu'� la fin de la ligne */
        int getSegmentEnd(int iCol) const;

        /** renvoie l'�tat de l'analyseur en fin de ligne */
        int getEndLineState() const { return this->iEndLineState; }

        /** renvoie si les informations sont valides */
        bool isValid() const { return this->bIsValid; }

        /** invalide les informations */
        void invalidate() { this->bIsValid = false; }

        /** optimise la segmentation de la ligne */
        void optimise();

    protected:
        /* la classe TEnlighter est d�finie comme amie afin qu'elle puisse modifier l'�tat des infos */
        friend class TEnlighter;

        /** d�fini l'�tat de l'analyseur en fin de ligne */
        void setEndLineState(int iState) { this->iEndLineState = iState; }

        /** d�fini la ligne comme mise en valeur et donc valide */
        void validate() { this->bIsValid = true; }

    private:
        typedef std::map<int,sbyte> TLineStylesMap;
        TLineStylesMap enlightenment;
        int iEndLineState;
        bool bIsValid;
};

class TDefaultEnlighter : public TEnlighter
{
    public:
        TDefaultEnlighter(TCodeEditor * editor) : TEnlighter(editor) {}

    protected:
        /**
         * d�finis tout au style par d�faut
         * ne pas appeler directement
         * @param iLine ligne a colorer
         * @param iPreviousLineEndState �tat dans lequel se trouvait l'analyseur lors de la sortie de cette fonction pour la ligne pr�c�dente. La premi�re ligne (0) est appell�e avec 0.
         * @param info informations de mise en valeur a compl�ter.
         * @return �tat de l'analyseur � utiliser pour la ligne suivante.
         */
        virtual int enlightLine(int iLine, int iPreviousLineEndState, TLineEnlightenmentInformation & info);
};


#endif
