
#include <sstream>
#include <string.h>

#include "protocol.h"
#include "datetime.h"

#ifdef _DEBUG
#ifndef DEBUG_NEW
#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
#define new DEBUG_NEW
#endif
#endif

// ################################

#define MSG_CHAR_REQUEST         "REQUEST"
#define MSG_CHAR_ANSWER          "ANSWER"
#define MSG_CHAR_UPDATE          "UPDATE"

#define MSG_CHAR_REQUEST_END     MSG_CHAR_REQUEST "END"
#define MSG_CHAR_ANSWER_END_OK   MSG_CHAR_ANSWER  "OK"
#define MSG_CHAR_ANSWER_END_FA   MSG_CHAR_ANSWER  "FAIL"
#define MSG_CHAR_UPDATE_END      MSG_CHAR_UPDATE  "END"

// --------------------------------

void protocolWriter :: beginMessage(messageType type, const std::string &requestName) {
	type_ = type;

	switch (type_)
	{
	case MT_REQUEST: output_ = MSG_CHAR_REQUEST " ";         break;
	case MT_ANSWER:  output_ = MSG_CHAR_ANSWER " ";          break;
	case MT_UPDATE:  output_ = MSG_CHAR_UPDATE " ";          break;
	}
	output_ += requestName + " ";
}

// --------------------------------

char* protocolWriter :: copyMessage()
{
	return _strdup(output_.c_str());
}

// --------------------------------

const char*  protocolWriter :: endMessage(bool answerOK)
{
	switch (type_)
	{
	case MT_REQUEST: output_ += MSG_CHAR_REQUEST_END;                                          break;
	case MT_ANSWER:  output_ += answerOK ? MSG_CHAR_ANSWER_END_OK : MSG_CHAR_ANSWER_END_FA;    break;
	case MT_UPDATE:  output_ += MSG_CHAR_UPDATE_END;                                           break;
	}

	std :: stringstream sizeWriter;
	sizeWriter << output_.size();
	output_ = sizeWriter.str() + " " + output_;

	return output_.c_str();
}

// --------------------------------

void protocolWriter :: writeValue(const std::string &valueName, unsigned long value) 
{
	std :: stringstream valueWriter;
	valueWriter << value;
	std :: stringstream sizeWriter;
	std :: string valueStr = valueWriter.str();
	sizeWriter << valueStr.size();


	output_ += valueName + " " + sizeWriter.str() + " " + valueStr + " ";
}

// --------------------------------

void protocolWriter :: writeValue(const std::string &valueName, unsigned long long value) 
{
	std :: stringstream valueWriter;
	valueWriter << value;
	std :: stringstream sizeWriter;
	std :: string valueStr = valueWriter.str();
	sizeWriter << valueStr.size();


	output_ += valueName + " " + sizeWriter.str() + " " + valueStr + " ";
}

// --------------------------------

void protocolWriter :: writeValue(const std::string &valueName, signed long value) 
{
	std :: stringstream valueWriter;
	valueWriter << value;
	std :: stringstream sizeWriter;
	std :: string valueStr = valueWriter.str();
	sizeWriter << valueStr.size();


	output_ += valueName + " " + sizeWriter.str() + " " + valueStr + " ";
}

// --------------------------------

void protocolWriter :: writeValue(const std::string &valueName, bool value) 
{
	writeValue(valueName, value ? (unsigned long) 1 : (unsigned long) 0);
}

// --------------------------------

void protocolWriter :: writeValue(const std::string &valueName, double value) 
{
	std :: stringstream valueWriter;
	valueWriter << value;
	std :: stringstream sizeWriter;
	std :: string valueStr = valueWriter.str();
	sizeWriter << valueStr.size();


	output_ += valueName + " " + sizeWriter.str() + " " + valueStr + " ";
}

// --------------------------------

void protocolWriter :: writeValue(const std::string &valueName, const std::string &value) 
{
	std :: stringstream valueWriter;
	valueWriter << value;
	std :: stringstream sizeWriter;
	std :: string valueStr = valueWriter.str();
	sizeWriter << valueStr.size();


	output_ += valueName + " " + sizeWriter.str() + " " + valueStr + " ";
}

// --------------------------------

void protocolWriter :: writeValue(const std::string &valueName, const char *value) 
{
	std :: stringstream valueWriter;
	valueWriter << value;
	std :: stringstream sizeWriter;
	std :: string valueStr = valueWriter.str();
	sizeWriter << valueStr.size();


	output_ += valueName + " " + sizeWriter.str() + " " + valueStr + " ";
}

// --------------------------------

void protocolWriter :: writeValue(const std::string &valueName, signed long long value) 
{
	std :: stringstream valueWriter;
	valueWriter << value;
	std :: stringstream sizeWriter;
	std :: string valueStr = valueWriter.str();
	sizeWriter << valueStr.size();


	output_ += valueName + " " + sizeWriter.str() + " " + valueStr + " ";
}

// ################################

message *protocolReader :: translateMessage(const char *msg)
{  
	msg_                       = msg;
	messageType mt             = MT_UNDEFINED;
	answerKind ak              = AK_UNDEFINED;
	std :: string name         = "";
	message* result            = new message(mt, name, ak);

	do
	{
		scanToken();

		// zjisti typ zpravy
		if (scannedToken_ == MSG_CHAR_REQUEST) {
			result->type_ = MT_REQUEST;
			break;
		}

		if (scannedToken_ == MSG_CHAR_ANSWER) {
			result->type_ = MT_ANSWER;
			break;
		}

		if (scannedToken_ == MSG_CHAR_UPDATE) {
			result->type_ = MT_UPDATE;
			break;
		}

        // spatny typ zpravy, skonci
        delete result;
        return NULL;
	}
	while (false);

	// nacteme jmeno
	scanToken();
	result->name_ = scannedToken_;

	// nacteme hodnoty
	bool scanned = true;
	while (true)
	{
		if (!scanned) 
		{
			delete result;
			return NULL;
		}

		// nacteme jmeno hodnoty, nebo konec souboru
		scanned &= scanToken();

		// jestlize je jmeno hodnoty ukonceni, ukonci to
		// zjisti typ zpravy
		if (scannedToken_ == MSG_CHAR_UPDATE_END) 
		{
			if (result->type_ != MT_UPDATE) 
			{
				delete result;
				return NULL;
			}
			break;
		}

		if (scannedToken_ == MSG_CHAR_REQUEST_END) 
		{
			if (result->type_ != MT_REQUEST) 
			{
				delete result;
				return NULL;
			}
			break;
		}

		if (scannedToken_ == MSG_CHAR_ANSWER_END_OK) 
		{
			if (result->type_ != MT_ANSWER) 
			{
				delete result;
				return NULL;
			}
			result->ak_ = AK_OK;
			break;
		}

		if (scannedToken_ == MSG_CHAR_ANSWER_END_FA) 
		{
			if (result->type_ != MT_ANSWER) 
			{
				delete result;
				return NULL;
			}
			result->ak_ = AK_FAIL;
			break;
		}

		std :: string valueName = scannedToken_;
		scanned &= scanToken();

		int size = atoi(scannedToken_.c_str());
		scanned &= scanChars(size);

		result->values[valueName] = scannedToken_;
	}

	return result;
}

// --------------------------------

bool protocolReader :: scanToken()
{
	scannedToken_ = "";

	if (*msg_ == 0) return false;

	while (((*msg_) != ' ') && ((*msg_) != 0))
	{
		scannedToken_ += *msg_;
		msg_++;
	}

	if (*msg_ != 0) msg_++;

	return true;
}

// --------------------------------

bool protocolReader :: scanChars(int size)
{
	scannedToken_ = "";

	if (*msg_ == 0) return false;

	while ((size > 0) && ((*msg_) != 0))
	{
		scannedToken_ += *msg_;
		msg_++;
		size--;
	}

	if (*msg_ != 0) msg_++;

	return size == 0;
}

// ################################

