<commit_before>#include <string>
#include <array>
#include <algorithm>
#include <cstdint>
#include <cstdlib>
#include <cassert>
#include <type_traits>
#include <sstream>
#include <iterator>
#include <tarlib/tarlib.h>

namespace {
#if 0
	template <unsigned int OFFSET, unsigned int COUNT>
	unsigned long long _base256_to_10( typename std::enable_if<COUNT == 0, const Byte*>::type ptr) {
		return ptr[OFFSET];
	}

	template <unsigned int OFFSET, unsigned int COUNT>
	unsigned long long _base256_to_10( typename std::enable_if<COUNT != 0, const Byte*>::type ptr) {
		return (ptr[OFFSET] * 256 * COUNT) + _base256_to_10<OFFSET + 1, COUNT - 1>( ptr );
	}
#endif
	template <unsigned int OFFSET, unsigned int COUNT>
	unsigned long long base256_to_10( const char* ptr) {
		//return _base256_to_10<OFFSET, COUNT - 1>( ptr );
		return std::strtoull( ptr, nullptr, 256 );
	}

	unsigned long base8_to_10( const char* ptr ) {
		return std::strtoul( ptr, nullptr, 8 );
	}

	// Converts octal to usable decimal values
	void convert( tar_header& header ) {

		// Make sure file name is properly \0 terminated
		header.file_name[TAR_NELEMENTS(header.file_name) - 1] = '\0';

		const bool is_base_256 = header.file_bytes_octal[0] & 0x80;

		std::uint64_t value;

		const auto& field = header.file_bytes_octal;
		// Enforce proper file_bytes encoding
		header.file_bytes_terminator = '\0';
		if( is_base_256 ) {
			value = base256_to_10<1, 10>( field );
		} else {
			//std::ostringstream stream;
			value = base8_to_10( field );
		}
		header.file_bytes = value;
		header.modification_time = base8_to_10( header.modification_time_octal );
	}

	// Internal tar state
	struct internal {
		internal();
		tar_headerp header( tar_headerp );
		bool put( tar_stream& strm, bool continueAfterHeader );
	private:
		void reset( tar_stream& strm );
		struct {
			tar_headerp ptr_begin;
			Byte*       ptr;
			uint16_t    left; //bytes left till header is full
			void reset() {
				ptr  = reinterpret_cast<Byte*>( ptr_begin );
				left = TAR_HEADER_SIZE;
				if( ptr_begin ) {
					ptr_begin->done = 0;
					ptr_begin->file_bytes        = 0;
					ptr_begin->modification_time = 0;
				}
			}

			void reset( tar_headerp header ) {
				ptr_begin = header;
				reset();
			}
		} _header;
		tar_header    _internal_header;
		std::uint64_t _left;
		std::uint16_t _endPadding;
	};

	internal& intern( tar_stream& strm ) {
		return *static_cast<internal*>( strm.state );
	}

	Byte* begin( tar_header& header ) {
		return reinterpret_cast<Byte*>( &header );
	}

	Byte* end( tar_header& header ) {
		return begin(header) + TAR_HEADER_SIZE;
	}
}

internal::internal() :
	_header(), _internal_header(), _left( 0 )
{
	_header.reset( &_internal_header );
}

tar_headerp
internal::header( tar_headerp header ) {
	_header.reset( header );
	return _header.ptr_begin;
}

void
internal::reset( tar_stream& strm ) {
	_header.reset();
	strm.ptr_out  = nullptr;
	strm.len_out = 0;
	_left = 0;
}

bool
internal::put( tar_stream& strm, bool continueAfterHeader ) {
	if( !_header.left && !_left ) {
		if( strm.avail_in ) {
			// Go to the next entry
			reset( strm );
		}

		return false; //end of entry
	}

	if( _header.left ) {
		// Try to make the header full
		const auto distance = std::min( static_cast<decltype(strm.avail_in)>(_header.left), strm.avail_in );
		assert( distance <= _header.left );

		if( _header.ptr ) {
			std::copy( strm.next_in, strm.next_in + distance, _header.ptr );
			_header.ptr += distance;
		}
		strm.next_in  += distance;
		strm.avail_in -= distance;
		strm.total_in += distance;
		// We made sure distance is at max _header.left
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
		_header.left  -= distance;
#pragma GCC diagnostic pop

		if( !_header.left ) {
			// We reached a full header

			if( _header.ptr_begin ) {
				tar_header& header = *_header.ptr_begin;
				convert( header );
				_header.ptr_begin->done = 1;
			}

			{
				//FIXME: Make working without internal header
				const auto file_bytes = _header.ptr_begin->file_bytes;
				_endPadding = [&]() {
					// Data is always rounded up to 512
					static const std::uint16_t PADDING_SIZE = 512;
					auto quot = file_bytes / PADDING_SIZE;
					if( _left % PADDING_SIZE ) {
						++quot;
					}
					return static_cast<uint16_t>( quot * PADDING_SIZE - _left );
				}();
				// How much bytes are left to read
				_left = file_bytes + _endPadding;
			}

			if( !continueAfterHeader )
				return true;
		}
	}

	if( !_header.left && strm.avail_in ) {
		// Process file entry content
		strm.ptr_out    = strm.next_in;

		uInt moveValue = [&]() {
			if( _left > _endPadding ) {
				const std::uint64_t leftContent = _left - _endPadding;
				// Limit to current file entry only

				strm.len_out    = strm.avail_in < leftContent ? strm.avail_in : static_cast<decltype(strm.avail_in)>( leftContent );
				assert( strm.len_out <= leftContent );
				strm.total_out += strm.len_out;

				return strm.len_out;
			} else {
				uInt movePadding = static_cast<decltype(_endPadding)>( _left );

				if ( movePadding > strm.avail_in )
					movePadding = strm.avail_in;

				// Consume the padding but do not generate output
				strm.len_out    = 0;
				strm.total_out += movePadding;

				return movePadding;
			}
		}();

		strm.avail_in -= moveValue;
		strm.next_in  += moveValue;
		strm.total_in += moveValue;

		_left         -= moveValue;
	}

	return true;
}

// C wrapper
int TAREXPORT
tar_inflateInit( tar_streamp strm ) {
	assert( strm );

	strm->total_in  = 0;
	strm->ptr_out   = nullptr;
	strm->len_out   = 0;
	strm->total_out = 0;
	strm->state     = new internal();
	return TAR_OK;
}

int TAREXPORT
tar_inflate( tar_streamp strm, int flush ) {
	assert( strm );

	if( intern(*strm).put( *strm, flush != TAR_HEADER_FLUSH ) )
		return TAR_OK;
	else
		return TAR_ENTRY_END;
}

int TAREXPORT
tar_inflateEnd( tar_streamp strm ) {
	assert( strm );
	delete &intern( *strm );
	// Signal to externals that the stream
	// has ended
	strm->state = nullptr;
	return TAR_OK;
}

int TAREXPORT
tar_inflateGetHeader( tar_streamp strm,
                      tar_headerp head ) {
	assert(strm);
	assert(head);
	auto& internal = intern( *strm );
	internal.header( head );
	return TAR_OK;
}

int TAREXPORT
tar_inflateReset( tar_streamp strm ) {
	assert(strm);
	auto& internal = intern( *strm );
	internal.header( nullptr );
	return TAR_OK;
}

int TAREXPORT
tar_headerIsDir( tar_headerp header ) {
	assert( header );

	if( !header->done )
		return -1;

	if( header->extension.ustar.type_flag == TAR_DIR )
		return TAR_TRUE;

	// support pre-POSIX.1-1988
	auto len = strlen( header->file_name );

	if( len == 0 )
		return TAR_FALSE;

	// Check indicating via terminating slash
	return header->file_name[len - 1] == '/' ? TAR_TRUE : TAR_FALSE;
}

int TAREXPORT
tar_headerIsEmpty( tar_headerp header ) {
	assert( header );

	if( !header->done )
		return -1;

	return std::all_of( reinterpret_cast<const char*>(header),
	                    reinterpret_cast<const char*>(header) + TAR_HEADER_SIZE,
	                    []( const char& character ) {
	                    	return character == 0;
	                    } );

}

<commit_msg>Add cstring include for strlen()<commit_after>#include <string>
#include <array>
#include <algorithm>
#include <cstdint>
#include <cstdlib>
#include <cassert>
#include <cstring>
#include <type_traits>
#include <sstream>
#include <iterator>
#include <tarlib/tarlib.h>

namespace {
#if 0
	template <unsigned int OFFSET, unsigned int COUNT>
	unsigned long long _base256_to_10( typename std::enable_if<COUNT == 0, const Byte*>::type ptr) {
		return ptr[OFFSET];
	}

	template <unsigned int OFFSET, unsigned int COUNT>
	unsigned long long _base256_to_10( typename std::enable_if<COUNT != 0, const Byte*>::type ptr) {
		return (ptr[OFFSET] * 256 * COUNT) + _base256_to_10<OFFSET + 1, COUNT - 1>( ptr );
	}
#endif
	template <unsigned int OFFSET, unsigned int COUNT>
	unsigned long long base256_to_10( const char* ptr) {
		//return _base256_to_10<OFFSET, COUNT - 1>( ptr );
		return std::strtoull( ptr, nullptr, 256 );
	}

	unsigned long base8_to_10( const char* ptr ) {
		return std::strtoul( ptr, nullptr, 8 );
	}

	// Converts octal to usable decimal values
	void convert( tar_header& header ) {

		// Make sure file name is properly \0 terminated
		header.file_name[TAR_NELEMENTS(header.file_name) - 1] = '\0';

		const bool is_base_256 = header.file_bytes_octal[0] & 0x80;

		std::uint64_t value;

		const auto& field = header.file_bytes_octal;
		// Enforce proper file_bytes encoding
		header.file_bytes_terminator = '\0';
		if( is_base_256 ) {
			value = base256_to_10<1, 10>( field );
		} else {
			//std::ostringstream stream;
			value = base8_to_10( field );
		}
		header.file_bytes = value;
		header.modification_time = base8_to_10( header.modification_time_octal );
	}

	// Internal tar state
	struct internal {
		internal();
		tar_headerp header( tar_headerp );
		bool put( tar_stream& strm, bool continueAfterHeader );
	private:
		void reset( tar_stream& strm );
		struct {
			tar_headerp ptr_begin;
			Byte*       ptr;
			uint16_t    left; //bytes left till header is full
			void reset() {
				ptr  = reinterpret_cast<Byte*>( ptr_begin );
				left = TAR_HEADER_SIZE;
				if( ptr_begin ) {
					ptr_begin->done = 0;
					ptr_begin->file_bytes        = 0;
					ptr_begin->modification_time = 0;
				}
			}

			void reset( tar_headerp header ) {
				ptr_begin = header;
				reset();
			}
		} _header;
		tar_header    _internal_header;
		std::uint64_t _left;
		std::uint16_t _endPadding;
	};

	internal& intern( tar_stream& strm ) {
		return *static_cast<internal*>( strm.state );
	}

	Byte* begin( tar_header& header ) {
		return reinterpret_cast<Byte*>( &header );
	}

	Byte* end( tar_header& header ) {
		return begin(header) + TAR_HEADER_SIZE;
	}
}

internal::internal() :
	_header(), _internal_header(), _left( 0 )
{
	_header.reset( &_internal_header );
}

tar_headerp
internal::header( tar_headerp header ) {
	_header.reset( header );
	return _header.ptr_begin;
}

void
internal::reset( tar_stream& strm ) {
	_header.reset();
	strm.ptr_out  = nullptr;
	strm.len_out = 0;
	_left = 0;
}

