#ifndef _RSGBINARYOPS_HPP
#define _RSGBINARYOPS_HPP
/*-------------------------------------------------------------------------
 * 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 Binary operators.
 *//*--------------------------------------------------------------------*/

#include "rsgDefs.hpp"
#include "rsgExpression.hpp"

namespace rsg
{

enum Associativity
{
	ASSOCIATIVITY_LEFT = 0,
	ASSOCIATIVITY_RIGHT,

	ASSOCIATIVITY_LAST
};

template <int Precedence, Associativity Assoc>
class BinaryOp : public Expression
{
public:
								BinaryOp			(Token::Type operatorToken);
	virtual						~BinaryOp			(void);

	Expression*					createNextChild		(GeneratorState& state);
	void						tokenize			(GeneratorState& state, TokenStream& str) const;
	void						evaluate			(ExecutionContext& execCtx);
	ExecConstValueAccess		getValue			(void) const { return m_value.getValue(m_type); }

	virtual void				evaluate			(ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b) = DE_NULL;

protected:
	static float				getWeight			(const GeneratorState& state, ConstValueRangeAccess valueRange);

	Token::Type					m_operator;
	VariableType				m_type;
	ExecValueStorage			m_value;

	ValueRange					m_leftValueRange;
	ValueRange					m_rightValueRange;

	Expression*					m_leftValueExpr;
	Expression*					m_rightValueExpr;
};

template <int Precedence, bool Float, bool Int, bool Bool, class ComputeValueRange, class EvaluateComp>
class BinaryVecOp : public BinaryOp<Precedence, ASSOCIATIVITY_LEFT>
{
public:
								BinaryVecOp			(GeneratorState& state, Token::Type operatorToken, ConstValueRangeAccess valueRange);
	virtual						~BinaryVecOp		(void);

	void						evaluate			(ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b);
};

struct ComputeMulRange
{
	void operator() (de::Random& rnd, float dstMin, float dstMax, float& aMin, float& aMax, float& bMin, float& bMax) const;
	void operator() (de::Random& rnd, int dstMin, int dstMax, int& aMin, int& aMax, int& bMin, int& bMax) const;
	void operator() (de::Random&, bool, bool, bool&, bool&, bool&, bool&) const { DE_ASSERT(DE_FALSE); }
};

struct EvaluateMul
{
	template <typename T> inline T operator() (T a, T b) const { return a*b; }
};

typedef BinaryVecOp<4, true, true, false, ComputeMulRange, EvaluateMul> MulBase;

class MulOp : public MulBase
{
public:
								MulOp				(GeneratorState& state, ConstValueRangeAccess valueRange);
	virtual						~MulOp				(void) {}

	static float				getWeight			(const GeneratorState& state, ConstValueRangeAccess valueRange);
};

struct ComputeAddRange
{
	template <typename T>
	void operator() (de::Random& rnd, T dstMin, T dstMax, T& aMin, T& aMax, T& bMin, T& bMax) const;
};

struct EvaluateAdd
{
	template <typename T> inline T operator() (T a, T b) const { return a+b; }
};

typedef BinaryVecOp<5, true, true, false, ComputeAddRange, EvaluateAdd> AddBase;

class AddOp : public AddBase
{
public:
								AddOp				(GeneratorState& state, ConstValueRangeAccess valueRange);
	virtual						~AddOp				(void) {}

	static float				getWeight			(const GeneratorState& state, ConstValueRangeAccess valueRange);
};

struct ComputeSubRange
{
	template <typename T>
	void operator() (de::Random& rnd, T dstMin, T dstMax, T& aMin, T& aMax, T& bMin, T& bMax) const;
};

struct EvaluateSub
{
	template <typename T> inline T operator() (T a, T b) const { return a-b; }
};

typedef BinaryVecOp<5, true, true, false, ComputeSubRange, EvaluateSub> SubBase;

class SubOp : public SubBase
{
public:
								SubOp				(GeneratorState& state, ConstValueRangeAccess valueRange);
	virtual						~SubOp				(void) {}

	static float				getWeight			(const GeneratorState& state, ConstValueRangeAccess valueRange);
};

/* Template for Relational Operators. */

template <class ComputeValueRange, class EvaluateComp>
class RelationalOp : public BinaryOp<7, ASSOCIATIVITY_LEFT>
{
public:
								RelationalOp		(GeneratorState& state, Token::Type operatorToken, ConstValueRangeAccess valueRange);
	virtual						~RelationalOp		(void);

	void						evaluate			(ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b);