char* requestWriter :: ships(void)
{
    protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_SHIPS);
    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char* requestWriter :: discoveredStarsRequest()
{
    protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_DISCOVERED_STARS);
    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char* requestWriter :: bases(void)
{
    protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_BASES);
    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char* requestWriter :: login(const std :: string& login, const std :: string& password)
{
    protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_LOGIN);
    w.writeValue(REQUEST_LOGIN_LOGINNAME, login);
    w.writeValue(REQUEST_LOGIN_PASSWORD, password);
    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char* requestWriter :: chat(unsigned long recipient, const std :: string& message)
{
    protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_CHAT);
    w.writeValue(REQUEST_CHAT_RECIPIENT, recipient);
    w.writeValue(REQUEST_CHAT_MESSAGE, message);
    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char* requestWriter :: buddy(void)
{
    protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_BUDDY);
    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char*  requestWriter :: planets(unsigned long area)
{
    protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_PLANETS);
    w.writeValue(REQUEST_PLANETS_AREAID, area);
    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char* requestWriter :: navigation_planets(unsigned long ship, unsigned long area)
{
    protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_NAVIGATION_PLANETS);
    w.writeValue(REQUEST_NAVIGATION_PLANETS_AREAID, area);
    w.writeValue(REQUEST_NAVIGATION_PLANETS_SHIPID, ship);
    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char* requestWriter :: shipsinarea(unsigned long ship)
{
    protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_SHIPSINAREA);
    w.writeValue(REQUEST_SHIPSINAREA_SHIPID, ship);
    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char* requestWriter :: navigation_status(unsigned long ship)
{
    protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_NAVIGATION_STATUS);
    w.writeValue(REQUEST_NAVIGATION_STATUS_SHIPID, ship);
    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char* requestWriter :: navigation_stop(unsigned long ship)
{
    protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_NAVIGATION_STOP);
    w.writeValue(REQUEST_NAVIGATION_SHIPID, ship);
    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char* requestWriter :: navigation_warp(unsigned long ship, signed long long posx, signed long long posy)
{
    protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_NAVIGATION_WARP);
    w.writeValue(REQUEST_NAVIGATION_SHIPID, ship);
    w.writeValue(REQUEST_NAVIGATION_POSITIONX, posx);
    w.writeValue(REQUEST_NAVIGATION_POSITIONY, posy);
    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char* requestWriter :: navigation_break_warp(unsigned long ship)
{
    protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_NAVIGATION_BREAK_WARP);
    w.writeValue(REQUEST_NAVIGATION_SHIPID, ship);
    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char* requestWriter :: navigation_move_to(unsigned long ship, signed long long posx, signed long long posy, 
                                          dv_time:: datetime limit)
{
    protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_NAVIGATION_MOVE_TO);
    w.writeValue(REQUEST_NAVIGATION_SHIPID, ship);
    w.writeValue(REQUEST_NAVIGATION_POSITIONX, posx);
    w.writeValue(REQUEST_NAVIGATION_POSITIONY, posy);
    writeDateTime(w, REQUEST_NAVIGATION_ENGINELIMIT, limit);
    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char* requestWriter :: navigation_orbit(unsigned long ship)
{
    protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_NAVIGATION_ORBIT);
    w.writeValue(REQUEST_NAVIGATION_SHIPID, ship);
    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char* requestWriter :: navigation_pursuit(unsigned long ship, unsigned long target, dv_time:: datetime limit)
{
    protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_NAVIGATION_PURSUIT);
    w.writeValue(REQUEST_NAVIGATION_SHIPID, ship);
    w.writeValue(REQUEST_NAVIGATION_TARGET, target);
    writeDateTime(w, REQUEST_NAVIGATION_ENGINELIMIT, limit);
    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char* requestWriter :: navigation_move_to_spobj(unsigned long ship, unsigned long spaceObject, 
                                                dv_time:: datetime limit)
{
    protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_NAVIGATION_MOVE_TO_SPOBJ);
    w.writeValue(REQUEST_NAVIGATION_SHIPID, ship);
    w.writeValue(REQUEST_NAVIGATION_SPACEOBJECT, spaceObject);
    writeDateTime(w, REQUEST_NAVIGATION_ENGINELIMIT, limit);
    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char* requestWriter :: navigation_move_to_spobj_by_warp(unsigned long ship, unsigned long spaceObject)
{
    protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_NAVIGATION_MOVE_TO_SPOBJ_BY_WARP);
    w.writeValue(REQUEST_NAVIGATION_SHIPID, ship);
    w.writeValue(REQUEST_NAVIGATION_SPACEOBJECT, spaceObject);
    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char* requestWriter :: navigation_dock_down(unsigned long shipId, unsigned long baseId)
{
    protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_NAVIGATION_DOCK_DOWN);
    w.writeValue(REQUEST_NAVIGATION_DOCK_DOWN_SHIP_ID, shipId);
    w.writeValue(REQUEST_NAVIGATION_DOCK_DOWN_BASE_ID, baseId);
    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char* requestWriter :: navigation_unbound(unsigned long shipId)
{
    protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_NAVIGATION_UNBOUND);
    w.writeValue(REQUEST_NAVIGATION_UNBOUND_SHIP_ID, shipId);
    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char* requestWriter :: ship_journey_details(unsigned long ship)
{
    protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_SHIP_JOURNEY_DETAILS);
    w.writeValue(REQUEST_SHIP_JOURNEY_DETAILS_SHIPID, ship);
    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char* requestWriter :: device_energy_state(unsigned long ship)
{
    protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_DEVICE_ENERGY_STATE);
    w.writeValue(REQUEST_DEVICE_ENERGY_STATE_FORTRESSID, ship);
    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char* requestWriter :: ship_central_information(unsigned long ship)
{
    protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_SHIP_CENTRAL_INFORMATION);
    w.writeValue(REQUEST_SHIP_CENTRAL_INFORMATION_SHIPID, ship);
    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char* requestWriter :: fortress_shields_information(unsigned long fortress)
{
    protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_FORTRESS_SHIELDS_INFORMATION);
    w.writeValue(REQUEST_FORTRESS_SHIELDS_INFORMATION_FORTRESSID, fortress);
    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------


void writeDateTime(protocolWriter& pw, const std :: string& prefix, dv_time:: datetime dt)
{
    pw.writeValue(prefix, dt);
}

// --------------------------------

void write_energy_state_req(protocolWriter& w, const char* devName, const requestDeviceEnergyState& des)
{
    std :: stringstream ss;

    ss << devName << REQUEST_CHANGE_DEVICE_ENERGY_STATE_ANSWER_ES_PRIORITY;
    w.writeValue(ss.str(), (unsigned long)des.priority);
    ss.str(std :: string(""));

    ss << devName << REQUEST_CHANGE_DEVICE_ENERGY_STATE_ANSWER_ES_RATIO;
    w.writeValue(ss.str(), (unsigned long)des.ratio);
    ss.str(std :: string(""));

    ss << devName << REQUEST_CHANGE_DEVICE_ENERGY_STATE_ANSWER_ES_MAX_POWER_DRAIN;
    w.writeValue(ss.str(), des.maxPowerDrain);
    ss.str(std :: string(""));

    ss << devName << REQUEST_CHANGE_DEVICE_ENERGY_STATE_ANSWER_ES_SHUT_DOWN_ON_EL;
    w.writeValue(ss.str(), (unsigned long)(des.shutDownOnEnergyLack ? 1 : 0));
    ss.str(std :: string(""));
}

// --------------------------------

char* requestWriter :: change_device_energy_state(unsigned long ship, const requestDeviceEnergy& de)
{
    protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_CHANGE_DEVICE_ENERGY_STATE);
    w.writeValue(REQUEST_CHANGE_DEVICE_ENERGY_STATE_ANSWER_FORTRESSID, ship);

    write_energy_state_req(w, REQUEST_CHANGE_DEVICE_ENERGY_STATE_ANSWER_SHIELDS,       de.SHIELDS);
    write_energy_state_req(w, REQUEST_CHANGE_DEVICE_ENERGY_STATE_ANSWER_WEAPONS,       de.WEAPONS);
    write_energy_state_req(w, REQUEST_CHANGE_DEVICE_ENERGY_STATE_ANSWER_TRANSPORT,     de.TRANSPORT);
    write_energy_state_req(w, REQUEST_CHANGE_DEVICE_ENERGY_STATE_ANSWER_HR_SENSORS,    de.HR_SENSORS);
    write_energy_state_req(w, REQUEST_CHANGE_DEVICE_ENERGY_STATE_ANSWER_LR_SENSORS,    de.LR_SENSORS);
    write_energy_state_req(w, REQUEST_CHANGE_DEVICE_ENERGY_STATE_ANSWER_MASKING,       de.MASKING);
    write_energy_state_req(w, REQUEST_CHANGE_DEVICE_ENERGY_STATE_ANSWER_ANDROIDS,      de.ANDROIDS);
    write_energy_state_req(w, REQUEST_CHANGE_DEVICE_ENERGY_STATE_ANSWER_MAINFRAME,     de.MAINFRAME);
    write_energy_state_req(w, REQUEST_CHANGE_DEVICE_ENERGY_STATE_ANSWER_LIFE_SUPPORT,  de.LIFE_SUPPORT);    

    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------
// --------------------------------