bool
internal::put( tar_stream& strm, bool continueAfterHeader ) {
	if( !_header.left && !_left ) {
		if( strm.avail_in ) {
			// Go to the next entry
			reset( strm );
		}

		return false; //end of entry
	}

	if( _header.left ) {
		// Try to make the header full
		const auto distance = std::min( static_cast<decltype(strm.avail_in)>(_header.left), strm.avail_in );
		assert( distance <= _header.left );

		if( _header.ptr ) {
			std::copy( strm.next_in, strm.next_in + distance, _header.ptr );
			_header.ptr += distance;
		}
		strm.next_in  += distance;
		strm.avail_in -= distance;
		strm.total_in += distance;
		// We made sure distance is at max _header.left
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
		_header.left  -= distance;
#pragma GCC diagnostic pop

		if( !_header.left ) {
			// We reached a full header

			if( _header.ptr_begin ) {
				tar_header& header = *_header.ptr_begin;
				convert( header );
				_header.ptr_begin->done = 1;
			}

			{
				//FIXME: Make working without internal header
				const auto file_bytes = _header.ptr_begin->file_bytes;
				_endPadding = [&]() {
					// Data is always rounded up to 512
					static const std::uint16_t PADDING_SIZE = 512;
					auto quot = file_bytes / PADDING_SIZE;
					if( _left % PADDING_SIZE ) {
						++quot;
					}
					return static_cast<uint16_t>( quot * PADDING_SIZE - _left );
				}();
				// How much bytes are left to read
				_left = file_bytes + _endPadding;
			}

			if( !continueAfterHeader )
				return true;
		}
	}

	if( !_header.left && strm.avail_in ) {
		// Process file entry content
		strm.ptr_out    = strm.next_in;

		uInt moveValue = [&]() {
			if( _left > _endPadding ) {
				const std::uint64_t leftContent = _left - _endPadding;
				// Limit to current file entry only

				strm.len_out    = strm.avail_in < leftContent ? strm.avail_in : static_cast<decltype(strm.avail_in)>( leftContent );
				assert( strm.len_out <= leftContent );
				strm.total_out += strm.len_out;

				return strm.len_out;
			} else {
				uInt movePadding = static_cast<decltype(_endPadding)>( _left );

				if ( movePadding > strm.avail_in )
					movePadding = strm.avail_in;

				// Consume the padding but do not generate output
				strm.len_out    = 0;
				strm.total_out += movePadding;

				return movePadding;
			}
		}();

		strm.avail_in -= moveValue;
		strm.next_in  += moveValue;
		strm.total_in += moveValue;

		_left         -= moveValue;
	}

	return true;
}

// C wrapper
int TAREXPORT
tar_inflateInit( tar_streamp strm ) {
	assert( strm );

	strm->total_in  = 0;
	strm->ptr_out   = nullptr;
	strm->len_out   = 0;
	strm->total_out = 0;
	strm->state     = new internal();
	return TAR_OK;
}

int TAREXPORT
tar_inflate( tar_streamp strm, int flush ) {
	assert( strm );

	if( intern(*strm).put( *strm, flush != TAR_HEADER_FLUSH ) )
		return TAR_OK;
	else
		return TAR_ENTRY_END;
}

int TAREXPORT
tar_inflateEnd( tar_streamp strm ) {
	assert( strm );
	delete &intern( *strm );
	// Signal to externals that the stream
	// has ended
	strm->state = nullptr;
	return TAR_OK;
}

int TAREXPORT
tar_inflateGetHeader( tar_streamp strm,
                      tar_headerp head ) {
	assert(strm);
	assert(head);
	auto& internal = intern( *strm );
	internal.header( head );
	return TAR_OK;
}

int TAREXPORT
tar_inflateReset( tar_streamp strm ) {
	assert(strm);
	auto& internal = intern( *strm );
	internal.header( nullptr );
	return TAR_OK;
}

int TAREXPORT
tar_headerIsDir( tar_headerp header ) {
	assert( header );

	if( !header->done )
		return -1;

	if( header->extension.ustar.type_flag == TAR_DIR )
		return TAR_TRUE;

	// support pre-POSIX.1-1988
	auto len = strlen( header->file_name );

	if( len == 0 )
		return TAR_FALSE;

	// Check indicating via terminating slash
	return header->file_name[len - 1] == '/' ? TAR_TRUE : TAR_FALSE;
}

int TAREXPORT
tar_headerIsEmpty( tar_headerp header ) {
	assert( header );

	if( !header->done )
		return -1;

	return std::all_of( reinterpret_cast<const char*>(header),
	                    reinterpret_cast<const char*>(header) + TAR_HEADER_SIZE,
	                    []( const char& character ) {
	                    	return character == 0;
	                    } );

}

<|endoftext|>


<commit_before>#include "gridmanager.h"
#include "user.h"
#include "machine.h"
#include "job.h"
#include "log.h"
#include "loader.h"
#include "menu.h"

#include <chrono>
#include <iostream>
#include <map>
#include <algorithm>
#include <numeric>

uint GridManager::_lastUserId = 0;
uint GridManager::_lastMachineId = 0;
Menu* GridManager::_menu = Loader<Menu>("gridManagerMenu.txt").Load();

GridManager::~GridManager()
{
    for (auto user : _users)
        delete user;

    for (auto machine : _machines)
        delete machine;
}

bool GridManager::Save(ByteBuffer& bb) const
{
    bb.WriteUInt32(_lastUserId);
    bb.WriteUInt32(_lastMachineId);
    bb.WriteUInt32(Machine::GetLastJobId());

    bb.WriteUInt32(_users.size());
    for (auto user : _users)
        user->Save(bb);

    bb.WriteUInt32(_machines.size());
    for (auto machine : _machines)
        machine->Save(bb);

    bb.WriteUInt32(_priorityMachines.size());
    for (auto pMachine : _priorityMachines)
        pMachine->Save(bb);

    _idleUsers.Save(bb);

    return true;
}

GridManager* GridManager::Load(ByteBuffer& bb)
{
    GridManager* gm = new GridManager();

    _lastUserId = bb.ReadUInt32();
    _lastMachineId = bb.ReadUInt32();
    Machine::SetLastJobId(bb.ReadUInt32());

    uint32 usersCount = bb.ReadUInt32();
    for (uint32 i = 0; i < usersCount; ++i)
        gm->AddUser(User::Load(bb));

    uint32 machinesCount = bb.ReadUInt32();
    for (uint32 i = 0; i < machinesCount; ++i)
        gm->AddMachine(Machine::Load(bb));

    uint32 priorityMachinesCount = bb.ReadUInt32();
    for (uint32 i = 0; i < priorityMachinesCount; ++i)
        gm->AddPriorityMachine(PriorityMachine::Load(bb));

    gm->_idleUsers = *IdleUserContainer::Load(bb);

    return gm;
}

bool GridManager::RemoveUser(const User* user)
{
    if (!user) return NULL;
    auto it = std::find_if(_users.begin(), _users.end(), [user] (User* usr) { return usr == user; });
    if (it == _users.end())
    {
        sLog(Console)->Log("GridManager::RemoveUser(User*): Could not find user %s in GridManager", user->GetName().c_str());
        return false;
    }

    _idleUsers.InsertUser(IdleUser::FromUser(*it));

    delete *it;
    _users.erase(it);

    return true;
}

bool GridManager::RemoveUser(uint id)
{
    AcademicUser usr(id);
    auto it = _users.find(&usr);
    if (it == _users.end())
    {
        sLog(Console)->Log("GridManager::RemoveUser(uint): Could not find user with id %u in GridManager", id);
        return false;
    }

    _idleUsers.InsertUser(IdleUser::FromUser(*it));

    delete *it;
    _users.erase(it);

    return true;
}

bool GridManager::RemoveMachine(const Machine* machine)
{
    auto it = std::find_if(_machines.begin(), _machines.end(), [machine] (Machine* mach) { return mach == machine; });
    if (it == _machines.end())
    {
        sLog(Console)->Log("GridManager::RemoveMachine(Machine*): Could not find machine %s in GridManager", machine->GetName().c_str());
        return false;
    }

    delete *it;
    _machines.erase(it);

    return true;
}

bool GridManager::RemoveMachine(uint id)
{
    Machine m(id);
    auto it = _machines.find(&m);
    if (it == _machines.end())
    {
        sLog(Console)->Log("GridManager::RemoveMachine(uint): Could not find machine with id %u in GridManager", id);
        return false;
    }

    delete *it;
    _machines.erase(it);

    return true;
}

bool GridManager::RemovePriorityMachine(const PriorityMachine* machine)
{
    auto it = std::find_if(_priorityMachines.begin(), _priorityMachines.end(), [machine] (PriorityMachine* mach) { return mach == machine; });
    if (it == _priorityMachines.end())
    {
        sLog(Console)->Log("GridManager::RemovePriorityMachine(PriorityMachine*): Could not find priority machine %s in GridManager", machine->GetName().c_str());
        return false;
    }

    delete *it;
    _priorityMachines.erase(it);

    return true;
}

bool GridManager::RemovePriorityMachine(uint id)
{
    PriorityMachine m(id);
    auto it = _priorityMachines.find(&m);
    if (it == _priorityMachines.end())
    {
        sLog(Console)->Log("GridManager::RemovePriorityMachine(uint): Could not find priority machine with id %u in GridManager", id);
        return false;
    }

    delete *it;
    _priorityMachines.erase(it);

    return true;
}

User* GridManager::GetUser(uint id) const
{
    AcademicUser usr(id);
    auto it = _users.find(&usr);
    if (it == _users.end())
    {
        sLog(Console)->Log("GridManager::GetUser: Could not find user with id %u in GridManager", id);
        return NULL;
    }

    return *it;

}

Machine* GridManager::GetMachine(uint id) const
{
    Machine m(id);
    auto it = _machines.find(&m);
    if (it == _machines.end())
    {
        sLog(Console)->Log("GridManager::GetMachine: Could not find machine with id %u in GridManager", id);
        return NULL;
    }

    return *it;
}

PriorityMachine* GridManager::GetPriorityMachine( uint id ) const
{
    PriorityMachine m(id);
    auto it = _priorityMachines.find(&m);
    if (it == _priorityMachines.end())
    {
        sLog(Console)->Log("GridManager::GetPriorityMachine: Could not find priority machine with id %u in GridManager", id);
        return NULL;
    }

    return *it;
}

void GridManager::Update(uint32 diff)
{
    for (auto machine : _machines)
        machine->Update(diff);

    for (auto pMachine : _priorityMachines)
        pMachine->Update(diff);

    if (!_waitingJobs.empty())
    {
        Job* job = _waitingJobs.front();
        if (job->GetPriority() == 0)
        {
            std::vector<Machine*> machineVector; // TODO: Every time a job is added this sorted vector is being rebuilt; change that
            machineVector.reserve(_machines.size());

            // put machines in the map into a vector so we can sort them
            std::transform(_machines.begin(), _machines.end(), std::back_inserter(machineVector),
                [](MachineSet::value_type val) { return val; });

            // sort of load balancing, better machines get assigned jobs first
            std::sort(machineVector.begin(), machineVector.end(), [](Machine* m1, Machine* m2) {
                double score1 = ((m1->GetMaxJobs() - m1->GetNumberOfCurrentJobs()) + m1->GetAvailableDiskSpace() + m1->GetAvailableRAM());
                double score2 = ((m2->GetMaxJobs() - m2->GetNumberOfCurrentJobs()) + m2->GetAvailableDiskSpace() + m2->GetAvailableRAM());

                return score1 > score2;
            });

            for (auto& mach : machineVector)
            {
                if (mach->AddJob(job))
                {
                    sLog(Console)->Log("Job %s added to machine %s", job->GetName().c_str(), mach->GetName().c_str());
                    _waitingJobs.pop();
                }
            }
        }
        else
        {
            std::vector<PriorityMachine*> machineVector; // TODO: Every time a job is added this sorted vector is being rebuilt; change that
            machineVector.reserve(_priorityMachines.size());

            // put machines in the map into a vector so we can sort them
            std::transform(_priorityMachines.begin(), _priorityMachines.end(), std::back_inserter(machineVector),
                [](PriorityMachineSet::value_type val) { return val; });

            // sort of load balancing, better machines get assigned jobs first
            std::sort(machineVector.begin(), machineVector.end(), [](PriorityMachine* m1, PriorityMachine* m2) {
                double score1 = ((m1->GetMaxJobs() - m1->GetNumberOfCurrentJobs()) + m1->GetAvailableDiskSpace() + m1->GetAvailableRAM());
                double score2 = ((m2->GetMaxJobs() - m2->GetNumberOfCurrentJobs()) + m2->GetAvailableDiskSpace() + m2->GetAvailableRAM());

                return score1 > score2;
            });

            for (auto& mach : machineVector)
            {
                if (mach->AddJob(job))
                {
                    sLog(Console)->Log("Job %s added to machine %s", job->GetName().c_str(), mach->GetName().c_str());
                    _waitingJobs.pop();
                }
            }
        }
    }

    _idleUsers.Update(diff);
}

