/* c-basic-offset: 2; tab-width: 2; indent-tabs-mode: nil
 * vi: set shiftwidth=2 tabstop=2 expandtab:
 * :indentSize=2:tabSize=2:noTabs=true:
 */


/* This file, as the rest of the project is under MIT license.
 * see http://opensource.org/licenses/MIT
 *
 * Author Gustav Hartvigsson <gustav.hartvigsson _at_ gmail.com> 2014
 */

#ifndef __H_GAME_OBJECT__
#define __H_GAME_OBJECT__

#include <SDL2/SDL.h>
#include <stdbool.h>

#include "defs.h"
#include "Object.h"

/** @file
 * GameObject is the base class for game objects, it provides a set
 * of methods that make it easy to handle drawing and moving of objects in
 * the game.
 *
 * All game objects that require drawing to the screen should be a "subclass"
 * of this.
 *
 * @warning A GameObject contains no data, only the primaries for handling
 *          game objects.
 */

BEGIN_DECLS

#ifndef DOXYGEN_SHOULD_SKIP_THIS
typedef struct GameObject GameObject;
typedef struct GameObjectClass GameObjectClass;
#endif /* DOXYGEN_SHOULD_SKIP_THIS */

/******************************************************************************
 * Function pointer declarations.
 *****************************************************************************/
 
typedef void (* GameObjectCallbackFunc)(GameObject * self, _pointer data);

typedef void (* GameObjectDrawFunc)(GameObject * self, SDL_Renderer * renderer);

typedef void (* GameObjectCallbackHandlerFunc)(GameObject * self, char * name);

typedef void (* GameObjectSetCallbackFunc)(GameObject * self, char * name,\
                                      GameObjectCallbackFunc callback_func,
                                      _pointer data);

typedef void (* GameObjectMoveFunc)(GameObject * self);

typedef void (* GameObjectSetMovementDeltaFunc)(GameObject * self, int delta_x,\
                                      int delta_y, Uint32 time_delta);

typedef SDL_Rect (* GameObjectGetBoundingBoxFunc)(GameObject * self);

typedef bool (* GameObjectGetIsAliveFunc)(GameObject * self);

typedef bool (* GameObjectGetIsCollideFunc)(GameObject * self,
                                            GameObject * other);

typedef void (* GameObjectSetVisibleFunc)(GameObject * self, bool visible);

typedef bool (* GameObjectGetVisibleFunc)(GameObject * self);

/******************************************************************************
 * Object declaration.
 *****************************************************************************/

/**
 * The class for the GameObject.
 */
typedef struct GameObjectClass {
  /** The Parent Class */
  ObjectClass                            parent;
  /** The callback handler */
  GameObjectCallbackHandlerFunc          callback_handler_func;
  /** Method used to set a callback on a GameObject */
  GameObjectSetCallbackFunc              set_callback_func;
  /** The method that is used to draw a GameObject */
  GameObjectDrawFunc                     draw_func;
  /** The method to be run when <tt>game_object_move ()</tt> is run. */
  GameObjectMoveFunc                     move_func;
  /** The method that handles how objects move over time */
  GameObjectSetMovementDeltaFunc         set_movement_delta_func;
  /** The method that returns the bounding box of an object, if available. */
  GameObjectGetBoundingBoxFunc           get_bounding_box_func;
  /** Gets weather a game object is "alive" or "dead" */
  GameObjectGetIsAliveFunc               get_is_alive_func;
  /** The method that determines if a Game Object is colliding with an other
   * game object or not.
   */
  GameObjectGetIsCollideFunc             get_is_collide_func;
  /** This method sets the visiblillity of the GameObject */
  GameObjectSetVisibleFunc               set_visible_func;
  /** This method is used to get the visiblillity of an object. */
  GameObjectGetVisibleFunc               get_visible_func;
} GameObjectClass;

/**
 * Instance of a GameObject.
 */
typedef struct GameObject {
  Object parent;
  /** Is the object visible? */
  bool visible;
} GameObject;



/******************************************************************************
 * Game Object base functions.
 *****************************************************************************/