char* requestWriter :: science(void)
{
    protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_SCIENCE);
    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char* requestWriter :: change_science(sciencetree_raw_data& data)
{
    protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_SCIENCE_CHANGE);

    w.writeValue(TOKENS_SCIENCE_ENTITY_SHIPS,                                           data.tokensSCIENCE_ENTITY_SHIPS);
    w.writeValue(TOKENS_SCIENCE_ENTITY_BASES,                                           data.tokensSCIENCE_ENTITY_BASES);
    w.writeValue(TOKENS_SCIENCE_ENTITY_ENERGETIC_ACCUMULATOR,                           data.tokensSCIENCE_ENTITY_ENERGETIC_ACCUMULATOR);
    w.writeValue(TOKENS_SCIENCE_ENTITY_NAVIGATION_COMPUTER,                             data.tokensSCIENCE_ENTITY_NAVIGATION_COMPUTER);
    w.writeValue(TOKENS_SCIENCE_ENTITY_QUARK_GLUON_CORE,                                data.tokensSCIENCE_ENTITY_QUARK_GLUON_CORE);
    w.writeValue(TOKENS_SCIENCE_ENTITY_SUBSPACE_BEACON,                                 data.tokensSCIENCE_ENTITY_SUBSPACE_BEACON);
    w.writeValue(TOKENS_SCIENCE_ENTITY_INERTIAL_DAMPERS,                                data.tokensSCIENCE_ENTITY_INERTIAL_DAMPERS);
    w.writeValue(TOKENS_SCIENCE_ENTITY_IMPULS_JET_ENGINE,                               data.tokensSCIENCE_ENTITY_IMPULS_JET_ENGINE);
    w.writeValue(TOKENS_SCIENCE_ENTITY_MECHANICAL_DAMPERS,                              data.tokensSCIENCE_ENTITY_MECHANICAL_DAMPERS);
    w.writeValue(TOKENS_SCIENCE_ENTITY_DEFLECTOR_SHIELDS,                               data.tokensSCIENCE_ENTITY_DEFLECTOR_SHIELDS);
    w.writeValue(TOKENS_SCIENCE_ENTITY_WEAPON_ENERGY_CIRCUIT,                           data.tokensSCIENCE_ENTITY_WEAPON_ENERGY_CIRCUIT);
    w.writeValue(TOKENS_SCIENCE_ENTITY_DRONE_MISSILE_LAUNCHER,                          data.tokensSCIENCE_ENTITY_DRONE_MISSILE_LAUNCHER);
    w.writeValue(TOKENS_SCIENCE_ENTITY_DRONE_MISSILES,                                  data.tokensSCIENCE_ENTITY_DRONE_MISSILES);
    w.writeValue(TOKENS_SCIENCE_ENTITY_LASER_GUN,                                       data.tokensSCIENCE_ENTITY_LASER_GUN);
    w.writeValue(TOKENS_SCIENCE_ENTITY_TRANSPORT_BEAM_GENERATOR,                        data.tokensSCIENCE_ENTITY_TRANSPORT_BEAM_GENERATOR);
    w.writeValue(TOKENS_SCIENCE_ENTITY_MAGNETICAL_COLLECTORS_OF_PLASMA,                 data.tokensSCIENCE_ENTITY_MAGNETICAL_COLLECTORS_OF_PLASMA);
    w.writeValue(TOKENS_SCIENCE_ENTITY_SUBMERSIBLE_FILTRATION_TANK,                     data.tokensSCIENCE_ENTITY_SUBMERSIBLE_FILTRATION_TANK);
    w.writeValue(TOKENS_SCIENCE_ENTITY_SUBMARINE_MINING_MACHINE,                        data.tokensSCIENCE_ENTITY_SUBMARINE_MINING_MACHINE);
    w.writeValue(TOKENS_SCIENCE_ENTITY_UNDERGROUND_DRILLING_MACHINE,                    data.tokensSCIENCE_ENTITY_UNDERGROUND_DRILLING_MACHINE);
    w.writeValue(TOKENS_SCIENCE_ENTITY_PROBE,                                           data.tokensSCIENCE_ENTITY_PROBE);
    w.writeValue(TOKENS_SCIENCE_ENTITY_HIGH_RESOLUTION_SENSORS,                         data.tokensSCIENCE_ENTITY_HIGH_RESOLUTION_SENSORS);
    w.writeValue(TOKENS_SCIENCE_ENTITY_LONG_RANGE_SENSORS,                              data.tokensSCIENCE_ENTITY_LONG_RANGE_SENSORS);
    w.writeValue(TOKENS_SCIENCE_ENTITY_CLOAKING_DEVICE,                                 data.tokensSCIENCE_ENTITY_CLOAKING_DEVICE);
    w.writeValue(TOKENS_SCIENCE_ENTITY_ANDROIDS,                                        data.tokensSCIENCE_ENTITY_ANDROIDS);
    w.writeValue(TOKENS_SCIENCE_ENTITY_SCIENTIFIC_LAB,                                  data.tokensSCIENCE_ENTITY_SCIENTIFIC_LAB);
    w.writeValue(TOKENS_SCIENCE_ENTITY_LIFE_SUPPORT,                                    data.tokensSCIENCE_ENTITY_LIFE_SUPPORT);
    w.writeValue(TOKENS_SCIENCE_ENTITY_MAINFRAME,                                       data.tokensSCIENCE_ENTITY_MAINFRAME);
    w.writeValue(TOKENS_SCIENCE_ENTITY_HANGAR,                                          data.tokensSCIENCE_ENTITY_HANGAR);
    w.writeValue(TOKENS_SCIENCE_ENTITY_MAGNETICAL_FILTER,                               data.tokensSCIENCE_ENTITY_MAGNETICAL_FILTER);
    w.writeValue(TOKENS_SCIENCE_ENTITY_DEUTERIUM_DECOMPOSER,                            data.tokensSCIENCE_ENTITY_DEUTERIUM_DECOMPOSER);
    w.writeValue(TOKENS_SCIENCE_ENTITY_ZIRCONIUM_REACTOR,                               data.tokensSCIENCE_ENTITY_ZIRCONIUM_REACTOR);
    w.writeValue(TOKENS_SCIENCE_ENTITY_ILMENITE_FURNACE,                                data.tokensSCIENCE_ENTITY_ILMENITE_FURNACE);

    w.writeValue(TOKENS_SCIENCE_SUPREME_ENTITY_SCIENCE,                                 data.tokensSCIENCE_SUPREME_ENTITY_SCIENCE);

    w.writeValue(TOKENS_SCIENCE_SUPREME_ENTITY_DRIVE,                                   data.tokensSCIENCE_SUPREME_ENTITY_DRIVE);
    w.writeValue(TOKENS_SCIENCE_SUPREME_ENTITY_PLATFORM,                                data.tokensSCIENCE_SUPREME_ENTITY_PLATFORM);
    w.writeValue(TOKENS_SCIENCE_SUPREME_ENTITY_MODULES,                                 data.tokensSCIENCE_SUPREME_ENTITY_MODULES);
    w.writeValue(TOKENS_SCIENCE_SUPREME_ENTITY_PRODUCTION,                              data.tokensSCIENCE_SUPREME_ENTITY_PRODUCTION);

    w.writeValue(TOKENS_SCIENCE_SUPREME_ENTITY_SUBSPACE_DRIVE,                          data.tokensSCIENCE_SUPREME_ENTITY_SUBSPACE_DRIVE);
    w.writeValue(TOKENS_SCIENCE_SUPREME_ENTITY_IMPULS_DRIVE,                            data.tokensSCIENCE_SUPREME_ENTITY_IMPULS_DRIVE);
    w.writeValue(TOKENS_SCIENCE_SUPREME_ENTITY_CONSTRUCTION,                            data.tokensSCIENCE_SUPREME_ENTITY_CONSTRUCTION);
    w.writeValue(TOKENS_SCIENCE_SUPREME_ENTITY_EQUIPMENT,                               data.tokensSCIENCE_SUPREME_ENTITY_EQUIPMENT);
    w.writeValue(TOKENS_SCIENCE_SUPREME_ENTITY_ENERGETIC_RING,                          data.tokensSCIENCE_SUPREME_ENTITY_ENERGETIC_RING);
    w.writeValue(TOKENS_SCIENCE_SUPREME_ENTITY_RECOGNITION_DEVICES,                     data.tokensSCIENCE_SUPREME_ENTITY_RECOGNITION_DEVICES);
    w.writeValue(TOKENS_SCIENCE_SUPREME_ENTITY_FACTORIES,                               data.tokensSCIENCE_SUPREME_ENTITY_FACTORIES);
    w.writeValue(TOKENS_SCIENCE_SUPREME_ENTITY_QUARRYING_MACHINES,                      data.tokensSCIENCE_SUPREME_ENTITY_QUARRYING_MACHINES);

    w.writeValue(SPEC_PTS_QUARK_GLUON_CORE_SPEED,                                       data.specPtsQUARK_GLUON_CORE_SPEED);
    w.writeValue(SPEC_PTS_QUARK_GLUON_CORE_CONSUMPTION,                                 data.specPtsQUARK_GLUON_CORE_CONSUMPTION);

    w.writeValue(SPEC_PTS_NAVIGATION_COMPUTER_SPEED,                                    data.specPtsNAVIGATION_COMPUTER_SPEED);

    w.writeValue(SPEC_PTS_SUBSPACE_BEACON_SPEED,                                        data.specPtsSUBSPACE_BEACON_SPEED);

    w.writeValue(SPEC_PTS_INERTIAL_DAMPERS_SPEED,                                       data.specPtsINERTIAL_DAMPERS_SPEED);

    w.writeValue(SPEC_PTS_IMPULS_ENGINE_FORCE,                                          data.specPtsIMPULS_ENGINE_FORCE);
    w.writeValue(SPEC_PTS_IMPULS_ENGINE_CONSUMPTION,                                    data.specPtsIMPULS_ENGINE_CONSUMPTION);

    w.writeValue(SPEC_PTS_MECHANICAL_DAMPERS_ACCELERATION,                              data.specPtsMECHANICAL_DAMPERS_ACCELERATION);

    w.writeValue(SPEC_PTS_DRONE_MISSILES_DAMAGE,                                        data.specPtsDRONE_MISSILES_DAMAGE);
    w.writeValue(SPEC_PTS_DRONE_MISSILES_PRECISION,                                     data.specPtsDRONE_MISSILES_PRECISION);
    w.writeValue(SPEC_PTS_DRONE_MISSILES_RANGE,                                         data.specPtsDRONE_MISSILES_RANGE);

    w.writeValue(SPEC_PTS_DRONE_MISSILE_LAUNCHER_ACCUMULATOR,                           data.specPtsDRONE_MISSILE_LAUNCHER_ACCUMULATOR);
    w.writeValue(SPEC_PTS_DRONE_MISSILE_LAUNCHER_CHARGING,                              data.specPtsDRONE_MISSILE_LAUNCHER_CHARGING);

    w.writeValue(SPEC_PTS_SHIPS_LEVEL,                                                  data.specPtsSHIPS_LEVEL);

    w.writeValue(SPEC_PTS_BASES_LEVEL,                                                  data.specPtsBASES_LEVEL);

    w.writeValue(SPEC_PTS_HANGARS_LEVEL,                                                data.specPtsHANGARS_LEVEL);

    w.writeValue(SPEC_PTS_ANDROIDS_LEVEL,                                               data.specPtsANDROIDS_LEVEL);
    w.writeValue(SPEC_PTS_ANDROIDS_CONSUMPTION,                                         data.specPtsANDROIDS_CONSUMPTION);

    w.writeValue(SPEC_PTS_ENERGETIC_ACCUMULATOR_ACCUMULATOR,                            data.specPtsENERGETIC_ACCUMULATOR_ACCUMULATOR);
    w.writeValue(SPEC_PTS_ENERGETIC_ACCUMULATOR_CHARGING,                               data.specPtsENERGETIC_ACCUMULATOR_CHARGING);

    w.writeValue(SPEC_PTS_MAINFRAME_BIO_NODES,                                          data.specPtsMAINFRAME_BIO_NODES);
    w.writeValue(SPEC_PTS_MAINFRAME_PREDICTION,                                         data.specPtsMAINFRAME_PREDICTION);
    w.writeValue(SPEC_PTS_MAINFRAME_TIME_REUSABILITY,                                   data.specPtsMAINFRAME_TIME_REUSABILITY);
    w.writeValue(SPEC_PTS_MAINFRAME_CONSUMPTION,                                        data.specPtsMAINFRAME_CONSUMPTION);

    w.writeValue(SPEC_PTS_SCIENTIFIC_LABS_LEVEL,                                        data.specPtsSCIENTIFIC_LABS_LEVEL);

    w.writeValue(SPEC_PTS_LIFE_SUPPORT_CAPACITY,                                        data.specPtsLIFE_SUPPORT_CAPACITY);
    w.writeValue(SPEC_PTS_LIFE_SUPPORT_CONSUMPTION,                                     data.specPtsLIFE_SUPPORT_CONSUMPTION);

    w.writeValue(SPEC_PTS_WEAPON_ENERGY_CIRCUIT_CHARGING,                               data.specPtsWEAPON_ENERGY_CIRCUIT_CHARGING);

    w.writeValue(SPEC_PTS_TRANSPORT_BEAM_GENERATOR_ACCUMULATOR,                         data.specPtsTRANSPORT_BEAM_GENERATOR_ACCUMULATOR);
    w.writeValue(SPEC_PTS_TRANSPORT_BEAM_GENERATOR_CHARGING,                            data.specPtsTRANSPORT_BEAM_GENERATOR_CHARGING);
    w.writeValue(SPEC_PTS_TRANSPORT_BEAM_GENERATOR_FORCIBILITY,                         data.specPtsTRANSPORT_BEAM_GENERATOR_FORCIBILITY);
    w.writeValue(SPEC_PTS_TRANSPORT_BEAM_GENERATOR_PRECISION,                           data.specPtsTRANSPORT_BEAM_GENERATOR_PRECISION);
    w.writeValue(SPEC_PTS_TRANSPORT_BEAM_GENERATOR_RANGE,                               data.specPtsTRANSPORT_BEAM_GENERATOR_RANGE);

    w.writeValue(SPEC_PTS_LASER_GUN_ACCUMULATOR,                                        data.specPtsLASER_GUN_ACCUMULATOR);
    w.writeValue(SPEC_PTS_LASER_GUN_CHARGING,                                           data.specPtsLASER_GUN_CHARGING);
    w.writeValue(SPEC_PTS_LASER_GUN_FORCIBILITY,                                        data.specPtsLASER_GUN_FORCIBILITY);
    w.writeValue(SPEC_PTS_LASER_GUN_PRECISION,                                          data.specPtsLASER_GUN_PRECISION);
    w.writeValue(SPEC_PTS_LASER_GUN_RANGE,                                              data.specPtsLASER_GUN_RANGE);

    w.writeValue(SPEC_PTS_DEFLECTOR_SHIELDS_GENERATOR_SOLIDITY,                         data.specPtsDEFLECTOR_SHIELDS_GENERATOR_SOLIDITY);
    w.writeValue(SPEC_PTS_DEFLECTOR_SHIELDS_GENERATOR_ACCUMULATOR,                      data.specPtsDEFLECTOR_SHIELDS_GENERATOR_ACCUMULATOR);
    w.writeValue(SPEC_PTS_DEFLECTOR_SHIELDS_GENERATOR_CHARGING,                         data.specPtsDEFLECTOR_SHIELDS_GENERATOR_CHARGING);

    w.writeValue(SPEC_PTS_HIGH_RESOLUTION_SENSORS_LEVEL,                                data.specPtsHIGH_RESOLUTION_SENSORS_LEVEL);
    w.writeValue(SPEC_PTS_HIGH_RESOLUTION_SENSORS_RANGE,                                data.specPtsHIGH_RESOLUTION_SENSORS_RANGE);
    w.writeValue(SPEC_PTS_HIGH_RESOLUTION_SENSORS_CONSUMPTION,                          data.specPtsHIGH_RESOLUTION_SENSORS_CONSUMPTION);

    w.writeValue(SPEC_PTS_LONG_RANGE_SENSORS_LEVEL,                                     data.specPtsLONG_RANGE_SENSORS_LEVEL);
    w.writeValue(SPEC_PTS_LONG_RANGE_SENSORS_RANGE,                                     data.specPtsLONG_RANGE_SENSORS_RANGE);
    w.writeValue(SPEC_PTS_LONG_RANGE_SENSORS_CONSUMPTION,                               data.specPtsLONG_RANGE_SENSORS_CONSUMPTION);

    w.writeValue(SPEC_PTS_CLOAKING_DEVICE_LEVEL,                                        data.specPtsCLOAKING_DEVICE_LEVEL);
    w.writeValue(SPEC_PTS_CLOAKING_DEVICE_CONSUMPTION,                                  data.specPtsCLOAKING_DEVICE_CONSUMPTION);

    w.writeValue(SPEC_PTS_PROBE_DEVICE_LEVEL,                                           data.specPtsPROBE_DEVICE_LEVEL);

    w.writeValue(SPEC_PTS_MAGNETICAL_FILTER_PRODUCTION,                                 data.specPtsMAGNETICAL_FILTER_PRODUCTION);

    w.writeValue(SPEC_PTS_DEUTERIUM_DECOMPOSER_PRODUCTION,                              data.specPtsDEUTERIUM_DECOMPOSER_PRODUCTION);
    w.writeValue(SPEC_PTS_DEUTERIUM_DECOMPOSER_METAMORPHOSIS,                           data.specPtsDEUTERIUM_DECOMPOSER_METAMORPHOSIS);

    w.writeValue(SPEC_PTS_ZIRCONIUM_REACTOR_PRODUCTION,                                 data.specPtsZIRCONIUM_REACTOR_PRODUCTION);
    w.writeValue(SPEC_PTS_ZIRCONIUM_REACTOR_METAMORPHOSIS,                              data.specPtsZIRCONIUM_REACTOR_METAMORPHOSIS);

    w.writeValue(SPEC_PTS_ILMENITE_FURNACE_PRODUCTION,                                  data.specPtsILMENITE_FURNACE_PRODUCTION);
    w.writeValue(SPEC_PTS_ILMENITE_FURNACE_METAMORPHOSIS,                               data.specPtsILMENITE_FURNACE_METAMORPHOSIS);

    w.writeValue(SPEC_PTS_MAGNETICAL_COLLECTORS_OF_PLASMA_WINDING_SPEED,                data.specPtsMAGNETICAL_COLLECTORS_OF_PLASMA_WINDING_SPEED);

    w.writeValue(SPEC_PTS_SUBMERSIBLE_FILTRATION_TANK_WINDING_SPEED,                    data.specPtsSUBMERSIBLE_FILTRATION_TANK_WINDING_SPEED);
    w.writeValue(SPEC_PTS_SUBMERSIBLE_FILTRATION_TANK_RANGE,                            data.specPtsSUBMERSIBLE_FILTRATION_TANK_RANGE);

    w.writeValue(SPEC_PTS_SUBMARINE_MINING_MACHINE_WINDING_SPEED,                       data.specPtsSUBMARINE_MINING_MACHINE_WINDING_SPEED);
    w.writeValue(SPEC_PTS_SUBMARINE_MINING_MACHINE_RANGE,                               data.specPtsSUBMARINE_MINING_MACHINE_RANGE);

    w.writeValue(SPEC_PTS_UNDERGROUND_DRILLING_MACHINE_WINDING_SPEED,                   data.specPtsUNDERGROUND_DRILLING_MACHINE_WINDING_SPEED);
    w.writeValue(SPEC_PTS_UNDERGROUND_DRILLING_MACHINE_RANGE,                           data.specPtsUNDERGROUND_DRILLING_MACHINE_RANGE);     

    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char* requestWriter :: ship_subspace_drive_information(unsigned long ship)
{
	protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_SHIP_SUBSPACE_DRIVE_INFORMATION);
		w.writeValue(REQUEST_SHIP_SUBSPACE_DRIVE_INFORMATION_SHIPID, ship);
    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char* requestWriter :: ship_impulse_drive_information(unsigned long ship)
{
	protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_SHIP_IMPULSE_DRIVE_INFORMATION);
		w.writeValue(REQUEST_SHIP_IMPULSE_DRIVE_INFORMATION_SHIPID, ship);
    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char* requestWriter :: fortress_weapons_information(unsigned long fortress)
{
	protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_FORTRESS_WEAPONS_INFORMATION);
		w.writeValue(REQUEST_FORTRESS_WEAPONS_INFORMATION_FORTRESSID, fortress);
    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char* requestWriter :: fortress_set_weapons(unsigned long fortress, std :: list<idx_and_energy_lvl>& drone_launchers,
        std :: list<idx_and_energy_lvl>& laser_guns)
{
	protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_FORTRESS_WEAPONS_SET);

	w.writeValue(REQUEST_FORTRESS_WEAPONS_SET_FORTRESSID, fortress);

	for (std::list<idx_and_energy_lvl>::const_iterator it = drone_launchers.begin(); it != drone_launchers.end(); ++it) {
		std::stringstream ss;
		ss << REQUEST_FORTRESS_WEAPONS_LAUNCHER_PREFIX << it->first;
		w.writeValue(ss.str(), it->second);

		ss.clear(); ss.str("");

		ss << REQUEST_FORTRESS_WEAPONS_LAUNCHER_IS_SET << it->first;
		w.writeValue(ss.str(), true);
	}

	for (std::list<idx_and_energy_lvl>::const_iterator it = laser_guns.begin(); it != laser_guns.end(); ++it) {
		std::stringstream ss;
		ss << REQUEST_FORTRESS_WEAPONS_LASER_PREFIX << it->first;
		w.writeValue(ss.str(), it->second);

		ss.clear(); ss.str("");

		ss << REQUEST_FORTRESS_WEAPONS_LASER_IS_SET << it->first;
		w.writeValue(ss.str(), true);
	}

	w.endMessage(true);
	return w.copyMessage();
}