bool GridManager::AddJob(Job* job)
{
    if (!job)
    {
        sLog(Console)->Log("GridManager::AddJob: Tried to added a Job with null pointer");
        return false;
    }

    _waitingJobs.push(job);

    return true;
}

bool GridManager::AddJobByUser(User* user, Job* job)
{
    if (!user)
    {
        sLog(Console)->Log("GridManager::AddJobByUser: Tried to added a Job with user null pointer");
        return false;
    }

    if (!job)
    {
        sLog(Console)->Log("GridManager::AddJobByUser: Tried to added a Job with job null pointer");
        return false;
    }

    if (!user->CanCreateJob(job))
        throw std::runtime_error("Can't create Job because User doesn't have enough budget.");

    if (!AddJob(job))
        return false;

    user->CreatedJob(job);

    return true;
}

template<>
std::vector<const Job*> GridManager::ApplyPredicate<Job>(std::function<bool(const Job*)> predicate) const
{
    std::vector<const Job*> result;

    for (auto machine : _machines)
        for (auto job : machine->GetJobs())
            if (predicate(job))
                result.push_back(job);

    for (auto pmachine : _priorityMachines)
        for (auto job : pmachine->GetJobs())
            if (predicate(job))
                result.push_back(job);

    return result;
}

template<>
std::vector<const User*> GridManager::ApplyPredicate<User>(std::function<bool(const User*)> predicate) const
{
    std::vector<const User*> result;

    for (auto user : _users)
        if (predicate(user))
            result.push_back(user);

    return result;
}

template<>
std::vector<const IdleUser*> GridManager::ApplyPredicate<IdleUser>(std::function<bool(const IdleUser*)> predicate) const
{
    std::vector<const IdleUser*> result;

    for (auto iu : _idleUsers.GetContainer())
        if (predicate(iu.second))
            result.push_back(iu.second);

    return result;
}

template<>
std::vector<const Machine*> GridManager::ApplyPredicate<Machine>(std::function<bool(const Machine*)> predicate) const
{
    std::vector<const Machine*> result;

    for (auto machine : _machines)
        if (predicate(machine))
            result.push_back(machine);

    return result;
}

template<>
std::vector<const PriorityMachine*> GridManager::ApplyPredicate<PriorityMachine>(std::function<bool(const PriorityMachine*)> predicate) const
{
    std::vector<const PriorityMachine*> result;

    for (auto machine : _priorityMachines)
        if (predicate(machine))
            result.push_back(machine);

    return result;
}

uint GridManager::AddUser(User* user)
{
    if (!user)
        return 0;

    if (user->GetId() == 0) // inserting new user
    {
        _lastUserId++;
        user->SetId(_lastUserId);
    }

    _users.insert(user);

    return user->GetId();
}

uint GridManager::AddMachine(Machine* machine)
{
    if (!machine)
        return 0;

    if (machine->GetId() == 0) // inserting new machine
    {
        _lastMachineId++;
        machine->SetId(_lastMachineId);
    }

    _machines.insert(machine);

    return machine->GetId();
}

uint GridManager::GetNumberOfJobs() const
{
    return std::accumulate(_machines.begin(), _machines.end(), 0,
        [](uint sum, Machine* mach) { return sum + mach->GetNumberOfCurrentJobs(); }) +
           std::accumulate(_priorityMachines.begin(), _priorityMachines.end(), 0,
        [](uint sum, PriorityMachine* pMach) { return sum + pMach->GetNumberOfCurrentJobs(); });
}

bool GridManager::RemoveMachineJob(Machine* machine, uint jobId)
{
    if (!machine)
    {
        sLog(Console)->Log("GridManager::RemoveMachineJob: Tried to remove machine with machine null pointer");
        return false;
    }

    return machine->RemoveJob(jobId);
}

uint32 GridManager::AddPriorityMachine(PriorityMachine* machine)
{
    if (!machine)
        return 0;

    if (machine->GetId() == 0) // inserting new machine
    {
        _lastMachineId++;
        machine->SetId(_lastMachineId);
    }

    _priorityMachines.insert(machine);

    return machine->GetId();
}
<commit_msg>Implement save of waiting jobs queue.<commit_after>#include "gridmanager.h"
#include "user.h"
#include "machine.h"
#include "job.h"
#include "log.h"
#include "loader.h"
#include "menu.h"

#include <chrono>
#include <iostream>
#include <map>
#include <algorithm>
#include <numeric>

uint GridManager::_lastUserId = 0;
uint GridManager::_lastMachineId = 0;
Menu* GridManager::_menu = Loader<Menu>("gridManagerMenu.txt").Load();

GridManager::~GridManager()
{
    for (auto user : _users)
        delete user;

    for (auto machine : _machines)
        delete machine;
}

bool GridManager::Save(ByteBuffer& bb) const
{
    bb.WriteUInt32(_lastUserId);
    bb.WriteUInt32(_lastMachineId);
    bb.WriteUInt32(Machine::GetLastJobId());

    bb.WriteUInt32(_users.size());
    for (auto user : _users)
        user->Save(bb);

    bb.WriteUInt32(_machines.size());
    for (auto machine : _machines)
        machine->Save(bb);

    bb.WriteUInt32(_priorityMachines.size());
    for (auto pMachine : _priorityMachines)
        pMachine->Save(bb);

    bb.WriteUInt32(_waitingJobs.size());
    for (std::queue<Job*> temp(_waitingJobs); !temp.empty(); temp.pop())
        temp.front()->Save(bb);

    _idleUsers.Save(bb);

    return true;
}

GridManager* GridManager::Load(ByteBuffer& bb)
{
    GridManager* gm = new GridManager();

    _lastUserId = bb.ReadUInt32();
    _lastMachineId = bb.ReadUInt32();
    Machine::SetLastJobId(bb.ReadUInt32());

    uint32 usersCount = bb.ReadUInt32();
    for (uint32 i = 0; i < usersCount; ++i)
        gm->AddUser(User::Load(bb));

    uint32 machinesCount = bb.ReadUInt32();
    for (uint32 i = 0; i < machinesCount; ++i)
        gm->AddMachine(Machine::Load(bb));

    uint32 priorityMachinesCount = bb.ReadUInt32();
    for (uint32 i = 0; i < priorityMachinesCount; ++i)
        gm->AddPriorityMachine(PriorityMachine::Load(bb));

    uint32 waitingJobsCount = bb.ReadUInt32();
    for (uint32 i = 0; i < waitingJobsCount; ++i)
        gm->AddJob(Job::Load(bb));

    gm->_idleUsers = *IdleUserContainer::Load(bb);

    return gm;
}

bool GridManager::RemoveUser(const User* user)
{
    if (!user) return NULL;
    auto it = std::find_if(_users.begin(), _users.end(), [user] (User* usr) { return usr == user; });
    if (it == _users.end())
    {
        sLog(Console)->Log("GridManager::RemoveUser(User*): Could not find user %s in GridManager", user->GetName().c_str());
        return false;
    }

    _idleUsers.InsertUser(IdleUser::FromUser(*it));

    delete *it;
    _users.erase(it);

    return true;
}

bool GridManager::RemoveUser(uint id)
{
    AcademicUser usr(id);
    auto it = _users.find(&usr);
    if (it == _users.end())
    {
        sLog(Console)->Log("GridManager::RemoveUser(uint): Could not find user with id %u in GridManager", id);
        return false;
    }

    _idleUsers.InsertUser(IdleUser::FromUser(*it));

    delete *it;
    _users.erase(it);

    return true;
}

bool GridManager::RemoveMachine(const Machine* machine)
{
    auto it = std::find_if(_machines.begin(), _machines.end(), [machine] (Machine* mach) { return mach == machine; });
    if (it == _machines.end())
    {
        sLog(Console)->Log("GridManager::RemoveMachine(Machine*): Could not find machine %s in GridManager", machine->GetName().c_str());
        return false;
    }

    delete *it;
    _machines.erase(it);

    return true;
}

bool GridManager::RemoveMachine(uint id)
{
    Machine m(id);
    auto it = _machines.find(&m);
    if (it == _machines.end())
    {
        sLog(Console)->Log("GridManager::RemoveMachine(uint): Could not find machine with id %u in GridManager", id);
        return false;
    }

    delete *it;
    _machines.erase(it);

    return true;
}

bool GridManager::RemovePriorityMachine(const PriorityMachine* machine)
{
    auto it = std::find_if(_priorityMachines.begin(), _priorityMachines.end(), [machine] (PriorityMachine* mach) { return mach == machine; });
    if (it == _priorityMachines.end())
    {
        sLog(Console)->Log("GridManager::RemovePriorityMachine(PriorityMachine*): Could not find priority machine %s in GridManager", machine->GetName().c_str());
        return false;
    }

    delete *it;
    _priorityMachines.erase(it);

    return true;
}

bool GridManager::RemovePriorityMachine(uint id)
{
    PriorityMachine m(id);
    auto it = _priorityMachines.find(&m);
    if (it == _priorityMachines.end())
    {
        sLog(Console)->Log("GridManager::RemovePriorityMachine(uint): Could not find priority machine with id %u in GridManager", id);
        return false;
    }

    delete *it;
    _priorityMachines.erase(it);

    return true;
}

User* GridManager::GetUser(uint id) const
{
    AcademicUser usr(id);
    auto it = _users.find(&usr);
    if (it == _users.end())
    {
        sLog(Console)->Log("GridManager::GetUser: Could not find user with id %u in GridManager", id);
        return NULL;
    }

    return *it;

}

Machine* GridManager::GetMachine(uint id) const
{
    Machine m(id);
    auto it = _machines.find(&m);
    if (it == _machines.end())
    {
        sLog(Console)->Log("GridManager::GetMachine: Could not find machine with id %u in GridManager", id);
        return NULL;
    }

    return *it;
}

PriorityMachine* GridManager::GetPriorityMachine( uint id ) const
{
    PriorityMachine m(id);
    auto it = _priorityMachines.find(&m);
    if (it == _priorityMachines.end())
    {
        sLog(Console)->Log("GridManager::GetPriorityMachine: Could not find priority machine with id %u in GridManager", id);
        return NULL;
    }

    return *it;
}

void GridManager::Update(uint32 diff)
{
    for (auto machine : _machines)
        machine->Update(diff);

    for (auto pMachine : _priorityMachines)
        pMachine->Update(diff);

    if (!_waitingJobs.empty())
    {
        Job* job = _waitingJobs.front();
        if (job->GetPriority() == 0)
        {
            std::vector<Machine*> machineVector; // TODO: Every time a job is added this sorted vector is being rebuilt; change that
            machineVector.reserve(_machines.size());

            // put machines in the map into a vector so we can sort them
            std::transform(_machines.begin(), _machines.end(), std::back_inserter(machineVector),
                [](MachineSet::value_type val) { return val; });

            // sort of load balancing, better machines get assigned jobs first
            std::sort(machineVector.begin(), machineVector.end(), [](Machine* m1, Machine* m2) {
                double score1 = ((m1->GetMaxJobs() - m1->GetNumberOfCurrentJobs()) + m1->GetAvailableDiskSpace() + m1->GetAvailableRAM());
                double score2 = ((m2->GetMaxJobs() - m2->GetNumberOfCurrentJobs()) + m2->GetAvailableDiskSpace() + m2->GetAvailableRAM());

                return score1 > score2;
            });

            for (auto& mach : machineVector)
            {
                if (mach->AddJob(job))
                {
                    sLog(Console)->Log("Job %s added to machine %s", job->GetName().c_str(), mach->GetName().c_str());
                    _waitingJobs.pop();
                }
            }
        }
        else
        {
            std::vector<PriorityMachine*> machineVector; // TODO: Every time a job is added this sorted vector is being rebuilt; change that
            machineVector.reserve(_priorityMachines.size());

            // put machines in the map into a vector so we can sort them
            std::transform(_priorityMachines.begin(), _priorityMachines.end(), std::back_inserter(machineVector),
                [](PriorityMachineSet::value_type val) { return val; });

            // sort of load balancing, better machines get assigned jobs first
            std::sort(machineVector.begin(), machineVector.end(), [](PriorityMachine* m1, PriorityMachine* m2) {
                double score1 = ((m1->GetMaxJobs() - m1->GetNumberOfCurrentJobs()) + m1->GetAvailableDiskSpace() + m1->GetAvailableRAM());
                double score2 = ((m2->GetMaxJobs() - m2->GetNumberOfCurrentJobs()) + m2->GetAvailableDiskSpace() + m2->GetAvailableRAM());

                return score1 > score2;
            });

            for (auto& mach : machineVector)
            {
                if (mach->AddJob(job))
                {
                    sLog(Console)->Log("Job %s added to machine %s", job->GetName().c_str(), mach->GetName().c_str());
                    _waitingJobs.pop();
                }
            }
        }
    }

    _idleUsers.Update(diff);
}

