/*
 * Author: Andrew Robberts
 *
 * Copyright (C) 2003 Atomic Blue (info@planeshift.it, http://www.atomicblue.org)
 *
 *
 * 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 (version 2 of the License)
 * 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.
 *
 */
 
#ifndef PS_EFFECT_MANAGER_HEADER
#define PS_EFFECT_MANAGER_HEADER


// CS includes
#include <csutil/csstring.h>
#include <csutil/array.h>
#include <csutil/parray.h>
#include <csutil/ref.h>
#include <iutil/virtclk.h>
#include <csutil/hash.h>
#include <imap/reader.h>

struct iSector;
struct iSectorList;
struct iMeshWrapper;
struct iRegion;
struct iView;
struct iMovable;
class psEffect;

class psEffectGroup
{
public:
    csString name;
    csArray<csString> effects;
};

class psEffectManager : public scfImplementation1<psEffectManager,iLoaderPlugin>
{
public:
    psEffectManager();
    virtual ~psEffectManager();

    // used to handle and parse the <addon> tags.
    csPtr<iBase> Parse(iDocumentNode * node, iStreamSource*, iLoaderContext * ldr_context, iBase * context);
   
    /** loads one or more gfx effects from a file
     *   @param fileName the vfs path to the file that holds the spell effect
     *   @param parentView the CS viewport that views the effects
     *   @return true on success, false otherwise
     */
    bool LoadEffects(const csString & fileName, iView * parentView);

    /** loads the effect files listed in the given effects list
     *   @param fileName the vfs path to the file that holds the effects list
     *   @param parentView the CS viewport that views the effects
     *   @return true on success, false otherwise
     */
    bool LoadFromEffectsList(const csString & fileName, iView * parentView);

    /** Loads all effect files that can be found in a directory path.
     *   \param path            The vfs path to search.
     *   \param includeSubDirs  If True, it will extend its search into subdirectories.
     *   \param parentView      The CS viewport that views the effects.
     *   \return                True on success, false otherwise.
     */
    bool LoadFromDirectory(const csString & path, bool includeSubDirs, iView * parentView);

    /** deletes an effect
     *   @param effectID the unique ID of the effect (as returned by RenderEffect())
     *   @return true if the effect manager no longer contains an effect by that ID, false if there was a problem
     */
    bool DeleteEffect(unsigned int effectID);

    /** begins rendering of an effect that is attached to an iMeshWrapper
     *   @param effectName the name of the effect to render
     *   @param offset the position offset of the effect from the attached object
     *   @param attachPos the object to attach the effect to
     *   @param attachTarget the target of the effect, 0 assumes that the target is the same as the attachPos
     *   @param up the base up vector of the effect
     *   @param uniqueID overrides the unique ID of the effect (for things like group effects)
     *   @return 0 on failure, a unique ID of the effect otherwise
     */
    unsigned int RenderEffect(const csString & effectName, const csVector3 & offset, iMeshWrapper * attachPos, 
                              iMeshWrapper * attachTarget=0, const csVector3 & up=csVector3(0,1,0), 
                              const unsigned int uniqueIDOverride = 0);

    /** begins rendering an effect that isn't attached to anything
     *   @param effectName the name of the effect to render
     *   @param sector the starting sector of the new effect
     *   @param pos the position of the new effect
     *   @param target the target of the effect, 0 assumes that the target is the same as the offset
     *   @param up the base up vector of the effect
     *   @param uniqueID overrides the unique ID of the effect (for things like group effects)
     *   @return 0 on failure, a unique ID of the effect otherwise
     */
    unsigned int RenderEffect(const csString & effectName, iSector * sector, const csVector3 & pos, 
                              iMeshWrapper * attachTarget, const csVector3 & up=csVector3(0,1,0), 
                              const unsigned int uniqueIDOverride = 0);

    /** begins rendering an effect that isn't attached to anything
     *   @param effectName the name of the effect to render
     *   @param sectors the sectors the new effect is in
     *   @param pos the position of the new effect
     *   @param target the target of the effect, 0 assumes that the target is the same as the offset
     *   @param up the base up vector of the effect
     *   @param uniqueID overrides the unique ID of the effect (for things like group effects)
     *   @return 0 on failure, a unique ID of the effect otherwise
     */
    unsigned int RenderEffect(const csString & effectName, iSectorList * sectors, const csVector3 & pos, 
                              iMeshWrapper * attachTarget=0, const csVector3 & up=csVector3(0,1,0), 
                              const unsigned int uniqueIDOverride = 0);

    /** updates the spell effects (should be called every frame)
     *   @param elapsed the time in ms that has elapsed
     */
    void Update(csTicks elapsed = 0);
    
    /** Prepares the effects -- do this once after load, but before render loop.
     *   @return true if effects are successfully prepared, false otherwise
     */
    bool Prepare();

    /** Clears all effects.
     */
    void Clear();

    /** Gets the effect with the given ID.
     *   @param ID the id of the effect (the value returned by RenderEffect)
     *   @return a reference to the effect, 0 if the effect could not be found
     */
    psEffect * FindEffect(unsigned int ID) const;
    
    /** finds an effect by the given name
     *   @param name the name of the effect to find
     *   @return the effect if it found it, null if not
     */
    psEffect * FindEffect(const csString &name) const;

    /** Gets a global iterator that will iterate over all effect factories.
     *   @return the iterator.
     */
    csHash<psEffect *, csStrKey>::GlobalIterator GetEffectsIterator();
    

    /** Hide or Show the effect
     *   @param effect ID
     *   @param show or hide
     */
    void ShowEffect(unsigned int id,bool value = true);

private:

    /// Virtual clock to keep track of the ticks passed between frames.
    csRef<iVirtualClock> vc;

    /**
     * The collection of effects that don't do anything themselves, they're just ready to be quickly copied when a 
     * new effect is needed.
     */
    csHash<psEffect *, csStrKey> effectFactories;

    /// the actual effects that are seen
    csHash<psEffect *> actualEffects;
//    csPDelArray<psEffect> actualEffects;

    /// effects have their own region to make them easier to manage
    csRef<iRegion> region;

    iView * view;
};

#endif
