/*****************************************************************************
 * $Id: mod_pony_cloud.hh,v 1.1 2006/11/24 21:56:58 devel Exp $
 * @file
 * @author	Jim E. Brooks  http://www.jimbrooks.org
 * @brief	High-level cloud code.
 *//*
 * LEGAL:	COPYRIGHT (C) 2006 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE (GPL).
 *****************************************************************************/

#if COMPILING_MODULE_PONY
#ifndef MOD_PONY_CLOUD_HH
#define MOD_PONY_CLOUD_HH 1

#include "eng_billboard.hh"

////////////////////////////////////////////////////////////////////////////////
/// Class for cloud factory and parameters.
/// This is orthogonal to Object-derived Cloud classes (isn't their base class).
///
/// In meterology, clouds are described by combined words such as "altocumulus".
/// The C++ class TypeCombo works similarly by combining type enums into one object.
///
/// Some combinations of cloud types are invalid but
/// will normally occur because cloud types are randomly selected.
/// TypeCombo will correct by changing an invalid combo to a valid one.
///
class Cloud
{
PREVENT_COPYING(Cloud)
public:
    // Primary type.
    enum eType1
    {
        eType1_CUMULUS,     // puffy
        eType1_STRATUS,     // sheet

        eType1_DEFAULT = eType1_CUMULUS,
    };

    // Sub-types.
    enum eType2
    {
        eType2_DEFAULT,
        eType2_ALTO,        // high
        eType2_NIMBUS,      // vertical
        eType2_FRACTO,      // fragmented
        eType2_CIRRO,       // curly
        eType2_CIRRUS,      // fibrous
        eType2_RAIN,        // light/medium rain
        eType2_STORM,       // heavy rain, lightning
    };

    // Sub-type: general shape.
    enum eType3
    {
        eType3_DEFAULT,
        eType3_SPHERE,
        eType3_BOX,
        eType3_PYRAMID,
    };

    class TypeCombo
    {
    public:
                TypeCombo( const eType1 type1 = eType1_DEFAULT,
                           const eType2 type2 = eType2_DEFAULT,
                           const eType3 type3 = eType3_DEFAULT );
        void    Set(       const eType1 type1 = eType1_DEFAULT,
                           const eType2 type2 = eType2_DEFAULT,
                           const eType3 type3 = eType3_DEFAULT );
        eType1  GetType1( void ) const { return mType1; }
        eType2  GetType2( void ) const { return mType2; }
        eType3  GetType3( void ) const { return mType3; }

    private:
        eType1  mType1;
        eType2  mType2;
        eType3  mType3;
    };

public:
    static void Factory( const TypeCombo& typeCombo, QuadrantPtr quadrant );

private:
	static void FactoryCumulus( const TypeCombo& typeCombo, QuadrantPtr quadrant );
	static void FactoryCumulusSphere( const TypeCombo& typeCombo, QuadrantPtr quadrant );
	static void FactoryStratus( const TypeCombo& typeCombo, QuadrantPtr quadrant );
};

////////////////////////////////////////////////////////////////////////////////
/// Container that maps cloud parameters with a Billboard object.
///
/// This is meant to be a static member of Object-derived Cloud classes
/// which helps their ctors get a Billboard object associated with a CloudShape.
///
/// CloudShape class must define operator<() for STL.
///
template<typename CloudShape>
class CloudBillboardMap
{
PREVENT_COPYING(CloudBillboardMap)
private:
	typedef CloudShape              Key;
	typedef Billboard*				Val;
	typedef std::map<Key,Val>		Map;
	typedef typename Map::iterator	MapItr;

public:
    CloudBillboardMap( void ) { }
    ~CloudBillboardMap() { }  // omit deleting Billboards (this class will be static members)

	/// @return Existing Billboard or create a new one.
    SafePtr<Billboard>
	GetBillboard( const CloudShape& cloudShape, BillboardOwner& cloud, const Billboard::Parm& billboardParm )
    {
		// Does a Billboard exist associated with these cloud parameters?
		MapItr itr = mMap.find( cloudShape );
        if ( itr == mMap.end() )
		{
			// Create new Billboard.
			Billboard* billboard = new Billboard( cloud, billboardParm );
    		mMap.insert( make_pair(cloudShape,billboard) );
			return billboard;
		}
		else
		{
			// Billboard exists.
			return itr->second;  // value
		}
    }

private:
	Map			mMap;
};

void
Listener_ModulePony_TextureFilter_Cloud( string& textureName );

#endif // MOD_PONY_CLOUD_HH
#endif // COMPILING_MODULE_PONY