bool GridManager::AddJob(Job* job)
{
    if (!job)
    {
        sLog(Console)->Log("GridManager::AddJob: Tried to added a Job with null pointer");
        return false;
    }

    _waitingJobs.push(job);

    return true;
}

bool GridManager::AddJobByUser(User* user, Job* job)
{
    if (!user)
    {
        sLog(Console)->Log("GridManager::AddJobByUser: Tried to added a Job with user null pointer");
        return false;
    }

    if (!job)
    {
        sLog(Console)->Log("GridManager::AddJobByUser: Tried to added a Job with job null pointer");
        return false;
    }

    if (!user->CanCreateJob(job))
        throw std::runtime_error("Can't create Job because User doesn't have enough budget.");

    if (!AddJob(job))
        return false;

    user->CreatedJob(job);

    return true;
}

template<>
std::vector<const Job*> GridManager::ApplyPredicate<Job>(std::function<bool(const Job*)> predicate) const
{
    std::vector<const Job*> result;

    for (auto machine : _machines)
        for (auto job : machine->GetJobs())
            if (predicate(job))
                result.push_back(job);

    for (auto pmachine : _priorityMachines)
        for (auto job : pmachine->GetJobs())
            if (predicate(job))
                result.push_back(job);

    return result;
}

template<>
std::vector<const User*> GridManager::ApplyPredicate<User>(std::function<bool(const User*)> predicate) const
{
    std::vector<const User*> result;

    for (auto user : _users)
        if (predicate(user))
            result.push_back(user);

    return result;
}

template<>
std::vector<const IdleUser*> GridManager::ApplyPredicate<IdleUser>(std::function<bool(const IdleUser*)> predicate) const
{
    std::vector<const IdleUser*> result;

    for (auto iu : _idleUsers.GetContainer())
        if (predicate(iu.second))
            result.push_back(iu.second);

    return result;
}

template<>
std::vector<const Machine*> GridManager::ApplyPredicate<Machine>(std::function<bool(const Machine*)> predicate) const
{
    std::vector<const Machine*> result;

    for (auto machine : _machines)
        if (predicate(machine))
            result.push_back(machine);

    return result;
}

template<>
std::vector<const PriorityMachine*> GridManager::ApplyPredicate<PriorityMachine>(std::function<bool(const PriorityMachine*)> predicate) const
{
    std::vector<const PriorityMachine*> result;

    for (auto machine : _priorityMachines)
        if (predicate(machine))
            result.push_back(machine);

    return result;
}

uint GridManager::AddUser(User* user)
{
    if (!user)
        return 0;

    if (user->GetId() == 0) // inserting new user
    {
        _lastUserId++;
        user->SetId(_lastUserId);
    }

    _users.insert(user);

    return user->GetId();
}

uint GridManager::AddMachine(Machine* machine)
{
    if (!machine)
        return 0;

    if (machine->GetId() == 0) // inserting new machine
    {
        _lastMachineId++;
        machine->SetId(_lastMachineId);
    }

    _machines.insert(machine);

    return machine->GetId();
}

uint GridManager::GetNumberOfJobs() const
{
    return std::accumulate(_machines.begin(), _machines.end(), 0,
        [](uint sum, Machine* mach) { return sum + mach->GetNumberOfCurrentJobs(); }) +
           std::accumulate(_priorityMachines.begin(), _priorityMachines.end(), 0,
        [](uint sum, PriorityMachine* pMach) { return sum + pMach->GetNumberOfCurrentJobs(); });
}

bool GridManager::RemoveMachineJob(Machine* machine, uint jobId)
{
    if (!machine)
    {
        sLog(Console)->Log("GridManager::RemoveMachineJob: Tried to remove machine with machine null pointer");
        return false;
    }

    return machine->RemoveJob(jobId);
}

uint32 GridManager::AddPriorityMachine(PriorityMachine* machine)
{
    if (!machine)
        return 0;

    if (machine->GetId() == 0) // inserting new machine
    {
        _lastMachineId++;
        machine->SetId(_lastMachineId);
    }

    _priorityMachines.insert(machine);

    return machine->GetId();
}
<|endoftext|>


<commit_before>//Source file for the Transfer Tech & Upgrades hook module.
//This controls how technologies and upgrades are transferred when units are
//passed from one player to another, either by triggers or casting Mind Control.
#include "transfer_tech_upgrades.h"
#include <SCBW/api.h>

namespace {

typedef int (__stdcall *SErrSetLastErrorFunc)(int);
SErrSetLastErrorFunc const SErrSetLastError = (SErrSetLastErrorFunc) 0x00410172;

struct TechTransferData {
  u16 unitId;
  u16 relatedTech[5]; //Maximum number of tech (use TechId::None to mark a premature end-of-list)
};

const TechTransferData techTransferData[] = {
  //Terran
  {UnitId::marine, TechId::Stimpacks, TechId::None},
  {UnitId::firebat, TechId::Stimpacks, TechId::None},
  {UnitId::ghost, TechId::Lockdown, TechId::PersonnelCloaking, TechId::None},
  {UnitId::medic, TechId::Healing, TechId::Restoration, TechId::OpticalFlare, TechId::None},
  {UnitId::vulture, TechId::SpiderMines, TechId::None},
  {UnitId::siege_tank, TechId::TankSiegeMode, TechId::None},
  {UnitId::siege_tank_s, TechId::TankSiegeMode, TechId::None},
  {UnitId::wraith, TechId::CloakingField, TechId::None},
  {UnitId::science_vessel, TechId::DefensiveMatrix, TechId::Irradiate, TechId::EMPShockwave, TechId::None},
  {UnitId::battlecruiser, TechId::YamatoGun, TechId::None},

  //Zerg
  {UnitId::queen, TechId::Infestation, TechId::Parasite, TechId::SpawnBroodlings, TechId::Ensnare, TechId::None},
  {UnitId::defiler, TechId::Burrowing, TechId::DarkSwarm, TechId::Plague, TechId::Consume, TechId::None},
  {UnitId::drone, TechId::Burrowing, TechId::None},
  {UnitId::zergling, TechId::Burrowing, TechId::None},
  {UnitId::hydralisk, TechId::Burrowing, TechId::LurkerAspect, TechId::None},
  {UnitId::infested_terran, TechId::Burrowing, TechId::None},
  {UnitId::lurker, TechId::LurkerAspect, TechId::None},

  //Protoss
  {UnitId::high_templar, TechId::ArchonWarp, TechId::PsionicStorm, TechId::Hallucination, TechId::None},
  {UnitId::arbiter, TechId::Recall, TechId::StasisField, TechId::None},
  {UnitId::corsair, TechId::DisruptionWeb, TechId::None},
  {UnitId::dark_templar, TechId::DarkArchonMeld, TechId::None},
  {UnitId::dark_archon, TechId::MindControl, TechId::Feedback, TechId::Maelstrom, TechId::None},
};

struct UpgradeTransferData {
  u16 unitId;
  u16 relatedUpgrades[4]; //Maximum number of tech (use UpgradeId::None to mark a premature end-of-list)
};

const UpgradeTransferData upgradeTransferData[] = {
  //Terran
  {UnitId::marine, UpgradeId::U_238Shells, UpgradeId::None},
  {UnitId::ghost, UpgradeId::OcularImplants, UpgradeId::MoebiusReactor, UpgradeId::None},
  {UnitId::medic, UpgradeId::CaduceusReactor, UpgradeId::None},
  {UnitId::vulture, UpgradeId::IonThrusters, UpgradeId::None},
  {UnitId::goliath, UpgradeId::CharonBooster, UpgradeId::None},
  {UnitId::science_vessel, UpgradeId::TitanReactor, UpgradeId::None},
  {UnitId::wraith, UpgradeId::ApolloReactor, UpgradeId::None},
  {UnitId::battlecruiser, UpgradeId::ColossusReactor, UpgradeId::None},

  //Zerg
  {UnitId::overlord, UpgradeId::VentralSacs, UpgradeId::Antennae, UpgradeId::None},
  {UnitId::zergling, UpgradeId::MetabolicBoost, UpgradeId::AdrenalGlands, UpgradeId::None},
  {UnitId::hydralisk, UpgradeId::MuscularAugments, UpgradeId::GroovedSpines, UpgradeId::None},
  {UnitId::queen, UpgradeId::GameteMeiosis, UpgradeId::None},
  {UnitId::defiler, UpgradeId::MetasynapticNode, UpgradeId::None},
  {UnitId::ultralisk, UpgradeId::AnabolicSynthesis, UpgradeId::ChitinousPlating, UpgradeId::None},

  //Protoss
  {UnitId::zealot, UpgradeId::LegEnhancements, UpgradeId::None},
  {UnitId::dragoon, UpgradeId::SingularityCharge, UpgradeId::None},
  {UnitId::high_templar, UpgradeId::KhaydarinAmulet, UpgradeId::None},
  {UnitId::dark_archon, UpgradeId::ArgusTalisman, UpgradeId::None},
  {UnitId::reaver, UpgradeId::ScarabDamage, UpgradeId::ReaverCapacity, UpgradeId::None},
  {UnitId::shuttle, UpgradeId::GraviticDrive, UpgradeId::None},
  {UnitId::observer, UpgradeId::SensorArray, UpgradeId::GraviticBoosters, UpgradeId::None},
  {UnitId::scout, UpgradeId::ApialSensors, UpgradeId::GraviticThrusters, UpgradeId::None},
  {UnitId::carrier, UpgradeId::CarrierCapacity, UpgradeId::None},
  {UnitId::arbiter, UpgradeId::KhaydarinCore, UpgradeId::None},
  {UnitId::corsair, UpgradeId::ArgusJewel, UpgradeId::None},
};

} //Unnamed namespace

namespace hooks {

//Transfers all tech related to the @p source unit to @p targetPlayerId.
void transferUnitTechToPlayerHook(const CUnit *source, u8 targetPlayerId) {
  //Default StarCraft behavior

  //Stop if the source unit does not exist
  if (!source) {
    SErrSetLastError(87);
    return;
  }

  for (int i = 0; i < ARRAY_SIZE(techTransferData); ++i) {
    const TechTransferData *data = &techTransferData[i];

    if (source->id == data->unitId) {
      for (int t = 0; t < ARRAY_SIZE(data->relatedTech); ++i) {
        u16 techId = data->relatedTech[t];
        if (techId == TechId::None) break;

        if (scbw::hasTechResearched(source->playerId, techId)
            && !scbw::hasTechResearched(targetPlayerId, techId))
        {
          if (techId < TechId::Restoration)
            Tech::ResearchedSc->enabled[targetPlayerId][techId] = 1;
          else if (scbw::isBroodWarMode())
            Tech::ResearchedBw->enabled[targetPlayerId][techId] = 1;
        }
      }
    }
  }
}

//Transfers all upgrades related to the @p source unit to @p targetPlayerId.
void transferUnitUpgradesToPlayerHook(const CUnit *source, u8 targetPlayerId) {
  //Default StarCraft behavior

  //Stop if the source unit does not exist
  if (!source) {
    SErrSetLastError(87);
    return;
  }

  for (int i = 0; i < ARRAY_SIZE(upgradeTransferData); ++i) {
    const UpgradeTransferData *data = &upgradeTransferData[i];

    if (source->id == data->unitId) {
      for (int t = 0; t < ARRAY_SIZE(data->relatedUpgrades); ++i) {
        u16 upgradeId = data->relatedUpgrades[t];
        if (upgradeId == UpgradeId::None) break;

        u8 sourceUpgradeLevel = scbw::getUpgradeLevel(source->playerId, upgradeId);
        if (sourceUpgradeLevel > scbw::getUpgradeLevel(targetPlayerId, upgradeId))
        {
          if (upgradeId < UpgradeId::UnusedUpgrade46)
            Upgrade::CurrentUpgSc->level[targetPlayerId][upgradeId] = sourceUpgradeLevel;
          else if (scbw::isBroodWarMode())
            Upgrade::CurrentUpgBw->level[targetPlayerId][upgradeId - UpgradeId::UnusedUpgrade46] = sourceUpgradeLevel;
        }
      }
    }
  }
}

} //hooks
<commit_msg>Updated Transfer Tech & Upgrades hook module to use scbw::setTechResearchState() and scbw::setUpgradeLevel().<commit_after>//Source file for the Transfer Tech & Upgrades hook module.
//This controls how technologies and upgrades are transferred when units are
//passed from one player to another, either by triggers or casting Mind Control.
#include "transfer_tech_upgrades.h"
#include <SCBW/api.h>

