//
//  CodingProtocol.h
//  Meteor
//
//  Created by Cesar Parent on 05/09/2015.
//  Copyright © 2015 Cesar Parent. All rights reserved.
//

#ifndef CodingProtocol_h
#define CodingProtocol_h

#include "Value.h"
#include "../defines.h"
#include "../CPFoundation.h"
#include "../Geometry.h"
#include "../Graphics.h"

NS_BEGIN

class EncoderProtocol;
class DecoderProtocol;

/*!
 * @interface       CodingProtocol
 * @ingroup         Foundation Filesystem
 * @brief           Defines an object that can be serialized through the use of an Encoder.
 */
class CodingProtocol : public virtual CPObjectProtocol {
public:
    
    /*!
     * @brief       Archives an object to a concrete Encoder object.
     * @details     Objects implementing CodingProtocol should use this method to save any property
     *              that cannot be calculated at runtime. If an object needs to be decodable, it
     *              should implement a constructor that takes a DecoderProtocol object as parameter.
     * @note        The object does not own the Encoder passed to it.
     * @param       coder       The encoder to archive to.
     */
    virtual void
    encodeWithCoder(EncoderProtocol* coder) = 0;
};

/*!
 * @interface       EncoderProtocol
 * @ingroup         Foundation Filesystem
 * @brief           Encoders provide ways to save data from memory to different kinds of archives,
 *                  and are used to serialize objects. Objects that want to be serializable must
 *                  implement <code>CodingProtocol</code>
 */
class EncoderProtocol {
public:
    
    /*!
     * @brief       Save a boolean value to the archive.
     * @param       value       Boolean value.
     * @param       key         Key used to tag the value in the archive.
     */
    virtual void
    encodeBoolWithKey(bool value, const std::string& key) = 0;
    
    /*!
     * @brief       Save an integer value to the archive.
     * @param       value       Integer value.
     * @param       key         Key used to tag the value in the archive.
     */
    virtual void
    encodeIntegerWithKey(int value, const std::string& key) = 0;
    
    /*!
     * @brief       Save a real value to the archive.
     * @param       value       Real (double) value.
     * @param       key         Key used to tag the value in the archive.
     */
    virtual void
    encodeRealWithKey(double value, const std::string& key) = 0;
    
    /*!
     * @brief       Save a string value to the archive.
     * @param       value       String value.
     * @param       key         Key used to tag the value in the archive.
     */
    virtual void
    encodeStringWithKey(const std::string& value, const std::string& key) = 0;
    
    /*!
     * @brief       Save an array value to the archive.
     * @param       value       Array value.
     * @param       key         Key used to tag the value in the archive.
     */
    virtual void
    encodeArrayWithKey(const std::vector<Value>& value, const std::string& key) = 0;
    
    /*!
     * @brief       Save an dictionary value to the archive.
     * @param       value       Dictionary value.
     * @param       key         Key used to tag the value in the archive.
     */
    virtual void
    encodeDictionaryWithKey(const std::map<std::string, Value>& value, const std::string& key) = 0;
    
    /*!
     * @brief       Save a vector as an array of its members.
     * @param       value       Vector object.
     * @param       key         Key used to tag the value in the archive.
     */
    virtual void
    encodeVectorWithKey(const vec2& value, const std::string& key) = 0;
    
    /*!
     * @brief       Save a color as an array of its members.
     * @param       value       Color object.
     * @param       key         Key used to tag the value in the archive.
     */
    virtual void
    encodeColorWithKey(const Color& value, const std::string& key) = 0;
    
    /*!
     * @brief       Save a rectangle as an array of its members.
     * @param       value       Rect object.
     * @param       key         Key used to tag the value in the archive.
     */
    virtual void
    encodeRectWithKey(const Rect& value, const std::string& key) = 0;
    
};

/*!
 * @interface       DecoderProtocol
 * @ingroup         Foundation Filesystem
 * @brief           Decoders provide ways to extract data from an archive created with Coders.
 */
class DecoderProtocol {
public:
    
    /*!
     * @brief       Decode a value as a boolean. If there is no boolean value for that key,
     *              false will be returned.
     * @param       key         Key to look for in the archive.
     * @return      Boolean value for the given key.
     */
    virtual bool
    decodeBoolForKey(const std::string& key) = 0;
    
    /*!
     * @brief       Decode a value as an integer. If there is no integer value for that key,
     *              0 will be returned.
     * @param       key         Key to look for in the archive.
     * @return      Integer value for the given key.
     */
    virtual int
    decodeIntegerForKey(const std::string& key) = 0;
    
    /*!
     * @brief       Decode a value as an real (double). If there is no double value for that key,
     *              0 will be returned.
     * @param       key         Key to look for in the archive.
     * @return      Double value for the given key.
     */
    virtual double
    decodeRealForKey(const std::string& key) = 0;
    
    /*!
     * @brief       Decode a value as a string. If there is no string value for that key,
     *              an empty string will be returned.
     * @param       key         Key to look for in the archive.
     * @return      String value for the given key.
     */
    virtual std::string
    decodeStringForKey(const std::string& key) = 0;
    
    /*!
     * @brief       Decode a value as an array. If there is no array value for that key,
     *              an empty array will be returned.
     * @param       key         Key to look for in the archive.
     * @return      Array value for the given key.
     */
    virtual std::vector<Value>
    decodeArrayForKey(const std::string& key) = 0;
    
    /*!
     * @brief       Decode a value as a dictionary. If there is no dictionary value for that key,
     *              an empty dictionary will be returned.
     * @param       key         Key to look for in the archive.
     * @return      Dictionary value for the given key.
     */
    virtual std::map<std::string, Value>
    decodeDictionaryForKey(const std::string& key) = 0;
    
    /*!
     * @brief       Decode a value as a vector. If there is no vector value for that key,
     *              an error will be thrown.
     * @param       key         Key to look for in the archive.
     * @return      Vector value for the given key.
     */
    virtual vec2
    decodeVectorForKey(const std::string& key) = 0;
    
    /*!
     * @brief       Decode a value as a color. If there is no color value for that key,
     *              an error will be thrown.
     * @param       key         Key to look for in the archive.
     * @return      Color value for the given key.
     */
    virtual Color
    decodeColorForKey(const std::string& key) = 0;
    
    /*!
     * @brief       Decode a value as a rectangle. If there is no rectangle value for that key,
     *              an error will be thrown.
     * @param       key         Key to look for in the archive.
     * @return      Rectangle value for the given key.
     */
    virtual Rect
    decodeRectForKey(const std::string& key) = 0;
};

NS_END

#endif /* CodingProtocol_h */
