/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield 
 *
 * This library is open source and may be redistributed and/or modified under  
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or 
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 * 
 * This library 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 
 * OpenSceneGraph Public License for more details.
*/

#ifndef OSGTEXT_TEXT
#define OSGTEXT_TEXT 1

#include <osg/Drawable>
#include <osg/Quat>

#include <osgText/Font>
#include <osgText/String>

namespace osgText {


class OSGTEXT_EXPORT Text : public osg::Drawable
{
public:

    Text();
    Text(const Text& text,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);

    virtual osg::Object* cloneType() const { return new Text(); }
    virtual osg::Object* clone(const osg::CopyOp& copyop) const { return new Text(*this,copyop); }
    virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast<const Text*>(obj)!=NULL; }
    virtual const char* className() const { return "Text"; }
    virtual const char* libraryName() const { return "osgText"; }


    /** Set the Font to use to render the text.  
      * setFont(0) sets the use of the default font.*/
    void setFont(Font* font=0);

    /** Set the font, loaded from the specified front file, to use to render the text,
      * setFont("") sets the use of the default font.*/
    void setFont(const std::string& fontfile);

    /** Get the font. Return 0 if default is being used.*/    
    const Font* getFont() const { return _font.get(); }

    /** Set the Font reference width and height resolution in texels.
      * Note, the size may not be supported by current font, 
      * the closest supported font size will be selected.*/
    void setFontSize(unsigned int width, unsigned int height);
    
    unsigned int getFontWidth() const { return _fontWidth; }
    unsigned int getFontHeight() const { return _fontWidth; }
    
    
    /** Set the text using a osgText::String.*/
    void setText(const String& text);

    /** Set the text using a std::string, 
      * which is converted to an internal TextString.*/
    void setText(const std::string& text);

    /** Set the text using a Unicode encoded std::string, which is converted to an internal TextString.
      * The encoding parameter specificies which Unicode encodeding is used in the std::string. */
    void setText(const std::string& text,String::Encoding encoding);

    /** Set the text using a wchar_t string, 
      * which is converted to an internal TextString.*/
    void setText(const wchar_t* text);
    
    /** Get the text string. 
      * Note, if you modify the string you must call Text::update() for
      * the internal glyph reprentation to be updated.*/
    String& getText() { return _text; }

    /** Get the const text string.*/
    const String& getText() const { return _text; }
    
    /** update internal glyph respresnetation used for rendering, 
      * and bounding volume.*/
    void update() { computeGlyphRepresentation(); }


    /** Set the rendered character size in object coordinates.*/
    void setCharacterSize(float height,float aspectRatio=1.0f);
    
    float getCharacterHeight() const { return _characterHeight; }
    float getCharacterAspectRatio() const { return _characterAspectRatio; }



    /** Set the maximum width of the text box.
      * With horizontal layouts any characters which do not fit are wrapped around.
      * 0 or negative values indicate that no maximum width is set, lines can be as long as 
      * they need be to fit thre required text*/
    void setMaximumWidth(float maximumWidth);
    
    /** Get the maximim width of the text box.*/
    float getMaximumWidth() const { return _maximumWidth; }

    /** Set the maximum height of the text box.
      * With horizontal layouts any characters which do not fit are wrapped around.
      * 0 or negative values indicate that no maximum height is set, lines can be as long as 
      * they need be to fit thre required text*/
    void setMaximumHeight(float maximumHeight);
    
    /** Get the maximum height of the text box.*/
    float getMaximumHeight() const { return _maximumHeight; }



    /** Set the position of text.*/
    void setPosition(const osg::Vec3& pos);
    
    /** Get the position of text.*/
    const osg::Vec3& getPosition() const { return _position; }
       

    enum AlignmentType
    {
        LEFT_TOP,
        LEFT_CENTER,
        LEFT_BOTTOM,

        CENTER_TOP,
        CENTER_CENTER,
        CENTER_BOTTOM,

