/*
	Wheels Of Steel
	Copyright (c) 2006, Darragh Coy.
	All rights reserved.
	Original work(s), source code & author(s) details available at: http://www.darraghcoy.com

	Redistribution and use in source and binary forms, with or without modification, are permitted 
	provided that the following conditions are met:

		* 	Redistributions of source code must retain the above copyright notice, this list of 
			conditions and the following disclaimer.
		* 	Redistributions in binary form must reproduce the above copyright notice, this list of 
			conditions and the following disclaimer in the documentation.
		* 	Neither the name of the author nor the names of contributors may be used to endorse or 
			promote products derived from this software without specific prior written permission.
		* 	The use of any third party libraries, modules or data files provided with the source 
			form of the program must follow and respect the individual licensing terms of these 
			components. You do not have permission to modify or circumvent the licensing terms for 
			provided third party components unless the third party licenses specifically allow this. 
			If you do not agree to the terms of provided third party components then you do not have 
			permission to use them in your derived work(s).
		* 	The terms of this license do not apply to separate (but related) distributions if supplied 
			by the author(s), only to the contents of this source distribution, derived works, and the 
			binaries produced by either modified or unmodified versions of the source code. The terms 
			of this license do not also apply to any third party libraries or components provided with 
			the source distribution. Such third party elements are licensed under their own separate 
			agreements.

	THIS SOFTWARE IS PROVIDED BY DARRAGH COY ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
	BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
	ARE DISCLAIMED. IN NO EVENT SHALL DARRAGH COY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
	EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
	OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
	OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
	IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef GAMEOBJECTMANAGER_H
#define GAMEOBJECTMANAGER_H

//##############################################################################
// C Includes
//##############################################################################

#include "ProgramError.h"
#include <math.h>

//##############################################################################
// Forward declarations
//##############################################################################

class Timer;
class Track;
class TrackSection;
class GameObject;

//##############################################################################
//##############################################################################
//##############################################################################
//##############################################################################
//
//
// Class Name:   GameObjectManager
// Purpose:      Keeps track of all the objects in the game. Handles things like
//               spatial partitioning (assigning objects to track sections) and
//               collision detection, gravity, and event dispatching
//
//##############################################################################
//##############################################################################
//##############################################################################
//##############################################################################

class GameObjectManager
{

 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Public functions and data
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

 public:

        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // Functions
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        static void initObjects(Track * track);         // initialise the game object manager: sets all objects contained to null
        static void freeObjects();                      // delete all the objects in the array and remove their references
        static void moveObjects( float frameTime );     // moves all objects and does collision dection and such. basically all the physical simulation is done here.
        static void addObject( GameObject * object );   // add an object to the list of objects managed by the manager
        static void delObject( GameObject * object );   // remove an object from the list of objects managed by the manager

//##############################################################################
//##############################################################################
//##############################################################################
//##############################################################################

 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Private functions and data
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

private:

        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // Constants
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        // Maximum number of objects the game can support

        static const unsigned int MAX_OBJECTS = 0xffff;

        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // Structures
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        // Data that is kept during the testing, and passed to collision testing functions.

        typedef struct CollisionTestData
        {
            GameObject * xCollidee;     // object that the collider has collided along the x-axis
            GameObject * yCollidee;     // object that the collider has collided along the y-axis
            GameObject * zCollidee;     // object that the collider has collided along the z-axis

            float allowedX;             // X value the object is currently allowed to move to
            float allowedY;             // Y value the object is currently allowed to move to
            float allowedZ;             // Z value the object is currently allowed to move to
        };

        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // Variables
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        // The null terminated arrays of game objects: both moveable objects and static objects

        static GameObject * objArrayStatic[MAX_OBJECTS];
        static GameObject * objArrayMoving[MAX_OBJECTS];

        // An array to hold objects that have not been deleted immediately after being sent to the
        // delObject function, because the moveObjects function is underway and they cannot be deleted
        // to avoid messing with the game state. All these objects are deleted as soon as that function ends..

        static GameObject * objArrayDelayedDeletes[MAX_OBJECTS];

        // Count of the number of objects in the static, moveable, and delayed delete objects array

        static unsigned int objCountStatic;
        static unsigned int objCountMoving;
        static unsigned int objCountDelayedDeletes;

        // Track that holds all the objects

        static Track * track;

        // Is the game object manager currently moving objects ?

        static bool movingAllObjects;

        // Static helper variables

        static float frictionAir;           // friction multiplier for slowdown in the air
        static float frictionTrack;         // friction multiplier for slowdown when on the track
        static float frictionGround;        // friction multiplier for slowdown when in the grass
        static float frameTime;             // Time the last frame took in seconds
        static float gravity;               // Amount of downwards pull to apply for this frame

        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // Functions
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        static void           assignTrackReference  ( GameObject * object );  // assign the object to all the track sections it crosses
        static void           removeTrackReference  ( GameObject * object );  // remove references of the object from all the sections it crosses
        static GameObject **  getPotentialColliders ( GameObject * object );  // Get a null terminated list of objects this object could collide with

        // Check the object for collision against the track section and correct its position

        static void performTrackCollision(GameObject * object);

        // Object to solid object collision checking functions

        static void performObjectCollision_front    // Check the front of the collider against the back of the collidee                                                     // for collision along movement
        (
            GameObject          * collider,
            GameObject          * collidee,
            CollisionTestData   * collisionData
        );

        static void performObjectCollision_back     // Check the back of the collider against the front of the collidee                                                     // for collision along movement
        (
            GameObject          * collider,
            GameObject          * collidee,
            CollisionTestData   * collisionData
        );

        static void performObjectCollision_left     // Check the left of the collider against the right of the collidee                                                     // for collision along movement
        (
            GameObject          * collider,
            GameObject          * collidee,
            CollisionTestData   * collisionData
        );

        static void performObjectCollision_right    // Check the right of the collider against the left of the collidee                                                     // for collision along movement
        (
            GameObject          * collider,
            GameObject          * collidee,
            CollisionTestData   * collisionData
        );

        static void performObjectCollision_top     // Check the top of the collider against the bottom of the collidee                                                     // for collision along movement
        (
            GameObject          * collider,
            GameObject          * collidee,
            CollisionTestData   * collisionData
        );

        static void performObjectCollision_bottom  // Check the bottom of the collider against the top of the collidee                                                     // for collision along movement
        (
            GameObject          * collider,
            GameObject          * collidee,
            CollisionTestData   * collisionData
        );

        // Object to non solid object collision path cross checking functions:
        // just check if the object crosses path, doesn't attempt to fix position!
        // also calls collision event on collidee if they cross paths..

        static void performObjectCrossCheck_front   // Check the front of the collider against the back of the collidee                                                     // for collision along movement
        (
            GameObject          * collider,
            GameObject          * collidee,
            CollisionTestData   * collisionData
        );

        static void performObjectCrossCheck_back    // Check the back of the collider against the front of the collidee                                                     // for collision along movement
        (
            GameObject          * collider,
            GameObject          * collidee,
            CollisionTestData   * collisionData
        );

        static void performObjectCrossCheck_left    // Check the left of the collider against the right of the collidee                                                     // for collision along movement
        (
            GameObject          * collider,
            GameObject          * collidee,
            CollisionTestData   * collisionData
        );

        static void performObjectCrossCheck_right   // Check the right of the collider against the left of the collidee                                                     // for collision along movement
        (
            GameObject          * collider,
            GameObject          * collidee,
            CollisionTestData   * collisionData
        );

        static void performObjectCrossCheck_top     // Check the top of the collider against the bottom of the collidee                                                     // for collision along movement
        (
            GameObject          * collider,
            GameObject          * collidee,
            CollisionTestData   * collisionData
        );

        static void performObjectCrossCheck_bottom  // Check the bottom of the collider against the top of the collidee                                                     // for collision along movement
        (
            GameObject          * collider,
            GameObject          * collidee,
            CollisionTestData   * collisionData
        );

}; // end of: class GameObjectManager

//##############################################################################
// C++ Includes
//##############################################################################

#include "Timer.h"
#include "Track.h"
#include "TrackSection.h"
#include "GameObject.h"

#endif // end of: ifndef GAMEOBJECTMANAGER_H