namespace {

typedef int (__stdcall *SErrSetLastErrorFunc)(int);
SErrSetLastErrorFunc const SErrSetLastError = (SErrSetLastErrorFunc) 0x00410172;

struct TechTransferData {
  u16 unitId;
  u16 relatedTech[5]; //Maximum number of tech (use TechId::None to mark a premature end-of-list)
};

const TechTransferData techTransferData[] = {
  //Terran
  {UnitId::marine, TechId::Stimpacks, TechId::None},
  {UnitId::firebat, TechId::Stimpacks, TechId::None},
  {UnitId::ghost, TechId::Lockdown, TechId::PersonnelCloaking, TechId::None},
  {UnitId::medic, TechId::Healing, TechId::Restoration, TechId::OpticalFlare, TechId::None},
  {UnitId::vulture, TechId::SpiderMines, TechId::None},
  {UnitId::siege_tank, TechId::TankSiegeMode, TechId::None},
  {UnitId::siege_tank_s, TechId::TankSiegeMode, TechId::None},
  {UnitId::wraith, TechId::CloakingField, TechId::None},
  {UnitId::science_vessel, TechId::DefensiveMatrix, TechId::Irradiate, TechId::EMPShockwave, TechId::None},
  {UnitId::battlecruiser, TechId::YamatoGun, TechId::None},

  //Zerg
  {UnitId::queen, TechId::Infestation, TechId::Parasite, TechId::SpawnBroodlings, TechId::Ensnare, TechId::None},
  {UnitId::defiler, TechId::Burrowing, TechId::DarkSwarm, TechId::Plague, TechId::Consume, TechId::None},
  {UnitId::drone, TechId::Burrowing, TechId::None},
  {UnitId::zergling, TechId::Burrowing, TechId::None},
  {UnitId::hydralisk, TechId::Burrowing, TechId::LurkerAspect, TechId::None},
  {UnitId::infested_terran, TechId::Burrowing, TechId::None},
  {UnitId::lurker, TechId::LurkerAspect, TechId::None},

  //Protoss
  {UnitId::high_templar, TechId::ArchonWarp, TechId::PsionicStorm, TechId::Hallucination, TechId::None},
  {UnitId::arbiter, TechId::Recall, TechId::StasisField, TechId::None},
  {UnitId::corsair, TechId::DisruptionWeb, TechId::None},
  {UnitId::dark_templar, TechId::DarkArchonMeld, TechId::None},
  {UnitId::dark_archon, TechId::MindControl, TechId::Feedback, TechId::Maelstrom, TechId::None},
};

struct UpgradeTransferData {
  u16 unitId;
  u16 relatedUpgrades[4]; //Maximum number of tech (use UpgradeId::None to mark a premature end-of-list)
};

const UpgradeTransferData upgradeTransferData[] = {
  //Terran
  {UnitId::marine, UpgradeId::U_238Shells, UpgradeId::None},
  {UnitId::ghost, UpgradeId::OcularImplants, UpgradeId::MoebiusReactor, UpgradeId::None},
  {UnitId::medic, UpgradeId::CaduceusReactor, UpgradeId::None},
  {UnitId::vulture, UpgradeId::IonThrusters, UpgradeId::None},
  {UnitId::goliath, UpgradeId::CharonBooster, UpgradeId::None},
  {UnitId::science_vessel, UpgradeId::TitanReactor, UpgradeId::None},
  {UnitId::wraith, UpgradeId::ApolloReactor, UpgradeId::None},
  {UnitId::battlecruiser, UpgradeId::ColossusReactor, UpgradeId::None},

  //Zerg
  {UnitId::overlord, UpgradeId::VentralSacs, UpgradeId::Antennae, UpgradeId::None},
  {UnitId::zergling, UpgradeId::MetabolicBoost, UpgradeId::AdrenalGlands, UpgradeId::None},
  {UnitId::hydralisk, UpgradeId::MuscularAugments, UpgradeId::GroovedSpines, UpgradeId::None},
  {UnitId::queen, UpgradeId::GameteMeiosis, UpgradeId::None},
  {UnitId::defiler, UpgradeId::MetasynapticNode, UpgradeId::None},
  {UnitId::ultralisk, UpgradeId::AnabolicSynthesis, UpgradeId::ChitinousPlating, UpgradeId::None},

  //Protoss
  {UnitId::zealot, UpgradeId::LegEnhancements, UpgradeId::None},
  {UnitId::dragoon, UpgradeId::SingularityCharge, UpgradeId::None},
  {UnitId::high_templar, UpgradeId::KhaydarinAmulet, UpgradeId::None},
  {UnitId::dark_archon, UpgradeId::ArgusTalisman, UpgradeId::None},
  {UnitId::reaver, UpgradeId::ScarabDamage, UpgradeId::ReaverCapacity, UpgradeId::None},
  {UnitId::shuttle, UpgradeId::GraviticDrive, UpgradeId::None},
  {UnitId::observer, UpgradeId::SensorArray, UpgradeId::GraviticBoosters, UpgradeId::None},
  {UnitId::scout, UpgradeId::ApialSensors, UpgradeId::GraviticThrusters, UpgradeId::None},
  {UnitId::carrier, UpgradeId::CarrierCapacity, UpgradeId::None},
  {UnitId::arbiter, UpgradeId::KhaydarinCore, UpgradeId::None},
  {UnitId::corsair, UpgradeId::ArgusJewel, UpgradeId::None},
};

} //Unnamed namespace

namespace hooks {

//Transfers all tech related to the @p source unit to @p targetPlayerId.
void transferUnitTechToPlayerHook(const CUnit *source, u8 targetPlayerId) {
  //Default StarCraft behavior

  //Stop if the source unit does not exist
  if (!source) {
    SErrSetLastError(87);
    return;
  }

  for (int i = 0; i < ARRAY_SIZE(techTransferData); ++i) {
    const TechTransferData *data = &techTransferData[i];

    if (source->id == data->unitId) {
      for (int t = 0; t < ARRAY_SIZE(data->relatedTech); ++i) {
        u16 techId = data->relatedTech[t];
        if (techId == TechId::None) break;

        if (scbw::hasTechResearched(source->playerId, techId)
            && !scbw::hasTechResearched(targetPlayerId, techId))
          scbw::setTechResearchState(targetPlayerId, techId, true);
      }
    }
  }
}

//Transfers all upgrades related to the @p source unit to @p targetPlayerId.
void transferUnitUpgradesToPlayerHook(const CUnit *source, u8 targetPlayerId) {
  //Default StarCraft behavior

  //Stop if the source unit does not exist
  if (!source) {
    SErrSetLastError(87);
    return;
  }

  for (int i = 0; i < ARRAY_SIZE(upgradeTransferData); ++i) {
    const UpgradeTransferData *data = &upgradeTransferData[i];

    if (source->id == data->unitId) {
      for (int t = 0; t < ARRAY_SIZE(data->relatedUpgrades); ++i) {
        u16 upgradeId = data->relatedUpgrades[t];
        if (upgradeId == UpgradeId::None) break;

        u8 sourceUpgradeLevel = scbw::getUpgradeLevel(source->playerId, upgradeId);
        if (sourceUpgradeLevel > scbw::getUpgradeLevel(targetPlayerId, upgradeId))
          scbw::setUpgradeLevel(targetPlayerId, upgradeId, sourceUpgradeLevel);
      }
    }
  }
}

} //hooks
<|endoftext|>


<commit_before>/*
 * (C) 2009 Nikhil Marathe <nsm.nikhil@gmail.com>
 * Licensed under the GNU General Public License.
 * See LICENSE for details
 */
#include "messagedialog.h"

#include "qommunicate.h"
#include "messenger.h"
#include "constants.h"
#include "sendfileprogressdialog.h"

MessageDialog::MessageDialog(Member* receiver, QWidget *parent) : QDialog(0)
{
    receivers << receiver;
    ui.setupUi(this);
    messageTimer = NULL;

    m_online = true;
    setWindowTitle(tr("Conversation: %1").arg(receiver->name()));
    connect(messenger(), SIGNAL(msg_recvMsg(Message)), this, SLOT(incomingMessage(Message)));
    connect(messenger(), SIGNAL(msg_recvConfirmMsg(Message)), this, SLOT(messageRecvConfirm(Message)));
    connect(messenger(), SIGNAL(msg_exit(Message)), this, SLOT(userOffline(Message)));
    connect(messenger(), SIGNAL(msg_entry(Message)), this, SLOT(userOnline(Message)));

    ((Qommunicate*)parent)->dialogOpened(receiver);

}

MessageDialog::MessageDialog(QList<Member*> receivers, QWidget *parent) : QDialog(parent)
{
    this->receivers = receivers;

    ui.setupUi(this);

    QStringList titleRecvs;
    Member* t;
    foreach(t, receivers)
        titleRecvs << t->name();
    setWindowTitle(tr("Conversation: %1").arg(titleRecvs.join(",")));
}

MessageDialog::MessageDialog(QWidget *parent) : QDialog(parent)
{
    ui.setupUi(this);
    setWindowTitle(tr("Multicast message"));
    // no notifications for multicast
    // TODO: is that the right choice?
    ui.notifyReadCB->setEnabled(false);
}

void MessageDialog::reject()
{
    if(receivers.size() == 1)
        ((Qommunicate*) parent())->dialogClosed(receivers[0]);
    QDialog::reject();
}

void MessageDialog::incomingMessage(Message msg)
{
    if(msg.sender()->addressString() != receivers[0]->addressString())
        return;

    QString text = QString("%1 :  ")
                        .arg(Qt::escape(receivers[0]->name()));
    text += Qt::escape(msg.payload().replace('\a', "").trimmed());
    ui.messageEdit->append(text);
    QApplication::alert(this, 0);

    if(msg.command() & QOM_SENDCHECKOPT)
        messenger()->sendMessage(QOM_RECVMSG, QByteArray::number(msg.packetNo()), msg.sender());

    if(msg.command() & QOM_READCHECKOPT)
        messenger()->sendMessage(QOM_READMSG|(msg.command() & QOM_READCHECKOPT), QByteArray::number(msg.packetNo()), msg.sender());
}

void MessageDialog::on_sendButton_clicked()
{
    if(ui.messageInput->text().trimmed().isEmpty())
        return;

    if(receivers.isEmpty())
    {
        messenger()->multicast(QOM_SENDMSG|QOM_MULTICASTOPT, ui.messageInput->text().toAscii());
        QTimer::singleShot(500, this, SLOT(accept()));
        return;
    }

    int flags = QOM_SENDMSG | QOM_SENDCHECKOPT |
                (receivers.size() > 1 ? QOM_MULTICASTOPT : 0) |
                (ui.notifyReadCB->isChecked() ? QOM_READCHECKOPT | QOM_SECRETOPT : 0);

    foreach(Member* m, receivers)
    {
        messenger()->sendMessage( flags, ui.messageInput->text().toAscii(), m);
    }
    if(receivers.size() == 1)
    {
        if(messageTimer != NULL)
            delete messageTimer;
        messageTimer = new QTimer(this);
        messageTimer->setSingleShot(true);
        connect(messageTimer, SIGNAL(timeout()), this, SLOT(messageTimeout()));

        ui.messageInput->setEnabled(false);
        messageTimer->start(5000);
    }
    else
    {
        QTimer::singleShot(500, this, SLOT(accept()));
    }

}

