#ifndef     __FTVectoriser__
#define     __FTVectoriser__


#include "FTContour.h"
#include "FTList.h"
#include "FTPoint.h"
#include "FTVector.h"
#include "FTGL.h"


#ifndef CALLBACK
#define CALLBACK
#endif


/**
 * FTTesselation captures points that are output by OpenGL's gluTesselator.
 */
class FTGL_EXPORT FTTesselation
{
    public:
        /**
         * Default constructor
         */
        FTTesselation( GLenum m)
        : meshType(m)
        {
            pointList.reserve( 128);
        }

        /**
         *  Destructor
         */
        ~FTTesselation()
        {
            pointList.clear();
        }

        /**
         * Add a point to the mesh.
         */
        void AddPoint( const FTGL_DOUBLE x, const FTGL_DOUBLE y, const FTGL_DOUBLE z)
        {
            pointList.push_back( FTPoint( x, y, z));
        }

        /**
         * The number of points in this mesh
         */
        size_t PointCount() const { return pointList.size();}

        /**
         *
         */
        const FTPoint& Point( unsigned int index) const { return pointList[index];}

        /**
         * Return the OpenGL polygon type.
         */
        GLenum PolygonType() const { return meshType;}

    private:
        /**
         * Points generated by gluTesselator.
         */
        typedef FTVector<FTPoint> PointVector;
        PointVector pointList;

        /**
         * OpenGL primitive type from gluTesselator.
         */
        GLenum meshType;
};


/**
 * FTMesh is a container of FTTesselation's that make up a polygon glyph
 */
class FTGL_EXPORT FTMesh
{
   typedef FTVector<FTTesselation*> TesselationVector;
   typedef FTList<FTPoint> PointList;

    public:
        /**
         * Default constructor
         */
        FTMesh();

        /**
         *  Destructor
         */
        ~FTMesh();

        /**
         * Add a point to the mesh
         */
        void AddPoint( const FTGL_DOUBLE x, const FTGL_DOUBLE y, const FTGL_DOUBLE z);

        /**
         *  Create a combine point for the gluTesselator
         */
        const FTGL_DOUBLE* Combine( const FTGL_DOUBLE x, const FTGL_DOUBLE y, const FTGL_DOUBLE z);

        /**
         * Begin a new polygon
         */
        void Begin( GLenum meshType);

        /**
         * End a polygon
         */
        void End();

        /**
         * Record a gluTesselation error
         */
        void Error( GLenum e) { err = e;}

        /**
         * The number of tesselations in the mesh
         */
        unsigned int TesselationCount() const { return tesselationList.size();}

        /**
         * Get a tesselation by index
         */
        const FTTesselation* Tesselation( unsigned int index) const;

        /**
         * Return the temporary point list. For testing only.
         */
        const PointList& TempPointList() const { return tempPointList;}

        /**
         * Get the GL ERROR returned by the glu tesselator
         */
        GLenum Error() const { return err;}

    private:
        /**
         * The current sub mesh that we are constructing.
         */
        FTTesselation* currentTesselation;

        /**
         * Holds each sub mesh that comprises this glyph.
         */
        TesselationVector tesselationList;

        /**
         * Holds extra points created by gluTesselator. See ftglCombine.
         */
        PointList tempPointList;

        /**
         * GL ERROR returned by the glu tesselator
         */
        GLenum err;

};

const FTGL_DOUBLE FTGL_FRONT_FACING = 1.0;
const FTGL_DOUBLE FTGL_BACK_FACING = -1.0;

/**
 * FTVectoriser class is a helper class that converts font outlines into
 * point data.
 *
 * @see FTExtrdGlyph
 * @see FTOutlineGlyph
 * @see FTPolyGlyph
 * @see FTContour
 * @see FTPoint
 *
 */
class FTGL_EXPORT FTVectoriser
{
    public:
        /**
         * Constructor
         *
         * @param glyph The freetype glyph to be processed
         */
        FTVectoriser( const FT_GlyphSlot glyph);

        /**
         *  Destructor
         */
        virtual ~FTVectoriser();

        /**
         * Build an FTMesh from the vector outline data.
         *
         * @param zNormal   The direction of the z axis of the normal
         *                  for this mesh
         */
        void MakeMesh( FTGL_DOUBLE zNormal = FTGL_FRONT_FACING);

        /**
         * Get the current mesh.
         */
        const FTMesh* GetMesh() const { return mesh;}

        /**
         * Get the total count of points in this outline
         *
         * @return the number of points
         */
        size_t PointCount();

        /**
         * Get the count of contours in this outline
         *
         * @return the number of contours
         */
        size_t ContourCount() const { return ftContourCount;}

        /**
         * Return a contour at index
         *
         * @return the number of contours
         */
         const FTContour* Contour( unsigned int index) const;

        /**
         * Get the number of points in a specific contour in this outline
         *
         * @param c     The contour index
         * @return      the number of points in contour[c]
         */
        size_t ContourSize( int c) const { return contourList[c]->PointCount();}

        /**
         * Get the flag for the tesselation rule for this outline
         *
         * @return The contour flag
         */
        int ContourFlag() const { return contourFlag;}

    private:
        /**
         * Process the freetype outline data into contours of points
         */
        void ProcessContours();

        /**
         * The list of contours in the glyph
         */
        FTContour** contourList;

        /**
         * A Mesh for tesselations
         */
        FTMesh* mesh;

        /**
         * The number of contours reported by Freetype
         */
        short ftContourCount;

        /**
         * A flag indicating the tesselation rule for the glyph
         */
        int contourFlag;

        /**
         * A Freetype outline
         */
        FT_Outline outline;
};


#endif  //  __FTVectoriser__
