#ifndef _XETESTCASERESULT_HPP
#define _XETESTCASERESULT_HPP
/*-------------------------------------------------------------------------
 * drawElements Quality Program Test Executor
 * ------------------------------------------
 *
 * 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 Test case result models.
 *//*--------------------------------------------------------------------*/

#include "xeDefs.hpp"
#include "xeTestCase.hpp"

#include <string>
#include <vector>
#include <ostream>

namespace xe
{

enum TestStatusCode
{
	TESTSTATUSCODE_PASS,					//!< Test case passed.
	TESTSTATUSCODE_FAIL,					//!< Test case failed (not passed).
	TESTSTATUSCODE_QUALITY_WARNING,			//!< Result within specification, but suspicious quality wise
	TESTSTATUSCODE_COMPATIBILITY_WARNING,	//!< Result within specification, but likely to cause fragmentation
	TESTSTATUSCODE_PENDING,					//!< Not yet started.
	TESTSTATUSCODE_RUNNING,					//!< Currently running (not stored in database).
	TESTSTATUSCODE_NOT_SUPPORTED,			//!< Some feature was not supported in the implementation.
	TESTSTATUSCODE_RESOURCE_ERROR,			//!< A resource error has occurred.
	TESTSTATUSCODE_INTERNAL_ERROR,			//!< An internal error has occurred.
	TESTSTATUSCODE_CANCELED,				//!< User canceled the execution
	TESTSTATUSCODE_TIMEOUT,					//!< Test was killed because of watch dog timeout.
	TESTSTATUSCODE_CRASH,					//!< Test executable crashed before finishing the test.
	TESTSTATUSCODE_DISABLED,				//!< Test case disabled (for current target)
	TESTSTATUSCODE_TERMINATED,				//!< Terminated for other reason.

	TESTSTATUSCODE_LAST
};

const char* getTestStatusCodeName (TestStatusCode statusCode);

namespace ri
{

class Item;
class Result;
class Text;
class Number;
class Image;
class ImageSet;
class VertexShader;
class FragmentShader;
class ShaderProgram;
class ShaderSource;
class InfoLog;
class EglConfig;
class EglConfigSet;
class Section;
class KernelSource;
class CompileInfo;
class SampleList;
class SampleInfo;
class ValueInfo;
class Sample;
class SampleValue;

// \todo [2014-02-28 pyry] Make List<T> for items that have only specific subitems.

class List
{
public:
							List			(void);
							~List			(void);

	int						getNumItems		(void) const	{ return (int)m_items.size();	}
	const Item&				getItem			(int ndx) const	{ return *m_items[ndx];			}
	Item&					getItem			(int ndx)		{ return *m_items[ndx];			}

	template <typename T>
	T*						allocItem		(void);

private:
	std::vector<Item*>		m_items;
};

template <typename T>
T* List::allocItem (void)
{
	m_items.reserve(m_items.size()+1);
	T* item = new T();
	m_items.push_back(static_cast<ri::Item*>(item));
	return item;
}

} // ri

class TestCaseResultHeader
{
public:
						TestCaseResultHeader	(void) : caseType(TESTCASETYPE_LAST), statusCode(TESTSTATUSCODE_LAST) {}

	std::string			casePath;				//!< Full test case path.
	TestCaseType		caseType;				//!< Test case type.
	TestStatusCode		statusCode;				//!< Test status code.
	std::string			statusDetails;			//!< Status description.
};

class TestCaseResult : public TestCaseResultHeader
{
public:
	ri::List			resultItems;			//!< Test log items.
};

// Result items.
namespace ri
{

// Result item type.
enum Type
{
	TYPE_RESULT = 0,
	TYPE_TEXT,
	TYPE_NUMBER,
	TYPE_IMAGE,
	TYPE_IMAGESET,
	TYPE_SHADER,
	TYPE_SHADERPROGRAM,
	TYPE_SHADERSOURCE,
	TYPE_SPIRVSOURCE,
	TYPE_INFOLOG,
	TYPE_EGLCONFIG,
	TYPE_EGLCONFIGSET,
	TYPE_SECTION,
	TYPE_KERNELSOURCE,
	TYPE_COMPILEINFO,
	TYPE_SAMPLELIST,
	TYPE_SAMPLEINFO,
	TYPE_VALUEINFO,
	TYPE_SAMPLE,
	TYPE_SAMPLEVALUE,

