/***************************************************************************
 *   Copyright (C) 2006 by Harish Kukreja                                  *
 *   harish.kukreja@gmail.com                                              *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

//
// C++ Interface: universe
//
// Description: Declarations for Physiks' 'Universe' class and its members
//
//
// Author: Harish Kukreja <harish.kukreja@gmail.com>, (C) 2006
//
// Copyright: See COPYING file that comes with this distribution
//
//


#ifndef _PHYSIKS_UNIVERSE_H_
#define _PHYSIKS_UNIVERSE_H_


#include "physiks_export.h"
#include "globaldefs.h"

#include <vector>

using namespace std;

namespace Physiks {

class PhysicalObject;
class Vector;

/** A Universe encapsulates all information about fields, objects and parameters
 * of the physical environment. Force fields and objects (among other things)
 * are registered in a specific universe instance, and integration is initiated
 * via the instance itself. */
class PHYSIKS_EXPORT Universe {
  public:
    /** the dimension of all tuples used for this universe. */
    const u_int dimension;

    /** flag controlling whether or not data should be output (currently 
     * only to stdout). For testing purposes only. */
    bool output;

    /** \brief  Constructor 1.
     * \param dimension the dimension of all tuples used for this 
     *                  universe
     * \param def_timestep  the default timestep of integration */
    Universe(const u_int dimension, PHYSCALAR def_timestep = 0.01);

    virtual ~Universe();

    /** \brief  Adds an object to the calling universe's list of active 
     *          objects.
     * \param obj the object to be added */
    void add_object(const PhysicalObject &obj);

    /** \brief Performs a single iteration of the given timestep and updates
     * all universe parameters.
     * \param step_size the time-step over which forces are to be applied. 
     *                  Default value of 0.0 corresponds to the default 
     *                  step size for the Universe instance. */
    void step(PHYSCALAR step_size = 0.0);

    void integrate(const u_long num_steps);

    /** \brief  References the object at the specific index in the object 
     *          table.
     * \param   index the index of the queried object in this universe's 
     *          object table
     * \return  a pointer to the queried object. <b>The object is modifiable
     *          through the returned pointer.</b>    */
    PhysicalObject *object(const u_int index) const;


  protected:
    /** Default time step used for integration. Not constant to enable 
     * runtime modification. */
    PHYSCALAR timestep;

    /** A table of all objects in the universe. */
    vector<PhysicalObject *> objects;

    /** A table of the net-force vectors for each object in the universe */
    vector<Physiks::Vector *> forces;

    /** \brief  Updates the force vectors for each object in the universe, 
     * using the selected computation algorithm (currently only Euler).   */
    void update_forces();

    /** \brief  Updates the velocity vectors of each object in the universe
     *          using Euler's algorithm.
     * \param tstep the timestep fed to the Euler algorithm */
    void euler_update_velocities(const PHYSCALAR tstep);

    /** \brief  Updates the position vectors of each object in the universe
     *          using Euler's algorithm.
     * \param tstep the timestep fed to the Euler algorithm */
    void euler_update_positions(const PHYSCALAR tstep);
};

}   // End of namespace Physiks

#endif
