#include "StdAfx.h"
#include "ShaderLibrary.h"

#include "PathInfo.h"

#include <map>
using namespace std;

#include "Shader/DefaultShader.h"
#include "Shader/ConstantShader.h"
#include "Shader/CustomShader.h"
#include "Shader/NormalColorShader.h"
#include "Shader/DepthColorShader.h"
#include "Shader/ShadowMap.h"
#include "Shader/EnvMap.h"
#include "Shader/PhongShader.h"
#include "Shader/IntegrateShader.h"
#include "Shader/MatcapShader.h"



void ShaderLibrary::ReleaseAllShaders(void)
{
	m_DefaultShader     .reset();
	m_ConstantShader    .reset();
	m_PhongShader       .reset();
	m_CustomShaer       .reset();
	m_NormalColorShader .reset();
	m_DepthColorShader  .reset();
	m_ShadowMapShader   .reset();
	m_EnvMapShader      .reset();
	m_IntegrateShader   .reset();
	m_MatcapShader      .reset();
}

std::string ShaderLibrary::GetShaderLibDir(void) const
{
	return PathInfo::GetShaderDirPath().toLocal8Bit().data();
}

ShaderInterface* ShaderLibrary::GetShader(ShaderType t)
{
	switch(t)
	{
	case ShaderType::Constant    : return GetConstantShader();
	case ShaderType::Phong       : return GetPhongShader();
	case ShaderType::Custom      : return GetCustomShader();
	case ShaderType::NormalColor : return GetNormalColorShader();
	case ShaderType::DepthColor  : return GetDepthColorShader();
	case ShaderType::Shadowmap   : return GetShadowmapShader();
	case ShaderType::Envmap      : return GetEnvmapShader();
	case ShaderType::Integrate   : return GetIntegrateShader();
	case ShaderType::Matcap      : return GetMatcapShader();
	case ShaderType::Default     : return GetDefaultShader();

	default :
		return NULL;
	}
}

DefaultShader* ShaderLibrary::GetDefaultShader(void)
{
	DefaultShader* shader = m_DefaultShader.get();
	if(shader != NULL)
		return shader;

	shader = new DefaultShader(m_Context);

	m_DefaultShader.reset( shader );

	return shader;
}

ConstantShader* ShaderLibrary::GetConstantShader(void)
{
	ConstantShader* shader = m_ConstantShader.get();
	if(shader != NULL)
		return shader;
	
	shader = new ConstantShader(m_Context);
	shader->Initialize(GetShaderLibDir());

	m_ConstantShader.reset( shader );

	return shader;
}

PhongShader* ShaderLibrary::GetPhongShader(void)
{
	PhongShader* shader = m_PhongShader.get();
	if(shader != NULL)
		return shader;
	
	shader = new PhongShader(m_Context);
	shader->Initialize(2);

	m_PhongShader.reset( shader );

	return shader;
}

CustomShader* ShaderLibrary::GetCustomShader(void)
{
	CustomShader* shader = m_CustomShaer.get();
	if(shader != NULL)
		return shader;

	shader = new CustomShader(m_Context);

	m_CustomShaer.reset( shader );

	return shader;
}

NormalColorShader* ShaderLibrary::GetNormalColorShader(void)
{
	NormalColorShader* shader = m_NormalColorShader.get();
	if(shader != NULL)
		return shader;

	shader = new NormalColorShader(m_Context);

	m_NormalColorShader.reset( shader );

	shader->Initialize(GetShaderLibDir());

	return shader;
}

DepthColorShader* ShaderLibrary::GetDepthColorShader(void)
{
	DepthColorShader* shader = m_DepthColorShader.get();
	if(shader != NULL)
		return shader;

	shader = new DepthColorShader(m_Context);

	m_DepthColorShader.reset( shader );

	shader->Initialize(GetShaderLibDir());

	return shader;
}

ShadowMap* ShaderLibrary::GetShadowmapShader(void)
{
	ShadowMap* shader = m_ShadowMapShader.get();
	if(shader != NULL)
		return shader;

	shader = new ShadowMap(m_Context);
	m_ShadowMapShader.reset(shader);

	shader->Initialize(GetShaderLibDir());

	return shader;
}

EnvMap* ShaderLibrary::GetEnvmapShader(void)
{
	EnvMap* shader = m_EnvMapShader.get();
	if(shader != NULL)
		return shader;

	shader = new EnvMap(m_Context);
	m_EnvMapShader.reset(shader);

	shader->InitializeShader(GetShaderLibDir());

	return shader;
}

IntegrateShader* ShaderLibrary::GetIntegrateShader(void)
{
	IntegrateShader* shader = m_IntegrateShader.get();
	if(shader != NULL)
		return shader;

	shader = new IntegrateShader(m_Context);
	m_IntegrateShader.reset(shader);

	shader->Initialize(GetShaderLibDir());

	return shader;
}

MatcapShader* ShaderLibrary::GetMatcapShader(void)
{
	MatcapShader* shader = m_MatcapShader.get();
	if(shader != NULL)
		return shader;

	shader = new MatcapShader(m_Context);
	m_MatcapShader.reset(shader);

	shader->Initialize(GetShaderLibDir());

	return shader;
}


const char* ShaderLibrary::GetTypeToName(ShaderType type)
{
	switch(type)
	{
	case ShaderType::None        : return "None";
	case ShaderType::Constant    : return "Constant";
	case ShaderType::Default     : return "Default";
	case ShaderType::Phong       : return "Phong";
	case ShaderType::Custom      : return "Custom";
	case ShaderType::NormalColor : return "NormalColor";
	case ShaderType::DepthColor  : return "DepthColor";
	case ShaderType::Shadowmap   : return "ShadowMap";
	case ShaderType::Envmap      : return "EnvMap";
	case ShaderType::Integrate   : return "Integrate";
	case ShaderType::Matcap      : return "Matcap";
	default:
		assert(false);
		return "";
	}
}

ShaderType ShaderLibrary::GetNameToType(const char* name)
{
	map<string, ShaderType> m;
	m[ "None"        ] = ShaderType::None        ;
	m[ "Constant"    ] = ShaderType::Constant    ;
	m[ "Default"     ] = ShaderType::Default     ;
	m[ "Phong"       ] = ShaderType::Phong       ;
	m[ "Custom"      ] = ShaderType::Custom      ;
	m[ "NormalColor" ] = ShaderType::NormalColor ;
	m[ "DepthColor"  ] = ShaderType::DepthColor  ;
	m[ "ShadowMap"   ] = ShaderType::Shadowmap   ;
	m[ "EnvMap"      ] = ShaderType::Envmap      ;
	m[ "Integrate"   ] = ShaderType::Integrate   ;
	m[ "Matcap"      ] = ShaderType::Matcap      ;

	map<string, ShaderType>::iterator i = m.find(name);
	if(i == m.end())
	{
		assert(false);
		return ShaderType::None;
	}

	return i->second;
}