	TYPE_LAST
};

class NumericValue
{
public:
	enum Type
	{
		TYPE_EMPTY = 0,
		TYPE_INT64,
		TYPE_FLOAT64,

		TYPE_LAST
	};

					NumericValue	(void)			: m_type(TYPE_EMPTY)	{}
					NumericValue	(deInt64 value)	: m_type(TYPE_INT64)	{ m_value.int64 = value;	}
					NumericValue	(double value)	: m_type(TYPE_FLOAT64)	{ m_value.float64 = value;	}

	Type			getType			(void) const	{ return m_type; }
	deInt64			getInt64		(void) const	{ DE_ASSERT(getType() == TYPE_INT64);	return m_value.int64;	}
	double			getFloat64		(void) const	{ DE_ASSERT(getType() == TYPE_FLOAT64);	return m_value.float64;	}

private:
	Type			m_type;
	union
	{
		deInt64		int64;
		double		float64;
	} m_value;
};

std::ostream& operator<< (std::ostream& str, const NumericValue& value);

class Item
{
public:

	virtual			~Item				(void) {}

	Type			getType				(void) const { return m_type; }

protected:
					Item				(Type type) : m_type(type) {}

private:
					Item				(const Item& other);
	Item&			operator=			(const Item& other);

	Type			m_type;
};

class Result : public Item
{
public:
						Result			(void) : Item(TYPE_RESULT), statusCode(TESTSTATUSCODE_LAST) {}
						~Result			(void) {}

	TestStatusCode		statusCode;
	std::string			details;
};

class Text : public Item
{
public:
						Text			(void) : Item(TYPE_TEXT) {}
						~Text			(void) {}

	std::string			text;
};

class Number : public Item
{
public:
						Number			(void) : Item(TYPE_NUMBER) {}
						~Number			(void) {}

	std::string			name;
	std::string			description;
	std::string			unit;
	std::string			tag;
	NumericValue		value;
};

class Image : public Item
{
public:
	enum Format
	{
		FORMAT_RGB888,
		FORMAT_RGBA8888,

		FORMAT_LAST
	};

	enum Compression
	{
		COMPRESSION_NONE = 0,
		COMPRESSION_PNG,

		COMPRESSION_LAST
	};

							Image		(void) : Item(TYPE_IMAGE), width(0), height(0), format(FORMAT_LAST), compression(COMPRESSION_LAST) {}
							~Image		(void) {}

	std::string				name;
	std::string				description;
	int						width;
	int						height;
	Format					format;
	Compression				compression;
	std::vector<deUint8>	data;
};

class ImageSet : public Item
{
public:
						ImageSet		(void) : Item(TYPE_IMAGESET) {}
						~ImageSet		(void) {}

	std::string			name;
	std::string			description;
	List				images;
};

class ShaderSource : public Item
{
public:
						ShaderSource		(void) : Item(TYPE_SHADERSOURCE) {}
						~ShaderSource		(void) {}

	std::string			source;
};

class SpirVSource : public Item
{
public:
						SpirVSource			(void) : Item(TYPE_SPIRVSOURCE) {}
						~SpirVSource		(void) {}

	std::string			source;
};

class InfoLog : public Item
{
public:
						InfoLog				(void) : Item(TYPE_INFOLOG) {}
						~InfoLog			(void) {}

	std::string			log;
};

class Shader : public Item
{
public:
	enum ShaderType
	{
		SHADERTYPE_VERTEX = 0,
		SHADERTYPE_FRAGMENT,
		SHADERTYPE_GEOMETRY,
		SHADERTYPE_TESS_CONTROL,
		SHADERTYPE_TESS_EVALUATION,
		SHADERTYPE_COMPUTE,

		SHADERTYPE_LAST
	};

						Shader				(void) : Item(TYPE_SHADER), shaderType(SHADERTYPE_LAST), compileStatus(false) {}
						~Shader				(void) {}

	ShaderType			shaderType;
	bool				compileStatus;
	ShaderSource		source;
	InfoLog				infoLog;
};

class ShaderProgram : public Item
{
public:
						ShaderProgram		(void) : Item(TYPE_SHADERPROGRAM), linkStatus(false) {}
						~ShaderProgram		(void) {}