void MessageDialog::messageTimeout()
{
    if(QMessageBox::warning(this,
            tr("Sending Failed"),
            tr("Failed to send message. To retry click Ok"),
            QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok)
    {
        on_sendButton_clicked();
    }
    else
        ui.messageInput->setEnabled(true);
}

void MessageDialog::messageRecvConfirm(Message msg)
{
    if(msg.sender()->addressString() != receivers[0]->addressString())
        return;

    if(! ui.messageInput->text().trimmed().isEmpty())
        ui.messageEdit->append(QString("%1 :  %2")
                            .arg(Qt::escape(me().name()))
                            .arg(Qt::escape(ui.messageInput->text())));

    ui.messageInput->clear();
    ui.messageInput->setEnabled(true);

    if(receivers.size() == 1 && messageTimer != NULL)
        messageTimer->stop();

    ui.messageInput->setFocus();
}

void MessageDialog::userOffline(Message msg)
{
    if(!m_online || msg.sender()->addressString() != receivers[0]->addressString())
        return;

    ui.messageEdit->append(QString("%1 went offline").arg(Qt::escape(msg.sender()->name())));
    ui.messageInput->setEnabled(false);
    m_online = false;
}

void MessageDialog::userOnline(Message msg)
{
    if(m_online || msg.sender()->addressString() != receivers[0]->addressString())
        return;

    ui.messageEdit->append(QString("%1 came online").arg(Qt::escape(msg.sender()->name())));

    ui.messageInput->setEnabled(true);
    m_online = true;
}

void MessageDialog::dropEvent(QDropEvent *evt)
{
    QStringList files;
    foreach(QUrl url, evt->mimeData()->urls())
    {
        files << url.toLocalFile();
    }

    foreach(Member* to, receivers)
    {
        //new FileSendProgressDialog(files, to, ui.messageInput->text());
        fileUtils()->sendFilesUdpRequest(files, to, ui.messageInput->text());
    }
}
<commit_msg>Make parent of QDialogs null to make then perfectly non-modal<commit_after>/*
 * (C) 2009 Nikhil Marathe <nsm.nikhil@gmail.com>
 * Licensed under the GNU General Public License.
 * See LICENSE for details
 */
#include "messagedialog.h"

#include "qommunicate.h"
#include "messenger.h"
#include "constants.h"
#include "sendfileprogressdialog.h"

MessageDialog::MessageDialog(Member* receiver, QWidget *parent) : QDialog(0)
{
    receivers << receiver;
    ui.setupUi(this);
    messageTimer = NULL;

    m_online = true;
    setWindowTitle(tr("Conversation: %1").arg(receiver->name()));
    connect(messenger(), SIGNAL(msg_recvMsg(Message)), this, SLOT(incomingMessage(Message)));
    connect(messenger(), SIGNAL(msg_recvConfirmMsg(Message)), this, SLOT(messageRecvConfirm(Message)));
    connect(messenger(), SIGNAL(msg_exit(Message)), this, SLOT(userOffline(Message)));
    connect(messenger(), SIGNAL(msg_entry(Message)), this, SLOT(userOnline(Message)));

    ((Qommunicate*)parent)->dialogOpened(receiver);

}

MessageDialog::MessageDialog(QList<Member*> receivers, QWidget *parent) : QDialog(0)
{
    this->receivers = receivers;

    ui.setupUi(this);

    QStringList titleRecvs;
    Member* t;
    foreach(t, receivers)
        titleRecvs << t->name();
    setWindowTitle(tr("Conversation: %1").arg(titleRecvs.join(",")));
}

MessageDialog::MessageDialog(QWidget *parent) : QDialog(0)
{
    ui.setupUi(this);
    setWindowTitle(tr("Multicast message"));
    // no notifications for multicast
    // TODO: is that the right choice?
    ui.notifyReadCB->setEnabled(false);
}

void MessageDialog::reject()
{
    if(receivers.size() == 1)
        ((Qommunicate*) parent())->dialogClosed(receivers[0]);
    QDialog::reject();
}

void MessageDialog::incomingMessage(Message msg)
{
    if(msg.sender()->addressString() != receivers[0]->addressString())
        return;

    QString text = QString("%1:  ")
                        .arg(Qt::escape(receivers[0]->name()));
    text += Qt::escape(msg.payload().replace('\a', "").trimmed());
    ui.messageEdit->append(text);
    QApplication::alert(this, 0);

    if(msg.command() & QOM_SENDCHECKOPT)
        messenger()->sendMessage(QOM_RECVMSG, QByteArray::number(msg.packetNo()), msg.sender());

    if(msg.command() & QOM_READCHECKOPT)
        messenger()->sendMessage(QOM_READMSG|(msg.command() & QOM_READCHECKOPT), QByteArray::number(msg.packetNo()), msg.sender());
}

void MessageDialog::on_sendButton_clicked()
{
    if(ui.messageInput->text().trimmed().isEmpty())
        return;

    if(receivers.isEmpty())
    {
        messenger()->multicast(QOM_SENDMSG|QOM_MULTICASTOPT, ui.messageInput->text().toAscii());
        QTimer::singleShot(500, this, SLOT(accept()));
        return;
    }

    int flags = QOM_SENDMSG | QOM_SENDCHECKOPT |
                (receivers.size() > 1 ? QOM_MULTICASTOPT : 0) |
                (ui.notifyReadCB->isChecked() ? QOM_READCHECKOPT | QOM_SECRETOPT : 0);

    foreach(Member* m, receivers)
    {
        messenger()->sendMessage( flags, ui.messageInput->text().toAscii(), m);
    }
    if(receivers.size() == 1)
    {
        if(messageTimer != NULL)
            delete messageTimer;
        messageTimer = new QTimer(this);
        messageTimer->setSingleShot(true);
        connect(messageTimer, SIGNAL(timeout()), this, SLOT(messageTimeout()));

        ui.messageInput->setEnabled(false);
        messageTimer->start(5000);
    }
    else
    {
        QTimer::singleShot(500, this, SLOT(accept()));
    }

}

void MessageDialog::messageTimeout()
{
    if(QMessageBox::warning(this,
            tr("Sending Failed"),
            tr("Failed to send message. To retry click Ok"),
            QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok)
    {
        on_sendButton_clicked();
    }
    else
        ui.messageInput->setEnabled(true);
}

void MessageDialog::messageRecvConfirm(Message msg)
{
    if(msg.sender()->addressString() != receivers[0]->addressString())
        return;

    if(! ui.messageInput->text().trimmed().isEmpty())
        ui.messageEdit->append(QString("%1:  %2")
                            .arg(Qt::escape(me().name()))
                            .arg(Qt::escape(ui.messageInput->text())));

    ui.messageInput->clear();
    ui.messageInput->setEnabled(true);

    if(receivers.size() == 1 && messageTimer != NULL)
        messageTimer->stop();

    ui.messageInput->setFocus();
}

void MessageDialog::userOffline(Message msg)
{
    if(!m_online || msg.sender()->addressString() != receivers[0]->addressString())
        return;

    ui.messageEdit->append(QString("%1 went offline").arg(Qt::escape(msg.sender()->name())));
    ui.messageInput->setEnabled(false);
    m_online = false;
}

void MessageDialog::userOnline(Message msg)
{
    if(m_online || msg.sender()->addressString() != receivers[0]->addressString())
        return;

    ui.messageEdit->append(QString("%1 came online").arg(Qt::escape(msg.sender()->name())));

    ui.messageInput->setEnabled(true);
    m_online = true;
}

void MessageDialog::dropEvent(QDropEvent *evt)
{
    QStringList files;
    foreach(QUrl url, evt->mimeData()->urls())
    {
        files << url.toLocalFile();
    }

    foreach(Member* to, receivers)
    {
        //new FileSendProgressDialog(files, to, ui.messageInput->text());
        fileUtils()->sendFilesUdpRequest(files, to, ui.messageInput->text());
    }
}
<|endoftext|>


<commit_before>/*
Copyright 2016 Peter Repukat - FlatspotSoftware

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.
*/
#include "GloSC_GameLauncher.h"

GloSC_GameLauncher::GloSC_GameLauncher(QWidget *parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);

	QTimer::singleShot(0, this, SLOT(hide()));

	sharedMemInstance.setKey("GloSC_GameLauncher");
	sharedMemInstance.create(1024);

	if (!sharedMemInstance.create(1024) && sharedMemInstance.error() == QSharedMemory::AlreadyExists)
	{
		exit(1);
	}

	sharedMemInstance.attach();
	sharedMemInstance.lock();
	memset(sharedMemInstance.data(), NULL, 1024);

	QBuffer buffer;
	buffer.open(QBuffer::ReadWrite);
	QDataStream out(&buffer);
	out << defaultSharedMemData;
	int size = buffer.size();
	char *to = (char*)sharedMemInstance.data();
	const char *from = buffer.data().data();
	memcpy(to, from, qMin(sharedMemInstance.size(), size));

	sharedMemInstance.unlock();

	connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(isAboutToBeKilled()));
	connect(&updateTimer, SIGNAL(timeout()), this, SLOT(checkSharedMem()));

	updateTimer.setInterval(333);
	updateTimer.start();
}

void GloSC_GameLauncher::isAboutToBeKilled()
{
	sharedMemInstance.detach();
}

void GloSC_GameLauncher::checkSharedMem()
{
	QBuffer buffer;
	QDataStream dataStream(&buffer);
	QStringList stringList;

	sharedMemInstance.lock();

	buffer.setData((char*)sharedMemInstance.constData(), sharedMemInstance.size());
	buffer.open(QBuffer::ReadOnly);
	dataStream >> stringList;
	buffer.close();
	int i = stringList.indexOf(LaunchGame);
	if (i > -1)
	{
		if (stringList.at(i + 1) != "" && stringList.at(i + 2) != "")
		{
			launchGame(stringList.at(i + 1), stringList.at(i + 2));
			stringList = defaultSharedMemData;
		}
	}

	i = stringList.indexOf(IsSteamHooked);
	if (i > -1)
	{
		bHookedSteam = true;
		if (stringList.at(i + 1).toInt() > -1)
		{
			stringList.replace(i + 1, "-1");
		}
	}

	if (pid != NULL)
	{
		if (!IsProcessRunning(pid))
		{
			pid = NULL;
			int i = stringList.indexOf(LaunchedProcessFinished) + 1;
			stringList.replace(i, "1");
		}
	}

	buffer.open(QBuffer::ReadWrite);
	QDataStream out(&buffer);
	out << stringList;
	int size = buffer.size();
	char *to = (char*)sharedMemInstance.data();
	const char *from = buffer.data().data();
	memcpy(to, from, qMin(sharedMemInstance.size(), size));
	buffer.close();

	sharedMemInstance.unlock();

	if (FindWindow(NULL, L"GloSC_OverlayWindow") == NULL)
	{
		unhookBindings();
		bHookedSteam = false;
	}
}

void GloSC_GameLauncher::launchGame(QString type, QString path)
{

		if (type == LGT_Win32)
		{
			QProcess app;
			if (path.contains("\\"))
			{
				app.startDetached(path, QStringList(), path.mid(0, path.lastIndexOf("\\")), &pid);
			}
			else
			{
				app.startDetached(path, QStringList(), path.mid(0, path.lastIndexOf("/")), &pid);

			}
		} else if (type == LGT_UWP) {
			DWORD pid = 0;
			HRESULT hr = CoInitialize(nullptr);
			std::wstring appUMId = path.toStdWString();
			if (SUCCEEDED(hr)) {
				HRESULT result = LaunchUWPApp(appUMId.c_str(), &pid);
				if (SUCCEEDED(result))
				{
					this->pid = pid;

				}
			}
			CoUninitialize();

		}
}