// --------------------------------

char* requestWriter :: fortress_mainframe_information(unsigned long fortress)
{
	protocolWriter w;
    w.beginMessage(MT_REQUEST, REQUEST_FORTRESS_MAINFRAME_INFORMATION);
	w.writeValue(REQUEST_FORTRESS_MAINFRAME_INFORMATION_FORTRESSID, fortress);

	w.endMessage(true);
	return w.copyMessage();
}

// --------------------------------

char* requestWriter :: fortress_crew_information(unsigned long fortress)
{
	protocolWriter w;
	w.beginMessage(MT_REQUEST, REQUEST_FORTRESS_CREW_INFORMATION);
	w.writeValue(REQUEST_FORTRESS_CREW_INFORMATION_FORTRESSID, fortress);

	w.endMessage(true);
	return w.copyMessage();
}

// --------------------------------

std :: string create_param_name(const std :: string & item, int index)
{
    std :: stringstream s;
    s << item << index;
    return s.str();
}

// --------------------------------

std :: string create_param_name(const std :: string & item, int topindex, int subindex) {
    std :: stringstream s;
    s << item << topindex << "_" << subindex;
    return s.str();
}

// --------------------------------

std :: string create_param_name(const std :: string & listname, const std :: string & itemname, int index)
{
    std :: stringstream s;
    s << listname << "_" << index << "_" << itemname;
    return s.str();
}

