//
//  LabelNode.hpp
//  Meteor
//
//  Created by Cesar Parent on 20/08/2015.
//  Copyright © 2015 Cesar Parent. All rights reserved.
//

/*!
 * @file            LabelNode.h
 *
 */

#ifndef LabelNode_hpp
#define LabelNode_hpp

#include "Node.h"
#include "../Graphics.h"
#include <string>

NS_BEGIN

/*!
 * @class           LabelNode
 * @ingroup         GameObjects
 * @brief           A node that can draw text with TrueType fonts.
 */
class LabelNode : public Node {
    
public:
    
    /**
     * @brief       Options for aligning text vertically.
     */
    enum class VerticalAlignmentMode {
        /// Positions the text so that the top of the text is on the node's origin.
        Top,
        /// Centers the text vertically on the node’s origin.
        Center,
        /// Positions the text so that the bottom of the text is on the node’s origin.
        Bottom,
    };
    
    /**
     * @brief       Options for aligning text horizontally.
     */
    enum class HorizontalAlignmentMode {
        /// Positions the text so that the left side of the text is on the node’s origin.
        Left,
        /// Centers the text horizontally on the node’s origin.
        Center,
        /// Positions the text so that the right side of the text is on the node’s origin.
        Right,
    };
    
    /*!
     * @name        Creating and Saving Label Nodes
     * @{
     */
    
    /*!
     * @brief       Creates a new label.
     * @param       font        Filename of the TrueType font.
     */
    LabelNode(const std::string& font);
    
    /*!
     * @brief       Creates a new label from the data contained in a <code>DecoderProtocol</code>
     *              object.
     * @param       coder       Decoder that contains a serialized node.
     * @see         encodeWithCoder(EncoderProtocol*)
     */
    LabelNode(DecoderProtocol* coder);
    
    /*!
     * @brief       Serializes the label to an <code>EncoderProtocol</code> object.
     * @param       coder       Encoder object to serialize to.
     * @see         LabelNode(DecoderProtocol*)
     */
    virtual void
    encodeWithCoder(EncoderProtocol* coder) override;
    
    /*!
     * @}
     */
    
    virtual ~LabelNode();
    
    // MARK: -
    // MARK: Getters
    
    /*!
     * @name        Inspecting a Label's visual properties
     * @{
     */
    
    /*!
     * @brief       Returns the label's text.
     * @return      The label's text.
     * @see         setText(const std::string&)
     */
    std::string
    text() const { return _text; }
    
    /*!
     * @brief       Returns the label's font filename.
     * @return      The label's font filename.
     * @see         setFont(const std::string&)
     */
    std::string
    font() const { return _fontName; }
    
    /*!
     * @brief       Returns the label's font size.
     * @return      The label's font size.
     * @see         setFontSize(int)
     */
    int
    fontSize() const { return _fontSize; }
    
    /*!
     * @brief       Returns the label's font color.
     * @return      The label's font color.
     * @see         setFontColor(const Color&)
     */
    Color
    fontColor() const { return _fontColor; }
    
    /*!
     * @brief       Returns the label's rendering quality
     * @return      The label antialiasing setting.
     * @see         setFontAA(bool)
     */
    bool
    fontAA() const { return _antialias; }
    
    /*!
     * @brief       Returns The vertical position of the text relative to the node's position.
     * @return      The vertical position of the text relative to the node's position.
     * @see         setVerticalAlignmentMode(VerticalAlignmentMode)
     */
    VerticalAlignmentMode
    verticalAlignmentMode() const;
    
    /*!
     * @brief       Returns The horizontal position of the text relative to the node's position.
     * @return      The horizontal position of the text relative to the node's position.
     * @see         setHorizontalAlignmentMode(HorizontalAlignmentMode)
     */
    HorizontalAlignmentMode
    horizontalAlignmentMode() const;
    
    /*!
     * @brief       Returns the label's bounding rectangle.
     * @return      The label's bounding rectangle.
     */
    Rect
    frame() const;
    