HRESULT GloSC_GameLauncher::LaunchUWPApp(LPCWSTR packageFullName, PDWORD pdwProcessId)
{

	CComPtr<IApplicationActivationManager> spAppActivationManager;
	HRESULT result = E_INVALIDARG;
	// Initialize IApplicationActivationManager
	result = CoCreateInstance(CLSID_ApplicationActivationManager, NULL, CLSCTX_LOCAL_SERVER, IID_IApplicationActivationManager, (LPVOID*)&spAppActivationManager);

	if (!SUCCEEDED(result))
		return result;

	//This call causes troubles; especially with our always in foreground overlay-window
	/*
	// This call ensures that the app is launched as the foreground window
	result = CoAllowSetForegroundWindow(spAppActivationManager, NULL);

	if (!SUCCEEDED(result))
		return result;
		*/

	// Launch the app
	result = spAppActivationManager->ActivateApplication(packageFullName, NULL, AO_NONE, pdwProcessId);

	return result;
}

bool GloSC_GameLauncher::IsProcessRunning(DWORD pid)
{
	HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, pid);
	DWORD ret = WaitForSingleObject(process, 1);
	CloseHandle(process);
	return ret == WAIT_TIMEOUT;
}

void GloSC_GameLauncher::unhookBindings()
{
	QProcess proc;
	proc.setNativeArguments(" --eject ");
	proc.start("Injector.exe", QIODevice::ReadOnly);
	proc.waitForFinished();
	bHookedSteam = false;
}

<commit_msg>fix: trying to permanently unhook steam when overlaywindow is not found<commit_after>/*
Copyright 2016 Peter Repukat - FlatspotSoftware

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.
*/
#include "GloSC_GameLauncher.h"

GloSC_GameLauncher::GloSC_GameLauncher(QWidget *parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);

	QTimer::singleShot(0, this, SLOT(hide()));

	sharedMemInstance.setKey("GloSC_GameLauncher");
	sharedMemInstance.create(1024);

	if (!sharedMemInstance.create(1024) && sharedMemInstance.error() == QSharedMemory::AlreadyExists)
	{
		exit(1);
	}

	sharedMemInstance.attach();
	sharedMemInstance.lock();
	memset(sharedMemInstance.data(), NULL, 1024);

	QBuffer buffer;
	buffer.open(QBuffer::ReadWrite);
	QDataStream out(&buffer);
	out << defaultSharedMemData;
	int size = buffer.size();
	char *to = (char*)sharedMemInstance.data();
	const char *from = buffer.data().data();
	memcpy(to, from, qMin(sharedMemInstance.size(), size));

	sharedMemInstance.unlock();

	connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(isAboutToBeKilled()));
	connect(&updateTimer, SIGNAL(timeout()), this, SLOT(checkSharedMem()));

	updateTimer.setInterval(333);
	updateTimer.start();
}

void GloSC_GameLauncher::isAboutToBeKilled()
{
	sharedMemInstance.detach();
}

void GloSC_GameLauncher::checkSharedMem()
{
	QBuffer buffer;
	QDataStream dataStream(&buffer);
	QStringList stringList;

	sharedMemInstance.lock();

	buffer.setData((char*)sharedMemInstance.constData(), sharedMemInstance.size());
	buffer.open(QBuffer::ReadOnly);
	dataStream >> stringList;
	buffer.close();
	int i = stringList.indexOf(LaunchGame);
	if (i > -1)
	{
		if (stringList.at(i + 1) != "" && stringList.at(i + 2) != "")
		{
			launchGame(stringList.at(i + 1), stringList.at(i + 2));
			stringList = defaultSharedMemData;
		}
	}

	i = stringList.indexOf(IsSteamHooked);
	if (i > -1)
	{
		bHookedSteam = true;
		if (stringList.at(i + 1).toInt() > -1)
		{
			stringList.replace(i + 1, "-1");
		}
	}

	if (pid != NULL)
	{
		if (!IsProcessRunning(pid))
		{
			pid = NULL;
			int i = stringList.indexOf(LaunchedProcessFinished) + 1;
			stringList.replace(i, "1");
		}
	}

	buffer.open(QBuffer::ReadWrite);
	QDataStream out(&buffer);
	out << stringList;
	int size = buffer.size();
	char *to = (char*)sharedMemInstance.data();
	const char *from = buffer.data().data();
	memcpy(to, from, qMin(sharedMemInstance.size(), size));
	buffer.close();

	sharedMemInstance.unlock();

	if (bHookedSteam && FindWindow(NULL, L"GloSC_OverlayWindow") == NULL)
	{
		unhookBindings();
	}
}

void GloSC_GameLauncher::launchGame(QString type, QString path)
{

		if (type == LGT_Win32)
		{
			QProcess app;
			if (path.contains("\\"))
			{
				app.startDetached(path, QStringList(), path.mid(0, path.lastIndexOf("\\")), &pid);
			}
			else
			{
				app.startDetached(path, QStringList(), path.mid(0, path.lastIndexOf("/")), &pid);

			}
		} else if (type == LGT_UWP) {
			DWORD pid = 0;
			HRESULT hr = CoInitialize(nullptr);
			std::wstring appUMId = path.toStdWString();
			if (SUCCEEDED(hr)) {
				HRESULT result = LaunchUWPApp(appUMId.c_str(), &pid);
				if (SUCCEEDED(result))
				{
					this->pid = pid;

				}
			}
			CoUninitialize();

		}
}

HRESULT GloSC_GameLauncher::LaunchUWPApp(LPCWSTR packageFullName, PDWORD pdwProcessId)
{

	CComPtr<IApplicationActivationManager> spAppActivationManager;
	HRESULT result = E_INVALIDARG;
	// Initialize IApplicationActivationManager
	result = CoCreateInstance(CLSID_ApplicationActivationManager, NULL, CLSCTX_LOCAL_SERVER, IID_IApplicationActivationManager, (LPVOID*)&spAppActivationManager);

	if (!SUCCEEDED(result))
		return result;

	//This call causes troubles; especially with our always in foreground overlay-window
	/*
	// This call ensures that the app is launched as the foreground window
	result = CoAllowSetForegroundWindow(spAppActivationManager, NULL);

	if (!SUCCEEDED(result))
		return result;
		*/

	// Launch the app
	result = spAppActivationManager->ActivateApplication(packageFullName, NULL, AO_NONE, pdwProcessId);

	return result;
}

bool GloSC_GameLauncher::IsProcessRunning(DWORD pid)
{
	HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, pid);
	DWORD ret = WaitForSingleObject(process, 1);
	CloseHandle(process);
	return ret == WAIT_TIMEOUT;
}