// --------------------------------

std :: string create_param_name(const std :: string & listname, const std :: string & itemname, int topindex, int subindex)
{
    std :: stringstream s;
    s << listname << "_" << topindex << "_" << subindex << "_" << itemname;
    return s.str();
}

// --------------------------------

std :: string create_count_name(const std :: string & listname)
{
    std :: stringstream s;
    s << listname << "_" << "count";
    return s.str();
}

// --------------------------------

std :: string create_param_name(const std :: string & parentname, const std :: string & itemname)
{
    std :: stringstream s;
    s << parentname << "_" << itemname;
    return s.str();
}

// --------------------------------

char* requestWriter :: fortress_quarry_info(unsigned long fortress)
{
    protocolWriter w;
	w.beginMessage(MT_REQUEST, REQUEST_FORTRESS_QUARRY_INFORMATION);
	w.writeValue(REQUEST_FORTRESS_QUARRY_INFORMATION_FORTRESSID, fortress);

	w.endMessage(true);
	return w.copyMessage();
}

// --------------------------------

char* requestWriter :: fortress_quarry_change_state(unsigned long fortress, const protQuarryType pt, bool newState)
{
    protocolWriter w;
	w.beginMessage(MT_REQUEST, REQUEST_FORTRESS_QUARRY_CHANGE_STATE);
	w.writeValue(REQUEST_FORTRESS_QUARRY_CHANGE_STATE_FORTRESS_ID,  fortress);
	w.writeValue(REQUEST_FORTRESS_QUARRY_CHANGE_STATE_PQ_TYPE,      (unsigned long long)pt);
    w.writeValue(REQUEST_FORTRESS_QUARRY_CHANGE_STATE_NEW_STATE,    (unsigned long long)(newState ? 1 : 0));

	w.endMessage(true);
	return w.copyMessage();
}

// --------------------------------

char* requestWriter :: fortress_accommodations_information(unsigned long fortress)
{
    protocolWriter w;
	w.beginMessage(MT_REQUEST, REQUEST_FORTRESS_ACCOMMODATIONS_INFORMATION);
	w.writeValue(REQUEST_FORTRESS_ACCOMMODATIONS_INFORMATION_FORTRESSID, fortress);

	w.endMessage(true);
	return w.copyMessage();
}

// --------------------------------

char* requestWriter :: fortress_other_equipment_information(unsigned long fortress) {
    protocolWriter w;
	w.beginMessage(MT_REQUEST, REQUEST_FORTRESS_OTHER_EQUIPMENT_INFORMATION);
	w.writeValue(REQUEST_FORTRESS_OTHER_EQUIPMENT_INFORMATION_FORTRESSID, fortress);

	w.endMessage(true);
	return w.copyMessage();
}

// --------------------------------

char* requestWriter :: base_factories_information(unsigned long base) {
    protocolWriter w;
	w.beginMessage(MT_REQUEST, REQUEST_BASE_FACTORIES_INFORMATION);
	w.writeValue(REQUEST_BASE_FACTORIES_INFORMATION_FORTRESSID, base);

	w.endMessage(true);
	return w.copyMessage();
}

// --------------------------------

char* requestWriter :: fortress_warehouses_information(unsigned long fortress) {
    protocolWriter w;
	w.beginMessage(MT_REQUEST, REQUEST_FORTRESS_WAREHOUSES_INFORMATION);
	w.writeValue(REQUEST_FORTRESS_WAREHOUSES_INFORMATION_FORTRESSID, fortress);

	w.endMessage(true);
	return w.copyMessage();
}

// --------------------------------

char* requestWriter :: ship_androids_information(unsigned long fortress) {
    protocolWriter w;
	w.beginMessage(MT_REQUEST, REQUEST_SHIP_ANDROIDS_INFORMATION);
	w.writeValue(REQUEST_SHIP_ANDROIDS_INFORMATION_FORTRESSID, fortress);

	w.endMessage(true);
	return w.copyMessage();
}

// --------------------------------

char* requestWriter :: base_androids_information(unsigned long fortress) {
    protocolWriter w;
	w.beginMessage(MT_REQUEST, REQUEST_BASE_ANDROIDS_INFORMATION);
	w.writeValue(REQUEST_BASE_ANDROIDS_INFORMATION_FORTRESSID, fortress);

	w.endMessage(true);
	return w.copyMessage();
}

// --------------------------------

