/*-------------------------------------------------------------------------
 * drawElements Quality Program Random Shader Generator
 * ----------------------------------------------------
 *
 * Copyright 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *//*!
 * \file
 * \brief Shader Class.
 *//*--------------------------------------------------------------------*/

#include "rsgShader.hpp"

using std::vector;

namespace rsg
{

namespace
{

template <typename T>
void deleteVectorElements (std::vector<T*>& vec)
{
	for (typename std::vector<T*>::iterator i = vec.begin(); i != vec.end(); i++)
		delete *i;
	vec.clear();
}

} // anonymous

Function::Function (void)
{
}

Function::Function (const char* name)
	: m_name(name)
{
}

Function::~Function (void)
{
	deleteVectorElements(m_parameters);
}

ShaderInput::ShaderInput (const Variable* variable, ConstValueRangeAccess valueRange)
	: m_variable	(variable)
	, m_min			(variable->getType().getScalarSize())
	, m_max			(variable->getType().getScalarSize())
{
	ValueAccess(variable->getType(), &m_min[0]) = valueRange.getMin().value();
	ValueAccess(variable->getType(), &m_max[0]) = valueRange.getMax().value();
}

Shader::Shader (Type type)
	: m_type			(type)
	, m_mainFunction	("main")
{
}

Shader::~Shader (void)
{
	deleteVectorElements(m_functions);
	deleteVectorElements(m_globalStatements);
	deleteVectorElements(m_inputs);
	deleteVectorElements(m_uniforms);
}

void Shader::getOutputs (vector<const Variable*>& outputs) const
{
	outputs.clear();
	const vector<Variable*>& globalVars = m_globalScope.getDeclaredVariables();
	for (vector<Variable*>::const_iterator i = globalVars.begin(); i != globalVars.end(); i++)
	{
		const Variable* var = *i;
		if (var->getStorage() == Variable::STORAGE_SHADER_OUT)
			outputs.push_back(var);
	}
}

void Shader::tokenize (GeneratorState& state, TokenStream& str) const
{
	// Add default precision for float in fragment shaders \todo [pyry] Proper precision handling
	if (state.getShader().getType() == Shader::TYPE_FRAGMENT)
		str << Token::PRECISION << Token::MEDIUM_PRECISION << Token::FLOAT << Token::SEMICOLON << Token::NEWLINE;

	// Tokenize global declaration statements
	for (int ndx = (int)m_globalStatements.size()-1; ndx >= 0; ndx--)
		m_globalStatements[ndx]->tokenize(state, str);

	// Tokenize all functions
	for (int ndx = (int)m_functions.size()-1; ndx >= 0; ndx--)
	{
		str << Token::NEWLINE;
		m_functions[ndx]->tokenize(state, str);
	}

	// Tokenize main
	str << Token::NEWLINE;
	m_mainFunction.tokenize(state, str);
}

void Shader::execute (ExecutionContext& execCtx) const
{
	// Execute global statements (declarations)
	for (vector<Statement*>::const_reverse_iterator i = m_globalStatements.rbegin(); i != m_globalStatements.rend(); i++)
		(*i)->execute(execCtx);

	// \todo [2011-03-08 pyry] Proper function calls
	m_mainFunction.getBody().execute(execCtx);
}

void Function::tokenize (GeneratorState& state, TokenStream& str) const
{
	// Return type
	m_returnType.tokenizeShortType(str);

	// Function name
	DE_ASSERT(m_name != "");
	str << Token(m_name.c_str());

	// Parameters
	str << Token::LEFT_PAREN;

	for (vector<Variable*>::const_iterator i = m_parameters.begin(); i != m_parameters.end(); i++)
	{
		if (i != m_parameters.begin())
			str << Token::COMMA;
		(*i)->tokenizeDeclaration(state, str);
	}

	str << Token::RIGHT_PAREN << Token::NEWLINE;

	// Tokenize body
	m_functionBlock.tokenize(state, str);
}

} // rsg