void GloSC_GameLauncher::unhookBindings()
{
	QProcess proc;
	proc.setNativeArguments(" --eject ");
	proc.start("Injector.exe", QIODevice::ReadOnly);
	proc.waitForFinished();
	bHookedSteam = false;
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
 * Copyright 2012, 2013 SAP AG. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 *
 */

#ifndef CPU_PPC_VM_GLOBALS_PPC_HPP
#define CPU_PPC_VM_GLOBALS_PPC_HPP

#include "utilities/globalDefinitions.hpp"
#include "utilities/macros.hpp"

// Sets the default values for platform dependent flags used by the runtime system.
// (see globals.hpp)

define_pd_global(bool, ConvertSleepToYield,   true);
define_pd_global(bool, ShareVtableStubs,      false); // Improves performance markedly for mtrt and compress.
define_pd_global(bool, NeedsDeoptSuspend,     false); // Only register window machines need this.

define_pd_global(bool, ImplicitNullChecks,    true);  // Generate code for implicit null checks.
define_pd_global(bool, UncommonNullCast,      true);  // Uncommon-trap NULLs passed to check cast.

// Use large code-entry alignment.
define_pd_global(intx, CodeEntryAlignment,    128);
define_pd_global(intx, OptoLoopAlignment,     16);
define_pd_global(intx, InlineFrequencyCount,  100);
define_pd_global(intx, InlineSmallCode,       1500);

define_pd_global(intx, PreInflateSpin,        10);

// Flags for template interpreter.
define_pd_global(bool, RewriteBytecodes,      true);
define_pd_global(bool, RewriteFrequentPairs,  true);

define_pd_global(bool, UseMembar,             false);

// GC Ergo Flags
define_pd_global(intx, CMSYoungGenPerWorker,  16*M);  // Default max size of CMS young gen, per GC worker thread.

// Platform dependent flag handling: flags only defined on this platform.
#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct)  \
  product(uintx, PowerArchitecturePPC64, 0,                                 \
          "CPU Version: x for PowerX. Currently recognizes Power5 to "      \
          "Power7. Default is 0. CPUs newer than Power7 will be "           \
          "recognized as Power7.")                                          \
                                                                            \
  /* Reoptimize code-sequences of calls at runtime, e.g. replace an */      \
  /* indirect call by a direct call.                                */      \
  product(bool, ReoptimizeCallSequences, true,                              \
          "Reoptimize code-sequences of calls at runtime.")                 \
                                                                            \
  product(bool, UseLoadInstructionsForStackBangingPPC64, false,             \
          "Use load instructions for stack banging.")                       \
                                                                            \
  /* special instructions */                                                \
                                                                            \
  product(bool, UseCountLeadingZerosInstructionsPPC64, true,                \
          "Use count leading zeros instructions.")                          \
                                                                            \
  product(bool, UseExtendedLoadAndReserveInstructionsPPC64, false,          \
          "Use extended versions of load-and-reserve instructions.")        \
                                                                            \
  product(bool, UseRotateAndMaskInstructionsPPC64, true,                    \
          "Use rotate and mask instructions.")                              \
                                                                            \
  product(bool, UseStaticBranchPredictionInCompareAndSwapPPC64, true,       \
          "Use static branch prediction hints in CAS operations.")          \
                                                                            \
  /* Trap based checks. */                                                  \
  /* Trap based checks use the ppc trap instructions to check certain */    \
  /* conditions. This instruction raises a SIGTRAP caught by the      */    \
  /* exception handler of the VM.                                     */    \
  product(bool, UseSIGTRAP, false,                                          \
          "Allow trap instructions that make use of SIGTRAP. Use this to "  \
          "switch off all optimizations requiring SIGTRAP.")                \
  product(bool, TrapBasedICMissChecks, true,                                \
          "Raise and handle SIGTRAP if inline cache miss detected.")        \
  product(bool, TrapBasedNotEntrantChecks, true,                            \
          "Raise and handle SIGTRAP if calling not entrant or zombie"       \
          " method.")                                                       \
  product(bool, TrapBasedNullChecks, true,                                  \
          "Generate code for null checks that uses a cmp and trap "         \
          "instruction raising SIGTRAP.  This is only used if an access to" \
          "null (+offset) will not raise a SIGSEGV.")                       \
  product(bool, TrapBasedRangeChecks, true,                                 \
          "Raise and handle SIGTRAP if array out of bounds check fails.")   \
  product(bool, TraceTraps, false, "Trace all traps the signal handler"     \
          "handles.")                                                       \
                                                                            \
  product(bool, ZapMemory, false, "Write 0x0101... to empty memory."        \
          " Use this to ease debugging.")                                   \

#endif // CPU_PPC_VM_GLOBALS_PPC_HPP
<commit_msg>8027964: Adapt PPC to 6843347: Boundary values in some public GC options cause crashes Reviewed-by: dholmes<commit_after>/*
 * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
 * Copyright 2012, 2013 SAP AG. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 *
 */

#ifndef CPU_PPC_VM_GLOBALS_PPC_HPP
#define CPU_PPC_VM_GLOBALS_PPC_HPP

#include "utilities/globalDefinitions.hpp"
#include "utilities/macros.hpp"

// Sets the default values for platform dependent flags used by the runtime system.
// (see globals.hpp)

define_pd_global(bool, ConvertSleepToYield,   true);
define_pd_global(bool, ShareVtableStubs,      false); // Improves performance markedly for mtrt and compress.
define_pd_global(bool, NeedsDeoptSuspend,     false); // Only register window machines need this.

define_pd_global(bool, ImplicitNullChecks,    true);  // Generate code for implicit null checks.
define_pd_global(bool, UncommonNullCast,      true);  // Uncommon-trap NULLs passed to check cast.

// Use large code-entry alignment.
define_pd_global(intx, CodeEntryAlignment,    128);
define_pd_global(intx, OptoLoopAlignment,     16);
define_pd_global(intx, InlineFrequencyCount,  100);
define_pd_global(intx, InlineSmallCode,       1500);

define_pd_global(intx, PreInflateSpin,        10);

// Flags for template interpreter.
define_pd_global(bool, RewriteBytecodes,      true);
define_pd_global(bool, RewriteFrequentPairs,  true);

define_pd_global(bool, UseMembar,             false);

// GC Ergo Flags
define_pd_global(uintx, CMSYoungGenPerWorker, 16*M);  // Default max size of CMS young gen, per GC worker thread.

// Platform dependent flag handling: flags only defined on this platform.
#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct)  \
  product(uintx, PowerArchitecturePPC64, 0,                                 \
          "CPU Version: x for PowerX. Currently recognizes Power5 to "      \
          "Power7. Default is 0. CPUs newer than Power7 will be "           \
          "recognized as Power7.")                                          \
                                                                            \
  /* Reoptimize code-sequences of calls at runtime, e.g. replace an */      \
  /* indirect call by a direct call.                                */      \
  product(bool, ReoptimizeCallSequences, true,                              \
          "Reoptimize code-sequences of calls at runtime.")                 \
                                                                            \
  product(bool, UseLoadInstructionsForStackBangingPPC64, false,             \
          "Use load instructions for stack banging.")                       \
                                                                            \
  /* special instructions */                                                \
                                                                            \
  product(bool, UseCountLeadingZerosInstructionsPPC64, true,                \
          "Use count leading zeros instructions.")                          \
                                                                            \
  product(bool, UseExtendedLoadAndReserveInstructionsPPC64, false,          \
          "Use extended versions of load-and-reserve instructions.")        \
                                                                            \
  product(bool, UseRotateAndMaskInstructionsPPC64, true,                    \
          "Use rotate and mask instructions.")                              \
                                                                            \
  product(bool, UseStaticBranchPredictionInCompareAndSwapPPC64, true,       \
          "Use static branch prediction hints in CAS operations.")          \
                                                                            \
  /* Trap based checks. */                                                  \
  /* Trap based checks use the ppc trap instructions to check certain */    \
  /* conditions. This instruction raises a SIGTRAP caught by the      */    \
  /* exception handler of the VM.                                     */    \
  product(bool, UseSIGTRAP, false,                                          \
          "Allow trap instructions that make use of SIGTRAP. Use this to "  \
          "switch off all optimizations requiring SIGTRAP.")                \
  product(bool, TrapBasedICMissChecks, true,                                \
          "Raise and handle SIGTRAP if inline cache miss detected.")        \
  product(bool, TrapBasedNotEntrantChecks, true,                            \
          "Raise and handle SIGTRAP if calling not entrant or zombie"       \
          " method.")                                                       \
  product(bool, TrapBasedNullChecks, true,                                  \
          "Generate code for null checks that uses a cmp and trap "         \
          "instruction raising SIGTRAP.  This is only used if an access to" \
          "null (+offset) will not raise a SIGSEGV.")                       \
  product(bool, TrapBasedRangeChecks, true,                                 \
          "Raise and handle SIGTRAP if array out of bounds check fails.")   \
  product(bool, TraceTraps, false, "Trace all traps the signal handler"     \
          "handles.")                                                       \
                                                                            \
  product(bool, ZapMemory, false, "Write 0x0101... to empty memory."        \
          " Use this to ease debugging.")                                   \

#endif // CPU_PPC_VM_GLOBALS_PPC_HPP
<|endoftext|>


<commit_before>/*
 * Author: Brendan Le Foll <brendan.le.foll@intel.com>
 * Contributions: Mihai Tudor Panu <mihai.t.panu@intel.com>
 * Contributions: Sarah Knepper <sarah.knepper@intel.com>
 * Copyright (c) 2014 Intel Corporation.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <iostream>

#include "grove.h"
#include "math.h"

using namespace upm;

//// GroveLed ////

GroveLed::GroveLed(int pin)
{
    mraa_init();
    m_gpio = mraa_gpio_init(pin);
    mraa_gpio_dir(m_gpio, MRAA_GPIO_OUT);
    m_name = "LED Socket";
}

GroveLed::~GroveLed()
{
    mraa_gpio_close(m_gpio);
}

mraa_result_t GroveLed::write(int value)
{
    if (value >= 1) {
        return mraa_gpio_write(m_gpio, 1);
    }
    return mraa_gpio_write(m_gpio, 0);
}

mraa_result_t GroveLed::on()
{
    return write(1);
}

mraa_result_t GroveLed::off()
{
    return write(0);
}

//// GroveTemp ////

GroveTemp::GroveTemp(unsigned int pin)
{
    mraa_init();
    m_aio = mraa_aio_init(pin);
    m_name = "Temperature Sensor";
}

GroveTemp::~GroveTemp()
{
    mraa_aio_close(m_aio);
}

int GroveTemp::value ()
{
    int a = mraa_aio_read(m_aio);
    float r = (float)(1023-a)*10000/a;
    float t = 1/(log(r/10000)/3975 + 1/298.15)-273.15;
    return (int) t;
}

float GroveTemp::raw_value()
{
    return (float) mraa_aio_read(m_aio);
}

//// GroveLight ////

GroveLight::GroveLight(unsigned int pin)
{
    mraa_init();
    m_aio = mraa_aio_init(pin);
    m_name = "Light Sensor";
}

GroveLight::~GroveLight()
{
    mraa_aio_close(m_aio);
}

int GroveLight::value()
{
    // rough conversion to lux, using formula from Grove Starter Kit booklet
    float a = (float) mraa_aio_read(m_aio);
    a = 10000.0/pow(((1023.0-a)*10.0/a)*15.0,4.0/3.0);
    return (int) round(a);
}

float GroveLight::raw_value()
{
    return (float) mraa_aio_read(m_aio);
}

//// GroveRotary ////

GroveRotary::GroveRotary(unsigned int pin)
{
    mraa_init();
    m_aio = mraa_aio_init(pin);
    m_name = "Rotary Angle Sensor";
}

GroveRotary::~GroveRotary()
{
    mraa_aio_close(m_aio);
}

float GroveRotary::abs_value()
{
    return (float) mraa_aio_read(m_aio);
}

float GroveRotary::abs_deg()
{
    return GroveRotary::abs_value() * (float) m_max_angle / 1023.0;
}

float GroveRotary::abs_rad()
{
    return GroveRotary::abs_deg() * M_PI / 180.0;
}

float GroveRotary::rel_value()
{
    return GroveRotary::abs_value() - 512.0;
}

float GroveRotary::rel_deg()
{
    return GroveRotary::rel_value() * (float) m_max_angle / 1023.0;
}

float GroveRotary::rel_rad()
{
    return GroveRotary::rel_deg() * M_PI / 180.0;
}

//// GroveSlide ////

GroveSlide::GroveSlide(unsigned int pin, float ref_voltage)
{
    mraa_init();
    m_aio = mraa_aio_init(pin);
    m_ref_voltage = ref_voltage;
    m_name = "Slide Potentiometer";
}

GroveSlide::~GroveSlide()
{
    mraa_aio_close(m_aio);
}

float GroveSlide::raw_value()
{
    return (float) mraa_aio_read(m_aio);
}

float GroveSlide::voltage_value()
{
    // conversion to Volts
    float a = GroveSlide::raw_value();
    a = m_ref_voltage * a / 1023.0 ;
    return a;
}

float GroveSlide::ref_voltage()
{
    return m_ref_voltage;
}

//// GroveButton ////

GroveButton::GroveButton(unsigned int pin)
{
    mraa_init();
    m_gpio = mraa_gpio_init(pin);
    mraa_gpio_dir(m_gpio, MRAA_GPIO_IN);
    m_name = "Button Sensor";
}

GroveButton::~GroveButton()
{
    mraa_gpio_close(m_gpio);
}

std::string GroveButton::name()
{
    return m_name;
}

int GroveButton::value()
{
    return mraa_gpio_read(m_gpio);
}
<commit_msg>grove.cxx: Improve GroveTemp formula<commit_after>/*
 * Author: Brendan Le Foll <brendan.le.foll@intel.com>
 * Contributions: Mihai Tudor Panu <mihai.t.panu@intel.com>
 * Contributions: Sarah Knepper <sarah.knepper@intel.com>
 * Copyright (c) 2014 Intel Corporation.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <iostream>

#include "grove.h"
#include "math.h"

using namespace upm;

//// GroveLed ////

GroveLed::GroveLed(int pin)
{
    mraa_init();
    m_gpio = mraa_gpio_init(pin);
    mraa_gpio_dir(m_gpio, MRAA_GPIO_OUT);
    m_name = "LED Socket";
}

GroveLed::~GroveLed()
{
    mraa_gpio_close(m_gpio);
}

mraa_result_t GroveLed::write(int value)
{
    if (value >= 1) {
        return mraa_gpio_write(m_gpio, 1);
    }
    return mraa_gpio_write(m_gpio, 0);
}

mraa_result_t GroveLed::on()
{
    return write(1);
}

mraa_result_t GroveLed::off()
{
    return write(0);
}

//// GroveTemp ////

GroveTemp::GroveTemp(unsigned int pin)
{
    mraa_init();
    m_aio = mraa_aio_init(pin);
    m_name = "Temperature Sensor";
}

GroveTemp::~GroveTemp()
{
    mraa_aio_close(m_aio);
}

int GroveTemp::value ()
{
    int a = mraa_aio_read(m_aio);
    float r = (float)(1023.0-a)*10000.0/a;
    float t = 1.0/(log(r/10000.0)/3975.0 + 1.0/298.15)-273.15;
    return (int) round(t);
}

float GroveTemp::raw_value()
{
    return (float) mraa_aio_read(m_aio);
}

//// GroveLight ////

GroveLight::GroveLight(unsigned int pin)
{
    mraa_init();
    m_aio = mraa_aio_init(pin);
    m_name = "Light Sensor";
}

GroveLight::~GroveLight()
{
    mraa_aio_close(m_aio);
}

int GroveLight::value()
{
    // rough conversion to lux, using formula from Grove Starter Kit booklet
    float a = (float) mraa_aio_read(m_aio);
    a = 10000.0/pow(((1023.0-a)*10.0/a)*15.0,4.0/3.0);
    return (int) round(a);
}

float GroveLight::raw_value()
{
    return (float) mraa_aio_read(m_aio);
}

//// GroveRotary ////

GroveRotary::GroveRotary(unsigned int pin)
{
    mraa_init();
    m_aio = mraa_aio_init(pin);
    m_name = "Rotary Angle Sensor";
}

GroveRotary::~GroveRotary()
{
    mraa_aio_close(m_aio);
}

float GroveRotary::abs_value()
{
    return (float) mraa_aio_read(m_aio);
}

float GroveRotary::abs_deg()
{
    return GroveRotary::abs_value() * (float) m_max_angle / 1023.0;
}

float GroveRotary::abs_rad()
{
    return GroveRotary::abs_deg() * M_PI / 180.0;
}

float GroveRotary::rel_value()
{
    return GroveRotary::abs_value() - 512.0;
}

float GroveRotary::rel_deg()
{
    return GroveRotary::rel_value() * (float) m_max_angle / 1023.0;
}

float GroveRotary::rel_rad()
{
    return GroveRotary::rel_deg() * M_PI / 180.0;
}

//// GroveSlide ////

GroveSlide::GroveSlide(unsigned int pin, float ref_voltage)
{
    mraa_init();
    m_aio = mraa_aio_init(pin);
    m_ref_voltage = ref_voltage;
    m_name = "Slide Potentiometer";
}

GroveSlide::~GroveSlide()
{
    mraa_aio_close(m_aio);
}

float GroveSlide::raw_value()
{
    return (float) mraa_aio_read(m_aio);
}

float GroveSlide::voltage_value()
{
    // conversion to Volts
    float a = GroveSlide::raw_value();
    a = m_ref_voltage * a / 1023.0 ;
    return a;
}

float GroveSlide::ref_voltage()
{
    return m_ref_voltage;
}

//// GroveButton ////

GroveButton::GroveButton(unsigned int pin)
{
    mraa_init();
    m_gpio = mraa_gpio_init(pin);
    mraa_gpio_dir(m_gpio, MRAA_GPIO_IN);
    m_name = "Button Sensor";
}

GroveButton::~GroveButton()
{
    mraa_gpio_close(m_gpio);
}

std::string GroveButton::name()
{
    return m_name;
}

int GroveButton::value()
{
    return mraa_gpio_read(m_gpio);
}
<|endoftext|>