/*-------------------------------------------------------------------------
 * drawElements Quality Program Tester Core
 * ----------------------------------------
 *
 * 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 Thread test utilities
 *//*--------------------------------------------------------------------*/

#include "tcuThreadUtil.hpp"
#include "deClock.h"
#include "deMemory.h"

using std::vector;
using de::SharedPtr;

namespace tcu
{
namespace ThreadUtil
{

Event::Event (void)
	: m_result		(RESULT_NOT_READY)
	, m_waiterCount	(0)
	, m_waiters		(0, 0)
{
}

Event::~Event (void)
{
}

void Event::setResult (Result result)
{
	m_lock.lock();
	DE_ASSERT(m_result == RESULT_NOT_READY);
	m_result = result;
	m_lock.unlock();

	for (int i = 0; i < m_waiterCount; i++)
		m_waiters.increment();
}

Event::Result Event::waitReady (void)
{
	m_lock.lock();

	if (m_result == RESULT_NOT_READY)
		m_waiterCount++;
	else
	{
		m_lock.unlock();
		return m_result;
	}

	m_lock.unlock();

	m_waiters.decrement();

	return m_result;
}

Object::Object (const char* type, SharedPtr<Event> e)
	: m_type	(type)
	, m_modify	(e)
{
}

Object::~Object	(void)
{
}

void Object::read (SharedPtr<Event> event, std::vector<SharedPtr<Event> >& deps)
{
	// Make call depend on last modifying call
	deps.push_back(m_modify);

	// Add read dependency
	m_reads.push_back(event);
}

void Object::modify (SharedPtr<Event> event, std::vector<SharedPtr<Event> >& deps)
{
	// Make call depend on all reads
	for (int readNdx = 0; readNdx < (int)m_reads.size(); readNdx++)
	{
		deps.push_back(m_reads[readNdx]);
	}
	deps.push_back(m_modify);

	// Update last modifying call
	m_modify = event;

	// Clear read dependencies of last "version" of this object
	m_reads.clear();
}

Operation::Operation (const char* name)
	: m_name	(name)
	, m_event	(new Event)
{
}

Operation::~Operation (void)
{
}

void Operation::execute (Thread& thread)
{
	bool success = true;

	// Wait for dependencies and check that they succeeded
	for (int depNdx = 0; depNdx < (int)m_deps.size(); depNdx++)
	{
		if (m_deps[depNdx]->waitReady() != Event::RESULT_OK)
			success = false;
	}

	// Try execute operation
	if (success)
	{
		try
		{
			exec(thread);
		}
		catch (...)
		{
			// Got exception event failed
			m_event->setResult(Event::RESULT_FAILED);
			throw;
		}

		m_event->setResult(Event::RESULT_OK);
	}
	else
		// Some dependencies failed
		m_event->setResult(Event::RESULT_FAILED);

	// Release resources
	m_deps.clear();
	m_event = SharedPtr<Event>();
}

const MessageBuilder::EndToken Message::End = MessageBuilder::EndToken();

void MessageBuilder::operator<< (const EndToken&)
{
	m_thread.pushMessage(m_stream.str());
}

Thread::Thread (int seed)
	: m_random	(seed)
	, m_status	(THREADSTATUS_NOT_STARTED)
{
}

Thread::~Thread (void)
{
	for (int operationNdx = 0; operationNdx < (int)m_operations.size(); operationNdx++)
		delete m_operations[operationNdx];

	m_operations.clear();
}

deUint8* Thread::getDummyData (size_t size)
{
	if (m_dummyData.size() < size)
	{
		m_dummyData.resize(size);
	}

	return &(m_dummyData[0]);
}

void Thread::addOperation (Operation* operation)
{
	m_operations.push_back(operation);
}

void Thread::run (void)
{
	m_status = THREADSTATUS_RUNNING;
	bool initOk = false;

	// Reserve at least two messages for each operation
	m_messages.reserve(m_operations.size()*2);
	try
	{
		init();
		initOk = true;
		for (int operationNdx = 0; operationNdx < (int)m_operations.size(); operationNdx++)
			m_operations[operationNdx]->execute(*this);

		deinit();
		m_status =  THREADSTATUS_READY;
	}
	catch (const tcu::NotSupportedError& e)
	{
		newMessage() << "tcu::NotSupportedError '" << e.what() << "'" << Message::End;
		deinit();
		m_status = (initOk ? THREADSTATUS_NOT_SUPPORTED : THREADSTATUS_INIT_FAILED);
	}
	catch (const tcu::Exception& e)
	{
		newMessage() << "tcu::Exception '" << e.what() << "'" << Message::End;
		deinit();
		m_status = (initOk ? THREADSTATUS_FAILED : THREADSTATUS_INIT_FAILED);
	}
	catch (const std::exception& error)
	{
		newMessage() << "std::exception '" << error.what() << "'" << Message::End;
		deinit();
		m_status = (initOk ? THREADSTATUS_FAILED : THREADSTATUS_INIT_FAILED);
	}
	catch (...)
	{
		newMessage() << "Unkown exception" << Message::End;
		deinit();
		m_status = (initOk ? THREADSTATUS_FAILED : THREADSTATUS_INIT_FAILED);
	}
}

void Thread::exec (void)
{
	start();
}

void Thread::pushMessage (const std::string& str)
{
	m_messages.push_back(Message(deGetMicroseconds(), str.c_str()));
}

DataBlock::DataBlock (SharedPtr<Event> event)
	: Object("DataBlock", event)
{
}

void DataBlock::setData (size_t size, const void* data)
{
	m_data = std::vector<deUint8>(size);
	deMemcpy(&(m_data[0]), data, (int)size);
}

CompareData::CompareData (SharedPtr<DataBlock> a, SharedPtr<DataBlock> b)
	: Operation	("CompareData")
	, m_a		(a)
	, m_b		(b)
{
	readObject(SharedPtr<Object>(a));
	readObject(SharedPtr<Object>(b));
}

void CompareData::exec (Thread& thread)
{
	bool result = true;
	DE_ASSERT(m_a->getSize() == m_b->getSize());

	thread.newMessage() << "Begin -- CompareData" << Message::End;

	for (int byteNdx = 0; byteNdx < (int)m_a->getSize(); byteNdx++)
	{
		if (m_a->getData()[byteNdx] != m_b->getData()[byteNdx])
		{
			result = false;
			thread.newMessage() << "CompareData failed at offset :" << byteNdx << Message::End;
			break;
		}
	}

	if (result)
		thread.newMessage() << "CompareData passed" << Message::End;
	else
		TCU_FAIL("Data comparision failed");

	thread.newMessage() << "End -- CompareData" << Message::End;
}

} // ThreadUtil
} // tcu
