public boolean decode(final ByteBuffer buffer) {
		if (!headerDecoder.isFullHeader(buffer)) {
			return false;
		}

		final int start = buffer.position();
		headerDecoder.parse(buffer);
		final int payloadLength = headerDecoder.getPayloadLength();

		if (!isFullPayload(buffer, payloadLength)) { // including terminating newline
			buffer.position(start);
			return false;
		}

		switch (headerDecoder.getMessageName()) {
			case TASK:
				taskDecoder.parse(buffer, payloadLength);
				notifyTask();
				break;
			case INPUT:
				inputDecoder.parse(buffer, payloadLength);
				notifyInput();
				break;
			case OK:
				okDecoder.parse(buffer, payloadLength);
				listener.ok();
				break;
			case FAIL:
				failDecoder.parse(buffer, payloadLength);
				notifyFail();
				break;
			case RETRY:
				retryDecoder.parse(buffer, payloadLength);
				notifyRetry();
				break;
			case WAIT:
				waitDecoder.parse(buffer, payloadLength);
				notifyPause();
				break;
		}

		buffer.position(buffer.position() + 1); // eat ending newline
		return true;
	}