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

#ifndef __Meteor__SDLRenderer__
#define __Meteor__SDLRenderer__

#include "../sdl_includes.h"
#include "../Geometry.h"
#include "RendererProtocol.h"
#include "SDLTexture.h"
#include <unordered_map>
#include <vector>
#include <string>

NS_BEGIN

/*!
 * @internal
 * @class           SDLRenderer
 */
class SDLRenderer : public CPObject, public RendererProtocol {
    
public:
    
    SDLRenderer(SDL_Window* window, size2 size);
    
    virtual ~SDLRenderer();
    
    /*!
     * @brief       Push a target texture on top of the rendering stack. The renderer will always
     *              render on the top of the stack.
     */
    virtual void
    pushTarget(ARC<TextureProtocol> target);
    
    /*!
     * @brief       Removes the target texture currently on top of the stack.
     *
     */
    virtual void
    popTarget();
    
    /*!
     * @brief       Set the renderer's origin offset. (0, 0) will point to that point on the
     *              current rendering target.
     */
    virtual void
    setOriginMatrix(const mat33& origin);
    
    /*!
     * @brief       Set the algorithm used to interpolate pixel color when rendering.
     * @param       mode        New filtering mode.
     */
    virtual void
    setFilteringMode(FilteringMode mode);
    
    /*!
     * @brief       Returns the current scale filtering mode.
     * @return      Current filtering mode.
     */
    virtual FilteringMode
    setFilteringMode() { return _filteringMode; }
    
    /*!
     * @brief       Returns a copy of the screen's pixels as ARGB bytes. This is used to create
     *              screenshots.
     * @param       size        The size of the returned array of pixels.
     * @return      An array of pixels that can be used to create surfaces.
     */
    virtual bool
    pixels(Uint8 pixels[], int pitch);
    
    virtual size2
    outputSize();
    
    /*!
     * @brief       Renders a line between two points
     * @param       start       Coordinates of the line's starting point.
     * @param       end         Coordinates of the line's end point.
     * @param       color       The line's color.
     */
    virtual void
    renderLine(const vec2& start, const vec2& end, const Color& color);
    
    /*!
     * @brief       Displays a texture on the screen.
     * @param       position    Absolute position of the texture's anchor point in the engine world.
     * @param       anchor      Point of the texture pointed to by the position vector.
     * @param       scale       Horizontal and Vertical scaling factor of the texture.
     * @param       angle       Texture's rotation.
     */
    virtual void
    renderTexture(TextureProtocol* texture,
                  const vec2& position,
                  const vec2& anchor,
                  const vec2& scale,
                  float angle);
    
    /*!
     * @brief       Displays a polygon on the screen.
     * @param       shape       Polygon object to draw.
     * @param       color       Polygon's stroke color.
     * @param       opacity     Polygon's opacity.
     */
    virtual void
    renderPolygon(const Polygon& shape, const Color& color, float opacity);
    
    /*!
     * @brief       Displays a polygon, filled with a color, on the screen
     * @param       shape       Polygon object to draw.
     * @param       color       Polygon's fill color.
     * @param       opacity     Polygon's opacity.
     */
    virtual void
    fillPolygon(const Polygon& shape, const Color& color, float opacity);
    
    /*!
     * @brief       Clears the renderer's view with the given color.
     * @param       color       Color to fill the screen with. Defaults to
     <code>Color::blackColor</code>
     */
    virtual void
    clear(const Color& color = Color::blackColor);
    
    /*!
     * @brief      Displays everything that was rendered since the last call on the screen.
     */
    virtual void
    present();
    
    /*!
     * @brief       Returns an implementation-specific texture from an image's data.
     * @param       image       File name of the image to load.
     * @return      Pointer to a Texture object.
     */
    virtual ARC<TextureProtocol>
    textureFromImage(const std::string& image);
    
    /*!
     * @brief       Returns an implementation-specific texture of a certain size and color.
     * @param       size        Integer size of the texture.
     * @param       color       Color of the texture.
     * @return      Pointer to a Texture object.
     */
    virtual ARC<TextureProtocol>
    textureWithSizeAndColor(const size2& size, const Color& color);
    
    /*!
     * @brief       Returns a texture that can be drawn to by the renderer.
     * @param       size        Integer size of the texture.
     * @return      Pointer to a target texture.
     */
    virtual ARC<TextureProtocol>
    targetTextureWithSize(const size2& size);
    
    /*!
     * @brief       Returns a texture filled with the given text, rendered with the given font.
     * @param       text        The text to render.
     * @param       size        The size of the text to render.
     * @param       color       The color of the text to render.
     * @param       style       A combination of Style bitmasks to render the font with.
     * @return      A texture filled with the rendered text on a transparent background.
     */
    virtual ARC<TextureProtocol>
    textureWithText(const std::string& text,
                    const std::string& font,
                    int size,
                    const Color& color,
                    bool antialiased);
    
    /*!
     * @brief       Flushes the renderer's texture cache.
     *              Cached texture are released, and will only be deallocated if no other object
     *              references them.
     */
    virtual void
    flushTextureCache();
    
private:
    
    TTF_Font*
    loadFont(const std::string& name, int size);
    
    SDL_Renderer*   _renderer;
    
    SDL_Window*     _window;
    
    /*!
     * @brief       Renderers' logical scale (in units, could be scaled before being rendered).
     */
    size2          _size;
    
    /*!
     * @brief       Target space location of the renderer's Origin point.
     */
    mat33           _origin;
    
    /*!
     * @brief       stack of rendering targets.
     */
    std::vector<ARC<SDLTexture>> _targetStack;
    
    /*!
     * @brief       stack or Rendering origins
     */
    std::vector<vec2> _originStack;
    
    /*!
     * @brief       Renderer's filtering mode.
     */
    FilteringMode   _filteringMode;
    
    /*!
     * @brief       Textures loaded from images are stored in the cache for faster reuse
     */
    std::unordered_map<std::string, ARC<SDLTextureRef>> _textureCache;
    
    
    std::unordered_map<std::string, TTF_Font*> _fontCache;
};

NS_END

#endif /* defined(__Meteor__SDLRenderer__) */