	static float				getWeight			(const GeneratorState& state, ConstValueRangeAccess valueRange);
};

/* Less Than. */

struct ComputeLessThanRange
{
	template <typename T>
	void operator() (de::Random& rnd, bool dstMin, bool dstMax, T& aMin, T& aMax, T& bMin, T& bMax) const;
};

struct EvaluateLessThan
{
	template <typename T> inline bool operator() (T a, T b) const { return a < b; }
};

typedef RelationalOp<ComputeLessThanRange, EvaluateLessThan> LessThanBase;

class LessThanOp : public LessThanBase
{
public:
								LessThanOp			(GeneratorState& state, ConstValueRangeAccess valueRange);
	virtual						~LessThanOp			(void) {}

	static float				getWeight			(const GeneratorState& state, ConstValueRangeAccess valueRange);
};

/* Less or Equal. */

struct ComputeLessOrEqualRange
{
	template <typename T>
	void operator() (de::Random& rnd, bool dstMin, bool dstMax, T& aMin, T& aMax, T& bMin, T& bMax) const;
};

struct EvaluateLessOrEqual
{
	template <typename T> inline bool operator() (T a, T b) const { return a <= b; }
};

typedef RelationalOp<ComputeLessOrEqualRange, EvaluateLessOrEqual> LessOrEqualBase;

class LessOrEqualOp : public LessOrEqualBase
{
public:
								LessOrEqualOp		(GeneratorState& state, ConstValueRangeAccess valueRange);
	virtual						~LessOrEqualOp		(void) {};

	static float				getWeight			(const GeneratorState& state, ConstValueRangeAccess valueRange);
};

/* Greater Than. */

struct ComputeGreaterThanRange
{
	template <typename T>
	void operator() (de::Random& rnd, bool dstMin, bool dstMax, T& aMin, T& aMax, T& bMin, T& bMax) const
	{
		ComputeLessThanRange()(rnd, dstMin, dstMax, bMin, bMax, aMin, aMax);
	}
};

struct EvaluateGreaterThan
{
	template <typename T> inline bool operator() (T a, T b) const { return a > b; }
};

typedef RelationalOp<ComputeGreaterThanRange, EvaluateGreaterThan> GreaterThanBase;

class GreaterThanOp : public GreaterThanBase
{
public:
								GreaterThanOp		(GeneratorState& state, ConstValueRangeAccess valueRange);
	virtual						~GreaterThanOp		(void) {}

	static float				getWeight			(const GeneratorState& state, ConstValueRangeAccess valueRange);
};

/* Greater or Equal. */

struct ComputeGreaterOrEqualRange
{
	template <typename T>
	void operator() (de::Random& rnd, bool dstMin, bool dstMax, T& aMin, T& aMax, T& bMin, T& bMax) const
	{
		ComputeLessOrEqualRange()(rnd, dstMin, dstMax, bMin, bMax, aMin, aMax);
	}
};

struct EvaluateGreaterOrEqual
{
	template <typename T> inline bool operator() (T a, T b) const { return a >= b; }
};

typedef RelationalOp<ComputeGreaterOrEqualRange, EvaluateGreaterOrEqual> GreaterOrEqualBase;

class GreaterOrEqualOp : public GreaterOrEqualBase
{
public:
								GreaterOrEqualOp	(GeneratorState& state, ConstValueRangeAccess valueRange);
	virtual						~GreaterOrEqualOp	(void) {};

	static float				getWeight			(const GeneratorState& state, ConstValueRangeAccess valueRange);
};

/* Equality comparison. */

template <bool IsEqual>
class EqualityComparisonOp : public BinaryOp<8, ASSOCIATIVITY_LEFT>
{
public:
								EqualityComparisonOp		(GeneratorState& state, ConstValueRangeAccess valueRange);
	virtual						~EqualityComparisonOp		(void) {}

	void						evaluate					(ExecValueAccess dst, ExecConstValueAccess a, ExecConstValueAccess b);

	static float				getWeight					(const GeneratorState& state, ConstValueRangeAccess valueRange);
};

// \note Since template implementation is in .cpp we have to reference specialized constructor and static functions from there.
class EqualOp : public EqualityComparisonOp<true>
{
public:
								EqualOp						(GeneratorState& state, ConstValueRangeAccess valueRange);
	static float				getWeight					(const GeneratorState& state, ConstValueRangeAccess valueRange);
};

class NotEqualOp : public EqualityComparisonOp<false>
{
public:
								NotEqualOp					(GeneratorState& state, ConstValueRangeAccess valueRange);
	static float				getWeight					(const GeneratorState& state, ConstValueRangeAccess valueRange);
};

} // rsg

#endif // _RSGBINARYOPS_HPP