    /*!
     * @brief       Returns the label's size.
     * @return      The label's size.
     */
    size2
    size() const { return _size; }
    
    /*!
     * @}
     */
    
    // MARK: -
    // MARK: Setters
    
    /*!
     * @name        Changing a Label's visual properties
     * @{
     */
    
    /*!
     * @brief       Sets the label's text.
     * @param       text        The label's text, encoded in UTF8.
     * @see         text()
     */
    void
    setText(const std::string& text) {
        if(text!=_text) {
            _text = text; _textureDirty = true;
        }
    }
    
    /*!
     * @brief       Sets the label's font filename.
     * @param       fontName    The label's font filename.
     * @see         font()
     */
    void
    setFont(const std::string& fontName) {
        if(fontName!=_fontName){
            _fontName = fontName; _textureDirty = true;
        }
    }
    
    /*!
     * @brief       Sets the label's font size.
     * @param       size        The label's font size.
     * @see         fontSize()
     */
    void
    setFontSize(int size) {
        if(size!=_fontSize) {
            _fontSize = size; _textureDirty = true;
        }
    }
    
    /*!
     * @brief       Sets the label's font color.
     * @param       color       The label's font color.
     * @see         fontColor()
     */
    void
    setFontColor(const Color& color) {
        if(color!=_fontColor) {
            _fontColor = color; _textureDirty = true;
        }
    }
    
    /*!
     * @brief       Sets the label's rendering quality.
     * @param       aa          The label's antialising setting.
     * @see         fontAA()
     */
    void
    setFontAA(bool aa) { _antialias = aa; }
    
    /*!
     * @brief       Sets The vertical position of the text relative to the node's position.
     * @param       mode        The vertical position of the text relative to the node's position.
     * @see         verticalAlignmentMode()
     */
    void
    setVerticalAlignmentMode(VerticalAlignmentMode mode);
    
    /*!
     * @brief       Sets The horizontal position of the text relative to the node's position.
     * @param       mode        The horizontal position of the text relative to the node's position.
     * @see         horizontalAlignmentMode()
     */
    void
    setHorizontalAlignmentMode(HorizontalAlignmentMode mode);
    
    /*!
     * @brief       The label's blend color.
     * @param       color       The label's blend color.
     * @see         color()
     */
    void
    setColor(const Color& color) {
        _color = color;
    }
    
    /*!
     * @}
     */
    
    // MARK: -
    // MARK: Drawing functions
    
    /*!
     * @internal
     * @brief       Draws the label onto the renderer.
     * @param       renderer    Reference to the current renderer used by the game
     */
    void
    draw(RendererProtocol& renderer) override;
    
    
private:
    
    void
    invalidateCachedTransform() const override;
    
    ARC<TextureProtocol>
    renderedText();
    
    /*!
     * @brief           The font's name.
     */
    std::string         _fontName;
    
    /*!
     * @brief           The displayed text.
     */
    std::string         _text;
    
    /*!
     * @brief           The label's font size.
     */
    int                 _fontSize;
    
    /*!
     * @brief           The label's text color.
     */
    Color               _fontColor;
    
    /*!
     * @brief           The label's blending color
     */
    Color               _color;
    
    /*!
     * @brief           The point in the sprite that corresponds to the node’s position.
     */
    vec2               _anchorPoint;
    
    /*!
     * @brief           Hardware texture.
     */
    ARC<TextureProtocol>_texture;
    
    /*!
     * @brief           Wether the texture needs to be recalculated.
     */
    mutable bool        _textureDirty;
    
    /*!
     * @brief           The label's size
     */
    size2              _size;
    
    /*!
     * @brief           The node's bounding box.
     */
    mutable Rect        _frame;
    
    /*!
     * @brief           Determine wether's the cached frame is valid.
     */
    mutable bool        _frameDirty;
    
    /*!
     * @brief           text's rendering quality
     */
    bool                _antialias;
    
};



NS_END

#endif /* LabelNode_hpp */
