// ===================================================================
// $Id$
//
// layered_surface.h
//    Implementation of multi-layered surface base class.
//
// Class: CSurfaceLayered
//
// Initial coding by Jiri Nekola within diploma thesis project, November 2011



#ifndef __SURFACE_LAYERED_H__
#define __SURFACE_LAYERED_H__

#include "configh.h"
#include "surface.h"

__BEGIN_BRDFLIB_HEADER

// Forward-declare classes
class CHitPointInfo;
class CTexture;

/// This class represents single layer of the surface.
/**
	This class represents single layer of the surface. This consists of
	material (BRDF model) for the layer, its thickness and wavelength-dependent
	absorption coefficient. Thickness and abs.coef. usually causing an attenuation
	of the light going through the layer may or may not be used by the layer, based 
	on the concrete use of the layer within layered surface.
*/
struct CSurfaceLayer
{
	/// Constructs layer of the surface with given initial parameters
	/**
		Constructs layer of the surface with given initial parameters.

		@param surf(in)	Material (BRDF model) of the layer.
		@param thick(in) Thickness texture of the layer.
		@param absorb(in) Absorption coefficient texture of the layer.
	*/
	CSurfaceLayer(CSurface* surf, CTexture* thick, CTexture* absorb):
		surface(surf),
		thickness(thick),
		absorbtion(absorb)
		{}

	/// Standard destructor. All the layer parameters are destroyed here.
	~CSurfaceLayer()
	{
		if (surface) delete surface;
		if (thickness) delete thickness;
		if (absorbtion) delete absorbtion;
	}

	CSurface*	surface;	///< Layer material.
	CTexture*	thickness;	///< Thickness of the layer.
	CTexture*	absorbtion; ///< Wavelength dependent absorption coefficient.
};

// ------------------------------------------------------------------------------
/// Layered surface base class. It is base class for the multi-layered materials, 
/// assuming, that surface is composed of one or more material layers of negligible
/// thickness. Each layer is then described as fundamental BRDF model implemented
/// in this library. It user's responsibility of this library to implement
/// methods for evaluation, rays spawning, albedo computing etc. for this multi-layered
/// based surfaces (implementing this base class), according to the behaviour of the 
/// interaction between adjacent layers (subsurface scattering).
// ------------------------------------------------------------------------------
class CSurfaceLayered :
  public CSurface
{
public:
	/**
		 Constructs the multi-layered surface with initial no layers.
	*/
	CSurfaceLayered():
	  CSurface(EE_NONE)
	{}

	virtual ~CSurfaceLayered();

	// layers methods

	/// Adds layer to the surface. Ownership is transferred.
	virtual void AddLayer(CSurface* surface, CTexture* thickness, CTexture* absorbtion);

	/// Adds layer to the surface. Ownership is transferred.
	virtual void AddLayer(CSurfaceLayer* layer);

	/// Inserts layer to the surface at a given position. Ownership is transferred.
	virtual void InsertLayer(CSurface* surface, CTexture* thickness, CTexture* absorbtion, int index);

	/// Inserts layer to the surface. Ownership is transferred.
	virtual void InsertLayer(CSurfaceLayer* layer, int index);

	/// Replace layer at the given index. Ownership is transferred.
	virtual void ReplaceLayer(CSurface* surface, CTexture* thickness, CTexture* absorbtion, int index); 

	/// Replace layer at the given index. Ownership is transferred.
	virtual void ReplaceLayer(CSurfaceLayer* layer, int index);

	/// Swaps layers of the given positions.
	virtual void SwapLayers(int index1, int index2);

	/// Moves layer with a given index up(true) or down(false) by 1 layer, based on a given direction
	virtual void ShiftLayer(int index, bool directionUp);

	/// Returns layer at the given index
	virtual const CSurfaceLayer* GetLayer(int index);

	/// Remove layer at the given index
	virtual void RemoveLayer(int index);

	/// Sets surface of the layer at the given index
	virtual void SetLayerSurface(int index, CSurface* surface);

	virtual void Describe(ostream &app, int ind) const;
	
	/// Creates and returns deep copy of layers vector, ownership of the vector is transfered outside
	vector<CSurfaceLayer*>& DupLayers() const;

	/// Implements CSurface
	virtual char* GetName() const
	{return "CSurfaceLayered";}

	/// Implements CSurface
	virtual inline EType GetType() const { return  EE_BSDFLayered; }

	/// Implements CSurface
	virtual const char* GetParameterTitle(int parameterIndex) const;

	/// Implements CSurface
	virtual const char* GetParameterDescription(int parameterIndex) const;

	/// Implements CSurface
	virtual EParameterUIType GetParameterSyntax(int parameterIndex) const;

	/// Implements CSurface
	virtual void SetParameter(int parameterIndex, const CValues& value);

	/// Implements CSurface
	virtual CValues GetParameter(int parameterIndex) const;

	/// Implements CSurface
	virtual CValues GetParameterConstraints(int parameterIndex) const;

	/// Implements CSurface
	virtual int GetNumParameters() const;

protected:
	vector<CSurfaceLayer*>		_layers;	///< Layers of the surface
};

__END_BRDFLIB_HEADER

#endif // __SURFACE_LAYERED_H__