	List				shaders;
	bool				linkStatus;
	InfoLog				linkInfoLog;
};

class EglConfig : public Item
{
public:
						EglConfig			(void);
						~EglConfig			(void) {}

	int					bufferSize;
	int					redSize;
	int					greenSize;
	int					blueSize;
	int					luminanceSize;
	int					alphaSize;
	int					alphaMaskSize;
	bool				bindToTextureRGB;
	bool				bindToTextureRGBA;
	std::string			colorBufferType;
	std::string			configCaveat;
	int					configID;
	std::string			conformant;
	int					depthSize;
	int					level;
	int					maxPBufferWidth;
	int					maxPBufferHeight;
	int					maxPBufferPixels;
	int					maxSwapInterval;
	int					minSwapInterval;
	bool				nativeRenderable;
	std::string			renderableType;
	int					sampleBuffers;
	int					samples;
	int					stencilSize;
	std::string			surfaceTypes;
	std::string			transparentType;
	int					transparentRedValue;
	int					transparentGreenValue;
	int					transparentBlueValue;
};

inline EglConfig::EglConfig (void)
	: Item					(TYPE_EGLCONFIG)
	, bufferSize			(0)
	, redSize				(0)
	, greenSize				(0)
	, blueSize				(0)
	, luminanceSize			(0)
	, alphaSize				(0)
	, alphaMaskSize			(0)
	, bindToTextureRGB		(false)
	, bindToTextureRGBA		(false)
	, configID				(0)
	, depthSize				(0)
	, level					(0)
	, maxPBufferWidth		(0)
	, maxPBufferHeight		(0)
	, maxPBufferPixels		(0)
	, maxSwapInterval		(0)
	, minSwapInterval		(0)
	, nativeRenderable		(false)
	, sampleBuffers			(0)
	, samples				(0)
	, stencilSize			(0)
	, transparentRedValue	(0)
	, transparentGreenValue	(0)
	, transparentBlueValue	(0)
{
}

class EglConfigSet : public Item
{
public:
						EglConfigSet		(void) : Item(TYPE_EGLCONFIGSET) {}
						~EglConfigSet		(void) {}

	std::string			name;
	std::string			description;
	List				configs;
};

class Section : public Item
{
public:
						Section			(void) : Item(TYPE_SECTION) {}
						~Section		(void) {}

	std::string			name;
	std::string			description;
	List				items;
};

class KernelSource : public Item
{
public:
						KernelSource	(void) : Item(TYPE_KERNELSOURCE) {}
						~KernelSource	(void) {}

	std::string			source;
};

class CompileInfo : public Item
{
public:
						CompileInfo		(void) : Item(TYPE_COMPILEINFO), compileStatus(false) {}
						~CompileInfo	(void) {}

	std::string			name;
	std::string			description;
	bool				compileStatus;
	InfoLog				infoLog;
};

class ValueInfo : public Item
{
public:
	enum ValueTag
	{
		VALUETAG_PREDICTOR,
		VALUETAG_RESPONSE,

		VALUETAG_LAST
	};

						ValueInfo		(void) : Item(TYPE_VALUEINFO), tag(VALUETAG_LAST) {}
						~ValueInfo		(void) {}

	std::string			name;
	std::string			description;
	std::string			unit;
	ValueTag			tag;
};

class SampleInfo : public Item
{
public:
						SampleInfo		(void) : Item(TYPE_SAMPLEINFO) {}
						~SampleInfo		(void) {}

	List				valueInfos;
};

class SampleValue : public Item
{
public:
						SampleValue		(void) : Item(TYPE_SAMPLEVALUE) {}
						~SampleValue	(void) {}

	NumericValue		value;
};

class Sample : public Item
{
public:
						Sample			(void) : Item(TYPE_SAMPLE) {}
						~Sample			(void) {}

	List				values;
};

class SampleList : public Item
{
public:
						SampleList		(void) : Item(TYPE_SAMPLELIST) {}
						~SampleList		(void) {}

	std::string			name;
	std::string			description;
	SampleInfo			sampleInfo;
	List				samples;
};

} // ri
} // xe

#endif // _XETESTCASERESULT_HPP