char* requestWriter :: change_ship_androids_state(const unsigned long fortressId, const ship_androids_request_status & sds) {
    
	protocolWriter w;
	w.beginMessage(MT_ANSWER, REQUEST_CHANGE_SHIP_ANDROIDS_STATE);
	w.writeValue(REQUEST_CHANGE_SHIP_ANDROIDS_STATE_ANSWER_FORTRESSID, fortressId);

	write_androids_request_state(w, sds);
	write_androids_assignment(w, REQUEST_ANDROIDS_ASSIGNMENT_SECTION_IMPULSDRIVE, sds.impulsDrive);
	write_androids_assignment(w, REQUEST_ANDROIDS_ASSIGNMENT_SECTION_SUBSPACEDRIVE, sds.subspaceDrive);

    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------
char* requestWriter :: base_hangar_information(unsigned long fortressId, unsigned long hangarId, const std::string & patternName)
 {   
	protocolWriter w;
	w.beginMessage(MT_ANSWER, REQUEST_BASE_HANGARS_INFORMATION);
	w.writeValue(REQUEST_BASE_HANGARS_INFORMATION_FORTRESSID, fortressId);
	w.writeValue(REQUEST_BASE_HANGARS_INFORMATION_HANGAR_ID, hangarId);
	w.writeValue(REQUEST_BASE_HANGARS_INFORMATION_SELECTED_ITEM_ID, patternName);
	w.writeValue(REQUEST_BASE_HANGARS_INFORMATION_ARBITRARY_HANGAR, (unsigned long) 0);

    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------
char* requestWriter :: base_hangar_item_information(const std::string & itemPattenId)  {
    
	protocolWriter w;
	w.beginMessage(MT_ANSWER, REQUEST_BASE_HANGAR_ITEM_INFORMATION);
	w.writeValue(REQUEST_BASE_HANGAR_ITEM_INFORMATION_ITEM_ID, itemPattenId);

    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

char* requestWriter :: change_base_androids_state(const unsigned long fortressId, const base_androids_request_status & sds) {
    
	protocolWriter w;
	w.beginMessage(MT_ANSWER, REQUEST_CHANGE_BASE_ANDROIDS_STATE);
	w.writeValue(REQUEST_CHANGE_BASE_ANDROIDS_STATE_ANSWER_FORTRESSID, fortressId);

	write_androids_request_state(w, sds);
	write_androids_assignment(w, REQUEST_ANDROIDS_ASSIGNMENT_SECTION_FACTORIES, sds.factories);
	write_androids_assignment(w, REQUEST_ANDROIDS_ASSIGNMENT_SECTION_HANGARS, sds.hangars);

    w.endMessage(true);
    return w.copyMessage();
}

// --------------------------------

void requestWriter :: write_androids_request_state(protocolWriter& w, const androids_request_status & sds)
{	
	w.writeValue(REQUEST_CHANGE_BASE_ANDROIDS_STATE_WORKING_ANDROIDS_SLIDER, sds.workingAndroidsSlider);
	w.writeValue(REQUEST_CHANGE_BASE_ANDROIDS_STATE_REP_CON_SLIDER, sds.repConSlider);

    write_androids_assignment(w, REQUEST_ANDROIDS_ASSIGNMENT_SECTION_CLOAKING, sds.cloaking);
	write_androids_assignment(w, REQUEST_ANDROIDS_ASSIGNMENT_SECTION_DEFLECTORSHIELDS, sds.deflectorShields);
	write_androids_assignment(w, REQUEST_ANDROIDS_ASSIGNMENT_SECTION_ENERGETICSYSTEM, sds.energeticSystem);
	write_androids_assignment(w, REQUEST_ANDROIDS_ASSIGNMENT_SECTION_MAINFRAMESYSTEM, sds.mainframeSystem);
	write_androids_assignment(w, REQUEST_ANDROIDS_ASSIGNMENT_SECTION_MECHANICS, sds.mechanics);	
	write_androids_assignment(w, REQUEST_ANDROIDS_ASSIGNMENT_SECTION_MININGDEVICES, sds.miningDevices);
	write_androids_assignment(w, REQUEST_ANDROIDS_ASSIGNMENT_SECTION_OTHEREQUIPMENT, sds.otherEquipment);
	write_androids_assignment(w, REQUEST_ANDROIDS_ASSIGNMENT_SECTION_PROBEDEVICES, sds.probeDevices);
	write_androids_assignment(w, REQUEST_ANDROIDS_ASSIGNMENT_SECTION_SENSORS, sds.sensors);
	write_androids_assignment(w, REQUEST_ANDROIDS_ASSIGNMENT_SECTION_TRANSPORTBEAM, sds.transportBeam);
	write_androids_assignment(w, REQUEST_ANDROIDS_ASSIGNMENT_SECTION_WAREHOUSE, sds.warehouse);
	write_androids_assignment(w, REQUEST_ANDROIDS_ASSIGNMENT_SECTION_WEAPONS, sds.weapons);	
	write_androids_assignment(w, REQUEST_ANDROIDS_ASSIGNMENT_SECTION_STRUCTURALINTEGRITY, sds.structuralIntegrity);	
}

// --------------------------------

void requestWriter :: write_androids_assignment(protocolWriter& w, const std::string & section, const androids_assignment & assignment)
{
    std :: stringstream ss;

	ss << section << REQUEST_ANDROIDS_ASSSIGNMENT_PRIORITY;
    w.writeValue(ss.str(), (unsigned long)assignment.priority);
    ss.str("");

	ss << section << REQUEST_ANDROIDS_ASSSIGNMENT_RATIO;
    w.writeValue(ss.str(), assignment.ratio);
    ss.str("");
}

// --------------------------------

char* requestWriter :: navigation_move_to(unsigned long ship, signed long long posx, signed long long posy, unsigned long long limitSeconds)
{
    return navigation_move_to(ship, posx, posy, (dv_time :: datetime)(((dv_time :: datetime) (double)limitSeconds) / dv_time :: datetime :: second()));
}

// --------------------------------

char* requestWriter :: navigation_pursuit(unsigned long ship, unsigned long target, unsigned long long limitSeconds)
{
    return navigation_pursuit(ship, target, (dv_time :: datetime)(((dv_time :: datetime) (double)limitSeconds) / dv_time :: datetime :: second()));
}

// --------------------------------

char* requestWriter :: navigation_move_to_spobj(unsigned long ship, unsigned long spaceObject, unsigned long long limitSeconds)
{
    return navigation_move_to_spobj(ship, spaceObject, (dv_time :: datetime)(((dv_time :: datetime) (double)limitSeconds) / dv_time :: datetime :: second()));
}

// --------------------------------

char* requestWriter :: ship_location_information(unsigned long ship)
{
    protocolWriter w;
	w.beginMessage(MT_REQUEST, REQUEST_SHIP_LOCATION_INFORMATION);
	w.writeValue(REQUEST_SHIP_LOCATION_INFORMATION_SHIPID, ship);

	w.endMessage(true);
	return w.copyMessage();
}

// --------------------------------

char* requestWriter :: base_hangar_build_item(unsigned long fortressId, const HangarServerInputData & data)
{
    protocolWriter w;
	w.beginMessage(MT_REQUEST, REQUEST_HANGAR_BUILD_ITEM);
	w.writeValue(REQUEST_HANGAR_BUILD_ITEM_FORTRESS_ID, fortressId);
	w.writeValue(REQUEST_HANGAR_BUILD_ITEM_HANGAR_ID, data.hangarId);
	w.writeValue(REQUEST_HANGAR_BUILD_ITEM_QUANTITY, (unsigned long) data.quantity);
	w.writeValue(REQUEST_HANGAR_BUILD_ITEM_LENGTH, (unsigned long) data.length);
	w.writeValue(REQUEST_HANGAR_BUILD_ITEM_WIDTH, (unsigned long) data.width);
	w.writeValue(REQUEST_HANGAR_BUILD_ITEM_HEIGHT, (unsigned long) data.height);
	w.writeValue(REQUEST_HANGAR_BUILD_ITEM_PATTERN_NAME, data.type);
	w.writeValue(REQUEST_HANGAR_BUILD_ITEM_WEIGHT, (unsigned long) data.weight);

	w.endMessage(true);
	return w.copyMessage();
}

// --------------------------------

char* requestWriter :: base_hangar_cancel_item(unsigned long fortressId, unsigned long hangarId)
{
    protocolWriter w;
	w.beginMessage(MT_REQUEST, REQUEST_HANGAR_CANCEL_ITEM);
	w.writeValue(REQUEST_HANGAR_CANCEL_ITEM_FORTRESS_ID, fortressId);
	w.writeValue(REQUEST_HANGAR_CANCEL_ITEM_HANGAR_ID, hangarId);

	w.endMessage(true);
	return w.copyMessage();
}

// --------------------------------

char* requestWriter :: unmount_fortress_device(const unmount_device_info & data)
{
    protocolWriter w;
	w.beginMessage(MT_REQUEST, REQUEST_UNMOUNT_FORTRESS_DEVICE);
	w.writeValue(REQUEST_UNMOUNT_FORTRESS_DEVICE_FORTRESSID, data.fortressId);
	w.writeValue(REQUEST_UNMOUNT_FORTRESS_DEVICE_PATTERN_NAME, data.patternName);
	w.writeValue(REQUEST_UNMOUNT_FORTRESS_DEVICE_CONCRETEID, data.concreteId);
	w.writeValue(REQUEST_UNMOUNT_FORTRESS_DEVICE_WORKING, data.working);
	w.writeValue(REQUEST_UNMOUNT_FORTRESS_DEVICE_DAMAGED, data.damaged);

	w.endMessage(true);
	return w.copyMessage();
}

// --------------------------------

char* requestWriter :: mount_fortress_device(const mount_device_info & data)
{
    protocolWriter w;
	w.beginMessage(MT_REQUEST, REQUEST_MOUNT_FORTRESS_DEVICE);
	w.writeValue(REQUEST_MOUNT_FORTRESS_DEVICE_FORTRESSID, data.fortressId);
	w.writeValue(REQUEST_MOUNT_FORTRESS_DEVICE_ITEM_ID, data.itemId);
	w.writeValue(REQUEST_MOUNT_FORTRESS_DEVICE_COUNT, data.count);

	w.endMessage(true);
	return w.copyMessage();
}

// --------------------------------

char* requestWriter :: send_trade_invitation(unsigned long hostFortressId, unsigned long invitedFortressId)
{
    protocolWriter w;
	w.beginMessage(MT_REQUEST, REQUEST_SEND_TRADE_INVITATION);
	w.writeValue(REQUEST_SEND_TRADE_INVITATION_HOST_FORTRESS_ID, hostFortressId);
	w.writeValue(REQUEST_SEND_TRADE_INVITATION_INVITED_FORTRESS_ID, invitedFortressId);

	w.endMessage(true);
	return w.copyMessage();
}

char* requestWriter :: cancel_trade_with_partner()
{
    protocolWriter w;
	w.beginMessage(MT_REQUEST, REQUEST_CANCEL_TRADE);

	w.endMessage(true);
	return w.copyMessage();
}


char* requestWriter :: trade_partner_fortresses(unsigned long fortressId)
{
    protocolWriter w;
	w.beginMessage(MT_REQUEST, REQUEST_TRADE_PARTNER_FORTRESSES);
	w.writeValue(REQUEST_TRADE_PARTNER_FORTRESSES_FORTRESS_ID, fortressId);

	w.endMessage(true);
	return w.copyMessage();
}

char* requestWriter :: decide_trade_invitation(unsigned long hostFortressId, unsigned long invitedFortressId, bool accepted) {
    protocolWriter w;

	w.beginMessage(MT_REQUEST, REQUEST_DECIDE_TRADE_INVITATION);
	w.writeValue(REQUEST_DECIDE_TRADE_INVITATION_HOST_FORTRESS_ID, hostFortressId);
	w.writeValue(REQUEST_DECIDE_TRADE_INVITATION_INVITED_FORTRESS_ID, invitedFortressId);
	w.writeValue(REQUEST_DECIDE_TRADE_INVITATION_ACCEPTED, accepted);

	w.endMessage(true);
	return w.copyMessage();
}

// --------------------------------

char* requestWriter :: cancel_trade_commit(unsigned long selfFortressId, unsigned long partnerFortressId) {
    protocolWriter w;

	w.beginMessage(MT_REQUEST, REQUEST_CANCEL_TRADE_COMMIT);
	w.writeValue(REQUEST_CANCEL_TRADE_COMMIT_SELF_FORTRESS_ID, selfFortressId);
	w.writeValue(REQUEST_CANCEL_TRADE_COMMIT_PARTNER_FORTRESS_ID, partnerFortressId);

	w.endMessage(true);
	return w.copyMessage();
}

// --------------------------------

char* requestWriter :: move_trade_item(const trade_client_movement_data & tradeData)
{
	protocolWriter w;

	w.beginMessage(MT_REQUEST, REQUEST_MOVE_TRADE_ITEM);
	write_trade_movement_data(w, tradeData);
	/*
	w.writeValue(TRADE_CLIENT_MOVEMENT_DATA_ITEM_ID, tradeData.itemId);
	w.writeValue(TRADE_CLIENT_MOVEMENT_DATA_SELF_FORTRESS_ID, tradeData.selfFortressId);
	w.writeValue(TRADE_CLIENT_MOVEMENT_DATA_PARTNER_FORTRESS_ID, tradeData.partnerFortressId);
	w.writeValue(TRADE_CLIENT_MOVEMENT_DATA_WORKING, tradeData.working);
	w.writeValue(TRADE_CLIENT_MOVEMENT_DATA_DAMAGED, tradeData.damaged);
	w.writeValue(TRADE_CLIENT_MOVEMENT_DATA_TRADE_DIRECTION, tradeData.tradeDirection);
	w.writeValue(TRADE_CLIENT_MOVEMENT_DATA_PATTERN_NAME, tradeData.patternName);
	*/
	w.endMessage(true);
	return w.copyMessage();
}
// --------------------------------

std::string resourceTypeToString(game_resource_type resourceType) 
{
	switch (resourceType)
	{
	case GAME_RESOURCE_TYPE_DEUTERIUM:
		return PROTOCOL_RESOURCE_TYPE_DEUTERIUM;
	case GAME_RESOURCE_TYPE_ENERGY:
		return PROTOCOL_RESOURCE_TYPE_ENERGY;
	case GAME_RESOURCE_TYPE_HEAVY_WATER:
		return PROTOCOL_RESOURCE_TYPE_HEAVY_WATER;
	case GAME_RESOURCE_TYPE_ILMENITE:
		return PROTOCOL_RESOURCE_TYPE_ILMENITE;
	case GAME_RESOURCE_TYPE_QUARK_GLUON_PLASMA:
		return PROTOCOL_RESOURCE_TYPE_QUARK_GLUON_PLASMA;
	case GAME_RESOURCE_TYPE_TITANIUM:
		return PROTOCOL_RESOURCE_TYPE_TITANIUM;
	case GAME_RESOURCE_TYPE_ULREA:
		return PROTOCOL_RESOURCE_TYPE_ULREA;
	case GAME_RESOURCE_TYPE_ZIRCONIUM_CRYSTALS:
		return PROTOCOL_RESOURCE_TYPE_ZIRCONIUM_CRYSTALS;
	}

	return "";
}

game_resource_type stringToResourceType(std::string resourceType) 
{
	if (resourceType == PROTOCOL_RESOURCE_TYPE_DEUTERIUM) {
		return GAME_RESOURCE_TYPE_DEUTERIUM;
	}
	else if (resourceType == PROTOCOL_RESOURCE_TYPE_ENERGY) {
		return GAME_RESOURCE_TYPE_ENERGY;
	}
	else if (resourceType == PROTOCOL_RESOURCE_TYPE_HEAVY_WATER) {
		return GAME_RESOURCE_TYPE_HEAVY_WATER;
	}
	else if (resourceType == PROTOCOL_RESOURCE_TYPE_ILMENITE) {
		return GAME_RESOURCE_TYPE_ILMENITE;
	}
	else if (resourceType == PROTOCOL_RESOURCE_TYPE_QUARK_GLUON_PLASMA) {
		return GAME_RESOURCE_TYPE_QUARK_GLUON_PLASMA;
	}
	else if (resourceType == PROTOCOL_RESOURCE_TYPE_TITANIUM) {
		return GAME_RESOURCE_TYPE_TITANIUM;
	}
	else if (resourceType == PROTOCOL_RESOURCE_TYPE_ULREA) {
		return GAME_RESOURCE_TYPE_ULREA;
	}
	else if (resourceType == PROTOCOL_RESOURCE_TYPE_ZIRCONIUM_CRYSTALS) {
		return GAME_RESOURCE_TYPE_ZIRCONIUM_CRYSTALS;
	}
	else {
		return GAME_RESOURCE_TYPE_UNKNOWN_MAPPING;
	}
}

// --------------------------------

char* requestWriter :: move_trade_resource(const trade_resource_movement_data & tradeData)
{
	protocolWriter w;

	w.beginMessage(MT_REQUEST, REQUEST_MOVE_TRADE_RESOURCE);
	write_trade_resource_movement_data(w, tradeData);

	w.endMessage(true);
	return w.copyMessage();
}

// --------------------------------

void write_trade_resource_movement_data(protocolWriter & w, const trade_resource_movement_data & tradeData)
{
	w.writeValue(TRADE_RESOURCE_MOVEMENT_DATA_COUNT, tradeData.count);
	w.writeValue(TRADE_RESOURCE_MOVEMENT_DATA_SELF_FORTRESS_ID, tradeData.selfFortressId);
	w.writeValue(TRADE_RESOURCE_MOVEMENT_DATA_PARTNER_FORTRESS_ID, tradeData.partnerFortressId);
	w.writeValue(TRADE_RESOURCE_MOVEMENT_DATA_RESOURCE_TYPE, resourceTypeToString(tradeData.resourceType));
	w.writeValue(TRADE_RESOURCE_MOVEMENT_DATA_TRADE_DIRECTION, tradeData.tradeDirection);
}

char* requestWriter :: commit_trade(unsigned long selfFortressId, unsigned long partnerFortressId, const client_trade_data & selfOffer, const client_trade_data & partnerOffer)
{
	protocolWriter w;

	w.beginMessage(MT_REQUEST, REQUEST_COMMIT_TRADE);
	w.writeValue(REQUEST_COMMIT_TRADE_SELF_FORTRESS_ID, selfFortressId);
	w.writeValue(REQUEST_COMMIT_TRADE_PARTNER_FORTRESS_ID, partnerFortressId);

	write_client_trade_data(w, REQUEST_COMMIT_TRADE_SELF_DATA_PREFIX, selfOffer);
	write_client_trade_data(w, REQUEST_COMMIT_TRADE_PARTNER_DATA_PREFIX, partnerOffer);

	w.endMessage(true);
	return w.copyMessage();
}

// --------------------------------

void write_client_trade_data(protocolWriter & w, const std::string & prefix, const client_trade_data & tradeData)
{
	w.writeValue(create_param_name(prefix, TRADE_ITEM_DATA_ITEM_COUNT), (unsigned long) tradeData.tradeItems.size());

	unsigned long index = 1;
	for (std::list<client_trade_item_data>::const_iterator it = tradeData.tradeItems.begin(); it != tradeData.tradeItems.end(); ++it) 
	{
		w.writeValue(create_param_name(prefix, TRADE_ITEM_DATA_PATTERN_NAME, index), it->patternName);
		w.writeValue(create_param_name(prefix, TRADE_ITEM_DATA_ID, index), it->id);
		w.writeValue(create_param_name(prefix, TRADE_ITEM_DATA_WORKING, index), it->working);
		w.writeValue(create_param_name(prefix, TRADE_ITEM_DATA_DAMAGED, index), it->damaged);
		index++;
	}	

	w.writeValue(create_param_name(prefix, TRADE_ITEM_DATA_DEUTERIUM), tradeData.deuterium);
	w.writeValue(create_param_name(prefix, TRADE_ITEM_DATA_HEAVY_WATER), tradeData.heavyWater);
	w.writeValue(create_param_name(prefix, TRADE_ITEM_DATA_ILMENITE), tradeData.ilmenite);
	w.writeValue(create_param_name(prefix, TRADE_ITEM_DATA_QUARK_GLUON_PLASMA), tradeData.quarkGluonPlasma);
	w.writeValue(create_param_name(prefix, TRADE_ITEM_DATA_TITANIUM), tradeData.titanium);
	w.writeValue(create_param_name(prefix, TRADE_ITEM_DATA_ULREA), tradeData.ulrea);
	w.writeValue(create_param_name(prefix, TRADE_ITEM_DATA_ZIRCONIUM_CRYSTAL), tradeData.zirconiumCrystal);
	w.writeValue(create_param_name(prefix, TRADE_ITEM_DATA_ENERGY), tradeData.energy);
}

char* requestWriter :: fortresses_in_weapons_range(unsigned long fortressId)
{
	protocolWriter w;

	w.beginMessage(MT_REQUEST, REQUEST_FORTRESSES_IN_WEAPONS_RANGE);
	w.writeValue(REQUEST_FORTRESSES_IN_WEAPONS_RANGE_FORTRESS_ID, fortressId);
	w.endMessage(true);
	return w.copyMessage();
}

char* requestWriter :: attack_fortress(unsigned long selfFortressId, unsigned long enemyFortressId)
{
	protocolWriter w;

	w.beginMessage(MT_REQUEST, REQUEST_ATTACK_FORTRESS);
	w.writeValue(REQUEST_ATTACK_FORTRESS_SELF_FORTRESS_ID, selfFortressId);
	w.writeValue(REQUEST_ATTACK_FORTRESS_ENEMY_FORTRESS_ID, enemyFortressId);
	w.endMessage(true);
	return w.copyMessage();
}

char* requestWriter :: stop_attack_fortress(unsigned long selfFortressId)
{
	protocolWriter w;

	w.beginMessage(MT_REQUEST, REQUEST_STOP_ATTACK_FORTRESS);
	w.writeValue(REQUEST_STOP_ATTACK_FORTRESS_SELF_FORTRESS_ID, selfFortressId);
	w.endMessage(true);
	return w.copyMessage();
}

bool fight_action_type_to_string(fight_action_type action, std::string & actionString) {
	switch (action) {
	case FIGHT_ACTION_OUR_WEAPONS_UNLOCKED:		
		actionString = PROTOCOL_FIGHT_ACTION_OUR_WEAPONS_UNLOCKED;
		return true;
	case FIGHT_ACTION_OUR_WEAPONS_LOCKED_ON_ENEMY:
		actionString =  PROTOCOL_FIGHT_ACTION_OUR_WEAPONS_LOCKED_ON_ENEMY;
		return true;
	case FIGHT_ACTION_ENEMY_WEAPONS_UNLOCKED:	
		actionString =  PROTOCOL_FIGHT_ACTION_ENEMY_WEAPONS_UNLOCKED;
		return true;
	case FIGHT_ACTION_ENEMY_WEAPONS_LOCKED_ON_WARNING:	
		actionString =  PROTOCOL_FIGHT_ACTION_ENEMY_WEAPONS_LOCKED_ON_WARNING;
		return true;
	case FIGHT_ACTION_WEAPONS_TARGET_HAS_BEEN_ANNIHILATED:
		actionString =  PROTOCOL_FIGHT_ACTION_WEAPONS_TARGET_HAS_BEEN_ANNIHILATED;
		return true;
	case FIGHT_ACTION_THIS_FORTRESS_HAS_BEEN_ANNIHILATED:
		actionString =  PROTOCOL_FIGHT_ACTION_THIS_FORTRESS_HAS_BEEN_ANNIHILATED;
		return true;
	}

	return false;
}

bool string_to_fight_action_type(const std::string & actionString, fight_action_type & action) {
	if (actionString == PROTOCOL_FIGHT_ACTION_OUR_WEAPONS_UNLOCKED) {
		action = FIGHT_ACTION_OUR_WEAPONS_UNLOCKED;
		return true;
	}
	else if (actionString == PROTOCOL_FIGHT_ACTION_OUR_WEAPONS_LOCKED_ON_ENEMY) {
		action =  FIGHT_ACTION_OUR_WEAPONS_LOCKED_ON_ENEMY;
		return true;
	}
	else if (actionString == PROTOCOL_FIGHT_ACTION_ENEMY_WEAPONS_UNLOCKED) {
		action =  FIGHT_ACTION_ENEMY_WEAPONS_UNLOCKED;
		return true;
	}
	else if (actionString == PROTOCOL_FIGHT_ACTION_ENEMY_WEAPONS_LOCKED_ON_WARNING) {
		action =  FIGHT_ACTION_ENEMY_WEAPONS_LOCKED_ON_WARNING;
		return true;
	}
	else if (actionString == PROTOCOL_FIGHT_ACTION_WEAPONS_TARGET_HAS_BEEN_ANNIHILATED) {
		action =  FIGHT_ACTION_WEAPONS_TARGET_HAS_BEEN_ANNIHILATED;
		return true;
	}
	else if (actionString == PROTOCOL_FIGHT_ACTION_THIS_FORTRESS_HAS_BEEN_ANNIHILATED) {
		action =  FIGHT_ACTION_THIS_FORTRESS_HAS_BEEN_ANNIHILATED;
		return true;
	}

	return false;
}

char* requestWriter :: fortresses_in_conquer_range(unsigned long fortressId)
{
	protocolWriter w;

	w.beginMessage(MT_REQUEST, REQUEST_FORTRESSES_IN_CONQUER_RANGE);
	w.writeValue(REQUEST_FORTRESSES_IN_CONQUER_RANGE_SELF_FORTRESS_ID, fortressId);
	w.endMessage(true);
	return w.copyMessage();
}

char* requestWriter :: build_new_base_shell(unsigned long fortressId, unsigned long fortressClassId, unsigned long long buildingTitanium)
{
	protocolWriter w;

	w.beginMessage(MT_REQUEST, REQUEST_BUILD_NEW_BASE_SHELL);
	w.writeValue(REQUEST_BUILD_NEW_BASE_SHELL_SELF_FORTRESS_ID, fortressId);
	w.writeValue(REQUEST_BUILD_NEW_BASE_SHELL_FORTRESS_CLASS_ID, fortressClassId);
	w.writeValue(REQUEST_BUILD_NEW_BASE_SHELL_TITANIUM, buildingTitanium);
	w.endMessage(true);
	return w.copyMessage();
}

char* requestWriter :: available_fortress_classes(unsigned long selfFortressId)
{
	protocolWriter w;

	w.beginMessage(MT_REQUEST, REQUEST_AVAILABLE_FORTRESS_CLASSES);
	w.writeValue(REQUEST_AVAILABLE_FORTRESS_CLASSES_SELF_FORTRESS_ID, selfFortressId);
	w.endMessage(true);
	return w.copyMessage();
}

char* requestWriter :: fortress_class_data(unsigned long fortressClassId)
{
	protocolWriter w;

	w.beginMessage(MT_REQUEST, REQUEST_FORTRESS_CLASS_DATA);
	w.writeValue(REQUEST_FORTRESS_CLASS_DATA_FORTRESS_CLASS_ID, fortressClassId);
	w.endMessage(true);
	return w.copyMessage();
}

char* requestWriter :: player_fortresses_build_information()
{
	protocolWriter w;

	w.beginMessage(MT_REQUEST, REQUEST_PLAYER_FORTRESSES_BUILD_INFORMATION);
	w.endMessage(true);
	return w.copyMessage();
}

char* requestWriter :: player_fortresses()
{
	protocolWriter w;

	w.beginMessage(MT_REQUEST, REQUEST_PLAYER_FORTRESSES);
	w.endMessage(true);
	return w.copyMessage();
}

char* requestWriter :: conquer_fortress(unsigned long selfFortressId, unsigned long enemyFortressId) 
{
	protocolWriter w;

	w.beginMessage(MT_REQUEST, REQUEST_CONQUER_FORTRESS);
	w.writeValue(REQUEST_CONQUER_FORTRESS_SELF_FORTRESS_ID, selfFortressId);
	w.writeValue(REQUEST_CONQUER_FORTRESS_ENEMY_FORTRESS_ID, enemyFortressId);
	w.endMessage(true);
	return w.copyMessage();
}

char* requestWriter :: fortress_add_accommodations(unsigned long fortressId, unsigned long count, accommodation_type accommodationType) {
	protocolWriter w;

	w.beginMessage(MT_REQUEST, REQUEST_FORTRESS_ADD_ACCOMMODATIONS);
	w.writeValue(REQUEST_FORTRESS_ADD_ACCOMMODATIONS_FORTRESS_ID, fortressId);
	w.writeValue(REQUEST_FORTRESS_ADD_ACCOMMODATIONS_ACCOMMODATION_COUNT, count);
	w.writeValue(REQUEST_FORTRESS_ADD_ACCOMMODATIONS_ACCOMMODATION_TYPE, (unsigned long) accommodationType);
	w.endMessage(true);
	return w.copyMessage();
}

char* requestWriter :: fortress_add_crew(unsigned long fortressId, unsigned long able, unsigned long wounded, crew_type crewType) {
	protocolWriter w;

	w.beginMessage(MT_REQUEST, REQUEST_FORTRESS_ADD_CREW);
	w.writeValue(REQUEST_FORTRESS_ADD_CREW_FORTRESS_ID, fortressId);
	w.writeValue(REQUEST_FORTRESS_ADD_CREW_ABLE_COUNT, able);
	w.writeValue(REQUEST_FORTRESS_ADD_CREW_WOUNDED_COUNT, wounded);
	w.writeValue(REQUEST_FORTRESS_ADD_CREW_CREW_TYPE, (unsigned long) crewType);
	w.endMessage(true);
	return w.copyMessage();
}

char* requestWriter :: fortress_remove_crew(unsigned long fortressId, unsigned long able, unsigned long wounded, crew_type crewType) {
	protocolWriter w;

	w.beginMessage(MT_REQUEST, REQUEST_FORTRESS_REMOVE_CREW);
	w.writeValue(REQUEST_FORTRESS_REMOVE_CREW_FORTRESS_ID, fortressId);
	w.writeValue(REQUEST_FORTRESS_REMOVE_CREW_ABLE_COUNT, able);
	w.writeValue(REQUEST_FORTRESS_REMOVE_CREW_WOUNDED_COUNT, wounded);
	w.writeValue(REQUEST_FORTRESS_REMOVE_CREW_CREW_TYPE, (unsigned long) crewType);
	w.endMessage(true);
	return w.copyMessage();
}

// --------------------------------

void requestWriter :: write_trade_movement_data(protocolWriter & w, const trade_client_movement_data & tradeData)
{
	w.writeValue(TRADE_CLIENT_MOVEMENT_DATA_ITEM_ID, tradeData.itemId);
	w.writeValue(TRADE_CLIENT_MOVEMENT_DATA_SELF_FORTRESS_ID, tradeData.selfFortressId);
	w.writeValue(TRADE_CLIENT_MOVEMENT_DATA_PARTNER_FORTRESS_ID, tradeData.partnerFortressId);
	w.writeValue(TRADE_CLIENT_MOVEMENT_DATA_WORKING, tradeData.working);
	w.writeValue(TRADE_CLIENT_MOVEMENT_DATA_DAMAGED, tradeData.damaged);
	w.writeValue(TRADE_CLIENT_MOVEMENT_DATA_TRADE_DIRECTION, tradeData.tradeDirection);
	w.writeValue(TRADE_CLIENT_MOVEMENT_DATA_PATTERN_NAME, tradeData.patternName);
}

char* requestWriter :: game_seconds_per_actual_second() {
	protocolWriter w;

	w.beginMessage(MT_REQUEST, REQUEST_GAME_SECONDS_PER_ACTUAL_SECOND);
	w.endMessage(true);
	return w.copyMessage();
}

char* requestWriter :: rename_fortress(unsigned long fortressId, const std::string & newName) {
	protocolWriter w;

	w.beginMessage(MT_REQUEST, REQUEST_RENAME_FORTRESS);
	w.writeValue(REQUEST_RENAME_FORTRESS_FORTRESS_ID, fortressId);
	w.writeValue(REQUEST_RENAME_FORTRESS_NEW_NAME, newName);
	w.endMessage(true);
	return w.copyMessage();
}

char* requestWriter :: player_fortresses_attack_information()
{
	protocolWriter w;

	w.beginMessage(MT_REQUEST, REQUEST_PLAYER_FORTRESSES_ATTACK_INFORMATION);
	w.endMessage(true);
	return w.copyMessage();
}

char* requestWriter :: base_hangar_build_ship(unsigned long fortressId, unsigned long hangarId, unsigned long fortressClassId, unsigned long long buildingTitanium)
{
	protocolWriter w;

	w.beginMessage(MT_REQUEST, REQUEST_HANGAR_BUILD_SHIP);
	w.writeValue(REQUEST_HANGAR_BUILD_SHIP_SELF_FORTRESS_ID, fortressId);
	w.writeValue(REQUEST_HANGAR_BUILD_SHIP_FORTRESS_CLASS_ID, fortressClassId);
	w.writeValue(REQUEST_HANGAR_BUILD_SHIP_HANGAR_ID, hangarId);
	w.writeValue(REQUEST_HANGAR_BUILD_SHIP_TITANIUM, buildingTitanium);
	w.endMessage(true);
	return w.copyMessage();
}

char* requestWriter :: fortress_sensors_information(unsigned long fortressId) {
	protocolWriter w;

	w.beginMessage(MT_REQUEST, REQUEST_FORTRESS_SENSORS_INFORMATION);
	w.writeValue(REQUEST_FORTRESS_SENSORS_INFORMATION_SELF_FORTRESS_ID, fortressId);
	w.endMessage(true);
	return w.copyMessage();
}

char* requestWriter :: fortress_cloaking_information(unsigned long fortressId) {
	protocolWriter w;

	w.beginMessage(MT_REQUEST, REQUEST_FORTRESS_CLOAKING_INFORMATION);
	w.writeValue(REQUEST_FORTRESS_CLOAKING_INFORMATION_SELF_FORTRESS_ID, fortressId);
	w.endMessage(true);
	return w.copyMessage();
}
