//
//  SpriteNode.h
//  Meteor
//
//  Created by Cesar Parent on 17/07/2015.
//  Copyright (c) 2015 Cesar Parent. All rights reserved.
//

#ifndef __Meteor__SpriteNode__
#define __Meteor__SpriteNode__

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

NS_BEGIN

/*!
 * @class           SpriteNode
 * @ingroup         GameObjects
 * @brief           A node that draws a texture loaded from an image, blended with a color.
 */
class SpriteNode : public Node {
    
public:
    
    /*!
     * @name        Creating and Saving a Sprite.
     * @{
     */
    
    /*!
     * @brief       Creates a sprite from an image file.
     * @param       imageName   The file path to the image in the app's resource directory.
     */
    SpriteNode(const std::string& imageName);
    
    /*!
     * @brief       Creates a sprite from the data contained in a <code>DecoderProtocol</code>
     *              object.
     * @param       coder       Decoder that contains a serialized node.
     * @see         encodeWithCoder(EncoderProtocol*)
     */
    SpriteNode(DecoderProtocol* coder);
    
    /*!
     * @brief       Serializes the sprite to an <code>EncoderProtocol</code> object.
     * @param       coder       Encoder object to serialize to.
     * @see         SpriteNode(DecoderProtocol*)
     */
    virtual void
    encodeWithCoder(EncoderProtocol* coder) override;
    
    /*!
     * @}
     */
    
    ~SpriteNode();
    
    // MARK: -
    // MARK: Getters
    
    /*!
     * @name        Inspecting the Sprite's texture.
     * @{
     */
    
    /*!
     * @brief       Returns the sprite's blending mode.
     * @return      The sprite's blending mode.
     * @see         setBlendMode(TextureProtocol::BlendMode)
     */
    TextureProtocol::BlendMode
    blendMode() const { return _texture->blendMode(); }
    
    /*!
     * @brief       Returns the sprite's color.
     * @return      The sprite's color.
     * @see         setColor(const Color&)
     */
    Color
    color() const { return _texture->color(); }
    
    /*!
     * @brief       Returns the area of the texture drawn by the sprite.
     * @return      The area of the texture drawn by the sprite.
     * @see         setClipRect(const Rect&)
     */
    Rect
    clipRect() const { return _texture->clippingQuad(); }
    
    /*!
     * @brief       Returns a constant pointer to the sprite's texture.
     * @return      A constant pointer to the sprite's texture.
     */
    const ARC<TextureProtocol>
    texture() const { return _texture; }
    
    /*!
     * @}
     * @name        Inspecting the Sprite's physical properties.
     * @{
     */
    
    /*!
     * @brief       Returns the point in the sprite that corresponds to the node’s position.
     * @return      The point in the sprite that corresponds to the node’s position.
     * @see         setAnchorPoint(const vec2&)
     */
    vec2
    anchorPoint() const { return _anchorPoint; }
    
    /*!
     * @brief       Returns the dimensions of the sprite in pixels.
     * @return      The dimensions of the sprite in pixels.
     * @see         setClipRect(const Rect&)
     * @see         frame()
     */
    size2
    size() const { return size2(clipRect().w, clipRect().h); }
    
    /*!
     * @brief       Returns the node's bounding rectangle.
     * @return      The node's bounding rectangle.
     * @see         setClipRect(const Rect&)
     * @see         size()

     */
    Rect
    frame() const;
    
    /*!
     * @}
     */
    
    // MARK: -
    // MARK: Setters
    
    /*!
     * @name        Editing the Sprite's texture.
     * @{
     */
    
    /*!
     * @brief       Sets the sprite's blending mode
     * @param       blendMode   The sprite's blending mode.
     * @see         blendMode()
     */
    void
    setBlendMode(TextureProtocol::BlendMode blendMode) {
        _texture->setBlendMode(blendMode);
    }
    
    /*!
     * @brief       Set the sprite's color.
     * @param       color       The sprite's color.
     * @see         color()
     */
    void
    setColor(const Color& color) { _texture->setColor(color); }
    
    /*!
     * @brief       Set the area of the texture drawn by the sprite.
     * @param       clipRect    the area of the texture drawn by the sprite.
     * @see         clipRect()
     */
    void
    setClipRect(const Rect& clipRect) { _texture->setClippingQuad(clipRect); _frameDirty = true; }
    
    /*!
     * @}
     * @name        Changing the Sprite's physical properties
     * @{
     */
    
    /*!
     * @brief       Set the point in the sprite that corresponds to the node’s position.
     * @param       anchor      The sprites's anchor point.
     * @see         anchorPoint()
     */
    void
    setAnchorPoint(const vec2& anchor) { _anchorPoint = anchor; _frameDirty = true; }
    
    /*!
     * @brief       Set the point in the sprite that corresponds to the node’s position.
     * @param       x           The anchor point's x coordinate.
     * @param       y           The anchor point's y coordinate.
     * @see         anchorPoint()
     */
    void
    setAnchorPoint(float x, float y) { setAnchorPoint({x, y}); }
    
    /*!
     * @internal
     */
    void
    invalidateCachedTransform() const override;
    
    /*!
     * @internal
     * @brief       Draws the sprite on the renderer.
     * @param       renderer    Reference to the current renderer used by the game.
     */
    void
    draw(RendererProtocol& renderer) override;
    
    /*!
     * @}
     */
    
private:
    
    /*!
     * @brief           The point in the sprite that corresponds to the node’s position.
     */
    vec2               _anchorPoint;
    
    /*!
     * @brief           Hardware texture.
     */
    ARC<TextureProtocol> _texture;
    
    /*!
     * @brief           The spritesheet's filename, for encoding/decoding purposes.
     */
    std::string         _textureName;
    
    /*!
     * @brief           The node's bounding box.
     */
    mutable Rect        _frame;
    
    /*!
     * @brief           Determine wether's the cached frame is valid.
     */
    mutable bool        _frameDirty;
    
};

NS_END

#endif /* defined(__Meteor__SpriteNode__) */