        RIGHT_TOP,
        RIGHT_CENTER,
        RIGHT_BOTTOM,
        BASE_LINE /// default.
    
    };
    
    void setAlignment(AlignmentType alignment);

    AlignmentType getAlignment() const { return _alignment; }


    enum AxisAlignment
    {
        XY_PLANE,
        XZ_PLANE,
        YZ_PLANE,
        SCREEN
    };

    void setAxisAlignment(AxisAlignment axis);
    
    AxisAlignment getAxisAlignment() const { return _axisAlignment; }


    void setRotation(const osg::Quat& quat);
    
    const osg::Quat& getRotation() const { return _rotation; }


    enum Layout
    {
        LEFT_TO_RIGHT, /// default
        RIGHT_TO_LEFT,
        VERTICAL
    };
    
    void setLayout(Layout layout);
    
    Layout getLayout() const { return _layout; }


    void setColor(const osg::Vec4& color);
    
    const osg::Vec4& getColor() const { return _color; }


    enum DrawModeMask
    {
        TEXT        = 1, /// default
        BOUNDINGBOX = 2,
        ALIGNMENT   = 4
    };

    void setDrawMode(unsigned int mode) { _drawMode=mode; }
    
    unsigned int getDrawMode() const { return _drawMode; }

   
    /** Draw the text.*/
    virtual void drawImplementation(osg::State& state) const;

    /** return false, osgText::Text does not support accept(AttributeFunctor&).*/
    virtual bool supports(osg::Drawable::AttributeFunctor&) const { return false; }

    /** return true, osgText::Text does support accept(ConstAttributeFunctor&).*/
    virtual bool supports(osg::Drawable::ConstAttributeFunctor&) const { return true; }

    /** accept an ConstAttributeFunctor and call its methods to tell it about the interal attributes that this Drawable has.*/
    virtual void accept(osg::Drawable::ConstAttributeFunctor& af) const;

    /** return true, osgText::Text does support accept(PrimitiveFunctor&) .*/
    virtual bool supports(osg::Drawable::PrimitiveFunctor&) const { return true; }

    /** accept a PrimtiveFunctor and call its methods to tell it about the interal primtives that this Drawable has.*/
    virtual void accept(osg::Drawable::PrimitiveFunctor& pf) const;


    // make Font a friend to allow it set the _font to 0 if the font is 
    // forcefully unloaded.
    friend class Font;

protected:

    virtual ~Text();

    virtual bool computeBound() const;

    Font* getActiveFont();
    const Font* getActiveFont() const;

    
    // members which have public access.
    osg::ref_ptr<Font>      _font;
    unsigned int            _fontWidth;
    unsigned int            _fontHeight;
    float                   _characterHeight;
    float                   _characterAspectRatio;
    float                   _maximumWidth;
    float                   _maximumHeight;

    String                  _text;
    osg::Vec3               _position;
    AlignmentType           _alignment;
    AxisAlignment           _axisAlignment;
    osg::Quat               _rotation;
    Layout                  _layout;
    osg::Vec4               _color;
    unsigned int            _drawMode;

    // internal structures, variable and methods used for rendering of characters.
    struct GlyphQuads
    {
        typedef std::vector<osg::Vec2> Coords;
        typedef std::vector<osg::Vec2> TexCoords;

        Coords      _coords;
        TexCoords   _texcoords;
    };
    typedef std::map<osg::ref_ptr<osg::StateSet>,GlyphQuads> TextureGlyphQuadMap;

    // iternal map used for rendering. Set up by the computeGlyphRepresentation() method.
    TextureGlyphQuadMap         _textureGlyphQuadMap;
    
    void computeGlyphRepresentation();

    // internal caches of the positioning of the text.
    osg::Matrix                 _matrix;
    osg::Vec3                   _offset;
    mutable osg::BoundingBox    _textBB;
    
    void computePositions();

};

}


#endif
