SharedMemoryBlock::SharedMemoryBlock(const std::string& filename,
		char character, size_t blockSize) :
		lock(filename), blockSize(blockSize) {
	key_t key = ftok(filename.c_str(), character);

	if (key > 0) {
		shmId = shmget(key, blockSize + sizeof(size_t), 0644 | IPC_CREAT);

		if (shmId > 0) {
			void* tmpPtr = shmat(shmId, NULL, 0);
			if (tmpPtr != (void*) -1) {
				ptrData = static_cast< byte_t* >(tmpPtr);
			}
			else {
				if (getAmountProcessesAttached() == 0) {
					shmctl(shmId, IPC_RMID, NULL);
				}
				throw SharedMemoryException(SharedMemoryException::shmat);
			}
		}
		else {
			throw SharedMemoryException(SharedMemoryException::shmget);
		}
	}
	else {
		throw SharedMemoryException(SharedMemoryException::ftok);
	}
}
void SharedMemoryBlock::freeResources() const {
	if (shmdt(static_cast< void* >(ptrData)) != -1) {
		if (getAmountProcessesAttached() == 0) {
			if (shmctl(shmId, IPC_RMID, NULL) == -1) {
				throw SharedMemoryException(SharedMemoryException::shmctl);
			}
		}
	}
	else {
		throw SharedMemoryException(SharedMemoryException::shmdt);
	}
}
//SM FUNCTIONS 
    void DoomController::SMInit() {
        this->SMName = std::string(SM_NAME_BASE) + instanceId;
        //bip::shared_memory_object::remove(this->SMName.c_str());
        try {
            this->SM = bip::shared_memory_object(bip::open_only, this->SMName.c_str(), bip::read_write);

            this->GameVariablesSMRegion = new bip::mapped_region(this->SM, bip::read_only, 0, 
                                                                 sizeof(DoomController::GameVariablesStruct));
            this->gameVariables = static_cast<DoomController::GameVariablesStruct *>(this->GameVariablesSMRegion->get_address());
            
            this->InputSMRegion = new bip::mapped_region(this->SM, bip::read_write,
                                                         sizeof(DoomController::GameVariablesStruct),
                                                         sizeof(DoomController::InputStruct));
            this->input = static_cast<DoomController::InputStruct *>(this->InputSMRegion->get_address());
            
            this->screenWidth = this->gameVariables->SCREEN_WIDTH;
            this->screenHeight = this->gameVariables->SCREEN_HEIGHT;
            this->screenPitch = this->gameVariables->SCREEN_PITCH;
            this->screenSize = this->gameVariables->SCREEN_SIZE;
            this->screenFormat = (ScreenFormat)this->gameVariables->SCREEN_FORMAT;

            this->ScreenSMRegion = new bip::mapped_region(this->SM, bip::read_only,
                                                          sizeof(DoomController::GameVariablesStruct) + sizeof(DoomController::InputStruct),
                                                          this->screenSize);
            this->screen = static_cast<uint8_t *>(this->ScreenSMRegion->get_address());
        }
        catch (bip::interprocess_exception &ex) {
            throw SharedMemoryException();
        }
    }
size_t SharedMemoryBlock::write(const ByteStream& data) {
	size_t dataSize = data.getTamanioOcupado();
	if (blockSize < dataSize) {
		throw SharedMemoryException(SharedMemoryException::write_size);
	}
	try {
		lock.seizeExclusiveLock();
		memcpy(ptrData, &dataSize, sizeof(size_t));
		memcpy(ptrData + sizeof(size_t), data.obtenerStream(), dataSize);
		lock.releaseLock();
	}
	catch(const LockException &e) {
		throw SharedMemoryException(SharedMemoryException::write_lock);
	}
	return dataSize;
}
size_t SharedMemoryBlock::read(ByteStream& data) const {
	size_t dataSize = 0;
	byte_t* buffer = NULL;
	try {
		lock.seizeSharedLock();
		memcpy(&dataSize, ptrData, sizeof(size_t));
		buffer = new byte_t[dataSize];
		memcpy(buffer, ptrData + sizeof(size_t), dataSize);
		lock.releaseLock();
		data.asignarStream(buffer, dataSize);
	}
	catch(const LockException &e) {
		delete[] buffer;
		throw SharedMemoryException(SharedMemoryException::read_lock);
	}
	delete[] buffer;
	return dataSize;
}