/**
 * Initialises a GameObject
 *
 * This function should be run on every "sub instance" of a GameObject.
 *
 * @warning It is important to note that like object_initialize, this one does
 * not allocate any memory. This is left up to the caller.
 */
void game_object_initialize (GameObject * self, char * name, _pointer klass);

/**
 * Initialises a GameObjectClass.
 *
 * This should be run on every "sub class" of a GameObjectClass before the
 * sub instance has its own methods and data set.
 *
 * @warning Like <tt>object_class_initialize</tt> this does not allocate any
 * memory for the objects, that is left to the caller.
 *
 * Also see Object for more information.
 *
 * @param klass The class to industrialise.
 * @param callback_handler_func The method used to do callbacks.
 * @param draw_func The Method used to draw a GameObject.
 * @param set_callback_func The method used to hook up callbacks.
 * @param move_func The method used to move an object. It takes no parameters.
 * @param set_movement_delta_func The method used to set how a object should
 *                                move.
 * @param get_bounding_box_func The method used for getting the bounding box of
 *                              a GameObject.
 * @param get_is_alive_func The method used to determin if an obejct is alive or
 *                          not.
 * @param get_is_collide_func The method used to determin if an GameObject has
 *                            collided with an other GameObject.
 * @param set_visible_func The method used to set the visiblillity of a
                           GameObject. If NULL it will use a standard method.
 * @param get_visible_func The method used to check if a GameObject is visible
 *                        or not. If NULL it will use standard method.
 */
void game_object_class_initialize (GameObjectClass *    klass,
                             NewFunc                    new_func,
                             FreeFunc                   free_func,
                             ToStringFunc               to_string_func,
                             GameObjectCallbackHandlerFunc
                                                          callback_handler_func,
                             GameObjectDrawFunc         draw_func,
                             GameObjectSetCallbackFunc  set_callback_func,
                             GameObjectMoveFunc         move_func,
                             GameObjectSetMovementDeltaFunc
                                                        set_movement_delta_func,
                             GameObjectGetBoundingBoxFunc
                                                        get_bounding_box_func,
                             GameObjectGetIsAliveFunc   get_is_alive_func,
                             GameObjectGetIsCollideFunc get_is_collide_func,
                             GameObjectSetVisibleFunc   set_visible_func,
                             GameObjectGetVisibleFunc   get_visible_func
                             );

void game_object_draw (GameObject * self, SDL_Renderer * renderer);

void game_object_move (GameObject * self);

void game_object_set_movement_delta (GameObject * self, int delta_x,
                                                     int delta_y, uint32_t d_t);

bool game_object_get_is_alive (GameObject * self);

void game_object_set_callback (GameObject * self, char * name,
                               GameObjectCallbackFunc callback_func,
                               _pointer data);

void game_object_do_callback (GameObject * self, char * name);

void game_object_set_visible (GameObject * self, bool visible);

bool game_object_get_visible (GameObject * self);

#if 0
/******************************************************************************
 * Game Object set virtual function functions.
 *****************************************************************************/

void game_object_set_callback_handler_func (GameObject * self,
                           GameObjectCallbackHandlerFunc callback_handler_func);

void game_object_set_add_callback_func (GameObject * self,
                                   GameObjectSetCallbackFunc add_callback_func);

void game_object_set_move_func (GameObject * self,
                                GameObjectMoveFunc move_func);

void game_object_set_set_move_delta_func (GameObject * self,
                          GameObjectSetMovementDeltaFunc set_movent_delta_func);

void game_object_set_get_bounding_box_func (GameObject * self,
                            GameObjectGetBoundingBoxFunc get_bounding_box_func);

void game_object_set_movment_delta (GameObject * self, int delta_x,
                                    int delta_y, uint32_t delta_time);

void game_object_set_get_is_alive_func (GameObject * self,
                                    GameObjectGetIsAliveFunc get_is_alive_func);

void game_object_set_is_collide_func (GameObject * self,
                                   GameObjectGetIsCollideFunc is_collide_func);
#endif

END_DECLS

#endif /* __H_GAME_OBJECT__ */
