
//#include <iostream>
#include <sstream>

using namespace std;

#include "engine.h"
#include "context.h"
#include "log.h"
#include "cache_list.h"
#include "players_realms.h"
#include "fortress_skelet.h"
#include "space.h"
#include "prot_srv.h"

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

typedef id (*request_fn)(id, const std :: string&, std :: map<std :: string, std :: string>& parameters);

map<std :: string, request_fn> request_processors;

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

id request_ping(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    /* proste jenom posleme zpravu nazpet */
    protocolWriter w;
    w.beginMessage(MT_ANSWER, requestName);
    
    /* posleme vsechny parametry nazpet */
    for (std :: map<std :: string, std :: string> :: const_iterator iter = parameters.begin(); iter  != parameters.end(); iter++)
    {
        w.writeValue(iter->first, iter->second);
    }

    w.endMessage(true);

    gctx.sendToClient(cl, w.copyMessage());
    return cl;
}

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

id request_chat(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    /* zkusime poslat zpravu prijemci */
    unsigned long recpt = strtoul(parameters[REQUEST_CHAT_RECIPIENT].c_str(), NULL, 0);
     gctx.sendToClient(make_pair(recpt, 0), answerWriter :: chat(cl.first, recpt, parameters[REQUEST_CHAT_MESSAGE],
        dv_time:: now()));

    return cl;
}

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

id request_buddy(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    /* vyplnime seznam prijemcu - zatim to budou vsichni hraci */
    std :: list<std :: pair<unsigned long, std :: string>> buddies;
    std :: deque<dtIdentifier> ids;
    actx->cacheRealmsList.getObjectIds(ids);
    for (std :: deque<dtIdentifier> :: const_iterator iter = ids.begin(); iter != ids.end(); iter++)
    {
        realmClass* realm = actx->cacheRealmsList.getItem<realmClass>(*iter);
        buddies.push_back(make_pair(realm->getID(), realm->getPlayerName()));
    }

    /* posleme seznam moznych prijemcu */
    gctx.sendToClient(cl, answerWriter :: buddy(buddies));

    return cl;
}

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

void clearTradeState(realmClass* realm) 
{
	if (realm == NULL) 
	{
		return;
	}

	if (realm->tradeState.isParticipant())
	{
		dtIdentifier partnerRealmId = realm->tradeState.getEnemyID();
		realmClass* partnerRealm = actx->cacheRealmsList.getItem<realmClass>(partnerRealmId);				

		dtIdentifier ownedFortressId = realm->tradeState.getOwnedFortressID();
		dtIdentifier partnerFortressId = realm->tradeState.getEnemyFortressID();

		realm->tradeState.cancelTrade();

		gctx.sendToClient(make_pair(realm->getID(), 0), answerWriter :: receive_cancel_trade(
			ownedFortressId, partnerFortressId));

		if (partnerRealm != NULL) 
		{
			partnerRealm->tradeState.cancelTrade();
			gctx.sendToClient(make_pair(partnerRealmId, 0), answerWriter :: receive_cancel_trade(
				partnerFortressId, ownedFortressId));
		}		
	}
}

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

id login(id cl, const std::string & requestName, const std :: string& name, const std::string& password)
{
    /* zkusime se prihlasit */
    unsigned long iduser = actx->cacheRealmsList.idByLogin(name);

    if (iduser != 0)
    {
        realmClass* realm = actx->cacheRealmsList.getItem<realmClass>(iduser);

        if (password == realm->getPassword())
        {
			clearTradeState(realm);

            /* prihlasime uzivatele */ 
            if (realm->hasBan())
            {
                return make_pair(0, 0);
            }
            else
            {
                return make_pair(iduser, 0);
            }
        }
        else
        {
            // neplatne heslo
            protocolWriter w;
            w.beginMessage(MT_ANSWER, requestName);
            w.writeValue(REQUEST_LOGIN_ANSWER_FAIL_REASON, REQUEST_LOGIN_ANSWER_BAD_PASSWORD);
            w.endMessage(false);
            gctx.sendToClient(cl, w.copyMessage());
            return make_pair(0, 0);
        }
    }
    else
    {
        // neplatny login
        protocolWriter w;
        w.beginMessage(MT_ANSWER, requestName);
        w.writeValue(REQUEST_LOGIN_ANSWER_FAIL_REASON, REQUEST_LOGIN_ANSWER_BAD_LOGIN);
        w.endMessage(false);
        gctx.sendToClient(cl, w.copyMessage());
    }

    return make_pair(iduser, 0);
}

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

id request_login(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    /* pokud uz jsme prihlaseni, nedelej nic */
    if (cl.first != 0) 
    {
        protocolWriter w;
        w.beginMessage(MT_ANSWER, requestName);
        w.writeValue(REQUEST_LOGIN_ANSWER_FAIL_REASON, REQUEST_LOGIN_ANSWER_ALREADY_AUTHORIZED);
        w.endMessage(false);
        gctx.sendToClient(cl, w.copyMessage());
        return cl;
    }

    return login(cl, requestName, parameters[REQUEST_LOGIN_LOGINNAME], parameters[REQUEST_LOGIN_PASSWORD]);
}


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

std::string player_adding_result_to_string(playerAddingResult result) {
	switch (result) {
	case PAR_OK:
		return PROTOCOL_PAR_OK;
	case PAR_NAME_ALREADY_EXISTS:
		return PROTOCOL_PAR_NAME_ALREADY_EXISTS;
	case PAR_LOGIN_ALREADY_EXISTS:
		return PROTOCOL_PAR_LOGIN_ALREADY_EXISTS;
	case PAR_INTERNAL_ERROR:
		return PROTOCOL_PAR_INTERNAL_ERROR;
	}

	return "";
}

id request_admin_add_realm(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	std::string realname = parameters[REALNAME];
	std::string username = parameters[USERNAME];
	std::string password = parameters[PASSWORD];
	unsigned long shipCount = strtoul(parameters[SHIP_COUNT].c_str(), NULL, 0);
	unsigned long baseCount = strtoul(parameters[BASE_COUNT].c_str(), NULL, 0);
	double shipQuality = strtod(parameters[SHIP_QUALITY].c_str(), NULL);
	double baseQuality = strtod(parameters[BASE_QUALITY].c_str(), NULL);
	double scienceQuality = strtod(parameters[SCIENCE_QUALITY].c_str(), NULL);

	playerAddingResult result = realmClass::createNewPlayer(realname, username, password, baseCount, baseQuality, shipCount, shipQuality, scienceQuality);

    protocolWriter w;
    w.beginMessage(MT_ANSWER, REQUEST_ADMIN_ADD_REALM);
	w.writeValue(PLAYER_ADDING_RESULT, player_adding_result_to_string(result));
    w.endMessage(true);
    gctx.sendToClient(cl, w.copyMessage());
    return cl;
}

id request_register_player(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	std::string username = parameters[REQUEST_REGISTER_PLAYER_USERNAME];
	std::string password = parameters[REQUEST_REGISTER_PLAYER_PASSWORD];
	std::string realname = parameters[REQUEST_REGISTER_PLAYER_REALNAME];

	std::deque<dtIdentifier> objectIds;
	actx->cacheSpaceObjectList.getObjectIds(objectIds);

	for (std::deque<dtIdentifier>::const_iterator it = objectIds.begin(); it != objectIds.end(); ++it) {
		spacePlanetObject * planet = actx->cacheSpaceObjectList.getItem<spacePlanetObject>(*it);

		if (planet != NULL) {
			actx->startingPlanet = planet;
			break;
		}
	}
 
	playerAddingResult result = realmClass::createNewPlayer(realname, username, password, 1, 0, 1, 0, 0);	
	
	id resultCl = cl;

	if (result == PAR_OK) {
		resultCl = login(cl, REQUEST_REGISTER_PLAYER, username, password);	
	}

    return resultCl;
}

bool get_realm_ships(realmClass * realm, std::list<shipClass*> & ships) 
{
    const dtIdentifierVector& vships = realm->getShipList();
    for (dtIdentifierVector :: const_iterator iter = vships.begin(); iter != vships.end(); iter++)
    {
        fortressClass* f = actx->cacheFortressesList.getItem<fortressClass>(*iter);
        if (f!= NULL)
        {
			if (!f->isControllable()) 
			{
				continue;
			}

            if (f->getFortressType() == FT_SHIP) 
            {
                ships.push_back(dynamic_cast<shipClass*>(f));
            }
            else
            {
                errExceptionError("Base [%u] in ships list!", (unsigned long long) f->getID());
                return false;
            }
        }
        else
        {
            errExceptionError("Ship with id %u not found!", (unsigned long long) *iter);
           return false;
        }
    }

	return true;
}

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

bool get_realm_bases(realmClass * realm, std::list<baseClass*> & bases)
{
	const dtIdentifierVector& vbases = realm->getBaseList();
    for (dtIdentifierVector :: const_iterator iter = vbases.begin(); iter != vbases.end(); iter++)
    {
        fortressClass* f = actx->cacheFortressesList.getItem<fortressClass>(*iter);

        if (f!= NULL)
        {
			if (!f->isControllable()) 
			{
				continue;
			}

            if (f->getFortressType() == FT_BASE) 
            {
                bases.push_back(dynamic_cast<baseClass*>(f));
            }
            else
            {
                errExceptionError("Ship [%u] in bases list!", (unsigned long long) f->getID());
                return false;
            }
        }
        else
        {
            errExceptionError("Base with id %u not found!", (unsigned long long) *iter);
            return false;
        }
    }

	return true;
}

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

id request_update_ships(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    /* vyplnime seznam prijemcu - zatim to budou vsichni hraci */
    std :: list<shipClass*> ships;
    realmClass* realm = actx->cacheRealmsList.getItem<realmClass>(cl.first);
    if (realm != NULL)
    {
        if (!get_realm_ships(realm, ships))
		{
			return make_pair(0, 0);
		}

        /* posleme seznam moznych prijemcu */
        gctx.sendToClient(cl, answerWriter :: ships(ships));
    }
    else
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) cl.first);
        return make_pair(0, 0);
    }

    return cl;
}

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

id request_update_bases(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    /* vyplnime seznam prijemcu - zatim to budou vsichni hraci */
    std :: list<baseClass*> bases;
    realmClass* realm = actx->cacheRealmsList.getItem<realmClass>(cl.first);
    if (realm != NULL)
    {
        if (!get_realm_bases(realm, bases))
		{
			return make_pair(0, 0);
		}

        /* posleme seznam moznych prijemcu */
        gctx.sendToClient(cl, answerWriter :: bases(bases));
    }
    else
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) cl.first);
        return make_pair(0, 0);
    }

    return cl;
}

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

static std :: string make_request_fmt(const char* item, int i)
{
    std :: stringstream s;
    s << item << i;
    return s.str();
}

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

static std :: string make_request_fmt(const char* item, int i, int j)
{
    std :: stringstream s;
    s << item << i << "_" << j;
    return s.str();
}

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

id request_update_planets(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    dtIdentifier areaid = strtoul(parameters[REQUEST_PLANETS_AREAID].c_str(), NULL, 0);
    spaceObject* sp     = actx->cacheSpaceObjectList.getItem<spaceObject>(areaid);
    if (sp != NULL)
    {
        if(sp->getType() == SOT_STAR)
        {
            spaceSunObject* sun = dynamic_cast<spaceSunObject*>(sp);
            if (sun != NULL)
            {
                protocolWriter w;                
                w.beginMessage(MT_ANSWER, REQUEST_PLANETS);
                w.writeValue(REQUEST_PLANETS_AREAID, areaid);
                w.writeValue(REQUEST_PLANETS_ANSWER_COUNT, sun->subObjectCount());
                w.writeValue(REQUEST_PLANETS_ANSWER_SUN_OBJ_RADIUS, sun->getObjectRadius());
                w.writeValue(REQUEST_PLANETS_ANSWER_SUN_ARE_RADIUS, sun->getAreaRadius());
                w.writeValue(REQUEST_PLANETS_ANSWER_SUN_NAME, sun->getName());
                w.writeValue(REQUEST_PLANETS_ANSWER_SUN_WEIGHT, sun->getWeight());
                w.writeValue(REQUEST_PLANETS_ANSWER_SUN_TYPE, (unsigned long)sun->getSunType());
                w.writeValue(REQUEST_PLANETS_ANSWER_GAMETIME, wt2gt(dv_time :: now()));

                /* proiterujeme planety */
                int i = 1;
                for (spaceSunObject :: dtIdentifierConstIterator iter = sun->subObjectsBegin();
                    iter != sun->subObjectsEnd(); iter++)
                {
                    // posleme udaje o planete
                    spacePlanetObject* pl = actx->cacheSpaceObjectList.getItem<spacePlanetObject>(*iter);

                    if (pl != NULL)
                    {
                        w.writeValue(make_request_fmt(REQUEST_PLANETS_ANSWER_PLANETID, i),  pl->getID());
                        w.writeValue(make_request_fmt(REQUEST_PLANETS_ANSWER_PIVOTX, i),    (/*unsigned*/ long long)sun->getPosition().x); //BUG FIX Martin Ruzicka...unsigned shoulnd be there probably!!!
                        w.writeValue(make_request_fmt(REQUEST_PLANETS_ANSWER_PIVOTY, i),    (/*unsigned*/ long long)sun->getPosition().y); //BUG FIX Martin Ruzicka...unsigned shoulnd be there probably!!!
                        w.writeValue(make_request_fmt(REQUEST_PLANETS_ANSWER_SPEED, i),     (unsigned long long)pl->getAngularVelocity());
                        w.writeValue(make_request_fmt(REQUEST_PLANETS_ANSWER_RADIUS, i),    (unsigned long long)pl->getDistanceFromParentObject());
                        w.writeValue(make_request_fmt(REQUEST_PLANETS_ANSWER_SIZE, i),      (unsigned long long)pl->getObjectRadius());
                        w.writeValue(make_request_fmt(REQUEST_PLANETS_ANSWER_ANGLE, i),     (unsigned long long)pl->getAngle());
                        w.writeValue(make_request_fmt(REQUEST_PLANETS_ANSWER_WEIGHT, i),    pl->getWeight());
                        w.writeValue(make_request_fmt(REQUEST_PLANETS_ANSWER_YEARP, i),     pl->getYearPeriod());
                        w.writeValue(make_request_fmt(REQUEST_PLANETS_ANSWER_DAYP, i),      pl->getDayPeriod());
                        w.writeValue(make_request_fmt(REQUEST_PLANETS_ANSWER_TYPE, i),      (unsigned long)pl->getPlanetType());
                        w.writeValue(make_request_fmt(REQUEST_PLANETS_ANSWER_DAYTEMP, i),   pl->getDayTemperature());
                        w.writeValue(make_request_fmt(REQUEST_PLANETS_ANSWER_NIGHTTEMP, i), pl->getNightTemperature());
                        w.writeValue(make_request_fmt(REQUEST_PLANETS_ANSWER_SEA, i),       pl->getSea());
                        w.writeValue(make_request_fmt(REQUEST_PLANETS_ANSWER_HEWA, i),      pl->getHeavyWaterSource());
                        w.writeValue(make_request_fmt(REQUEST_PLANETS_ANSWER_ZISO, i),      pl->getZirconiumSource());
                        w.writeValue(make_request_fmt(REQUEST_PLANETS_ANSWER_ILSO, i),      pl->getIlmeniteSource());
                        w.writeValue(make_request_fmt(REQUEST_PLANETS_ANSWER_NAME, i),      pl->getName());
                        w.writeValue(make_request_fmt(REQUEST_PLANETS_ANSWER_TEXTURE, i),   pl->getTexture());

                        std :: list<dtIdentifier> targets;
                        pl->getAimedTargets(targets);
                        w.writeValue(make_request_fmt(REQUEST_PLANETS_ANSWER_TARGET_CNT, i), (unsigned long long)targets.size());
                        int j = 1;
                        for (std :: list<dtIdentifier> :: const_iterator iter2 = targets.begin(); iter2 != targets.end(); iter2++)
                        {
                            fortressClass* ft = actx->cacheFortressesList.getItem<fortressClass>(*iter2);
                            if (ft != NULL)
                            {
                                if (ft->getFortressType() == FT_BASE)
                                {
                                    baseClass* bc = dynamic_cast<baseClass*>(ft);        
                                    w.writeValue(make_request_fmt(REQUEST_PLANETS_ANSWER_TARGET, i, j), bc->getFortressSpaceObjectHolder()->getParentSpaceObject());
                                    w.writeValue(make_request_fmt(REQUEST_PLANETS_ANSWER_TARGET_IS_SHIP, i, j), false);
                                }
                                else
                                {
                                    w.writeValue(make_request_fmt(REQUEST_PLANETS_ANSWER_TARGET, i, j), (unsigned long)(*iter2));
                                    w.writeValue(make_request_fmt(REQUEST_PLANETS_ANSWER_TARGET_IS_SHIP, i, j), true);
                                }
                            }
                            else
                            {
                                errLogicalError("Cannot access fortress %u !", (unsigned long long)(*iter2));
                            }
                            j++;
                        }
                    }
                    else
                    {
                        /* jedna se o spatny typ objektu */
                        errExceptionError("Space object [%u] is not a planet!", (unsigned long long)*iter);
                        gctx.sendToClient(cl, answerWriter :: planets_ie(areaid));  
                        return cl;
                    }
                    i++;
                }
               
                w.endMessage(true);
                gctx.sendToClient(cl, w.copyMessage());
            }
            else
            {
                /* jedna se o spatny typ objektu */
                errExceptionError("Space object [%u] marked as sun, but it is not a sun!", (unsigned long long)areaid);
                gctx.sendToClient(cl, answerWriter :: planets_ie(areaid));  
            }
        }
        else
        {
            /* posleme zpravu o chybe, ze dany objekt neni hvezda */
            gctx.sendToClient(cl, answerWriter :: planets_notstar(areaid));      
        }
    }
    else
    {
        /* posleme zpravu o chybe, ze dany objekt neexistuje */
        gctx.sendToClient(cl, answerWriter :: planets_nonexisting(areaid));       
    }

    return cl;
}

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

static void write_lr_ship(protocolWriter& w, int index, shipClass* cl)
{
    vector_dist_t pos = cl->MovementGetShipPosition();
    std :: stringstream ss;

    ss << REQUEST_SHIPSINAREA_ANSWER_LR_POSX << index;
    w.writeValue(ss.str(), (long long)pos.x);
    ss.str("");

    ss << REQUEST_SHIPSINAREA_ANSWER_LR_POSY << index;
    w.writeValue(ss.str(), (long long)pos.y);
    ss.str("");

    ss << REQUEST_SHIPSINAREA_ANSWER_LR_SHIPID << index;
    w.writeValue(ss.str(), cl->getID());
    ss.str("");
}

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

static void write_hr_ship(protocolWriter& w, int index, shipClass* cl)
{
    vector_dist_t pos = cl->MovementGetShipPosition();
    std :: stringstream ss;

    ss << REQUEST_SHIPSINAREA_ANSWER_HR_POSX << index;
    w.writeValue(ss.str(), pos.x);
    ss.str("");

    ss << REQUEST_SHIPSINAREA_ANSWER_HR_POSY << index;
    w.writeValue(ss.str(), pos.y);
    ss.str("");

    ss << REQUEST_SHIPSINAREA_ANSWER_HR_SHIPID << index;
    w.writeValue(ss.str(), cl->getID());
    ss.str("");

    ss << REQUEST_SHIPSINAREA_ANSWER_HR_SHIPNAME << index;
    w.writeValue(ss.str(), cl->getFortressName());
    ss.str("");

    ss << REQUEST_SHIPSINAREA_ANSWER_HR_SPEED << index;
    w.writeValue(ss.str(), cl->MovementGetCurrentSpeed());
    ss.str("");

    ss << REQUEST_SHIPSINAREA_ANSWER_HR_ACCELERATION << index;
    w.writeValue(ss.str(), cl->MovementGetCurrentAcceleration());
    ss.str("");

    ss << REQUEST_SHIPSINAREA_ANSWER_HR_COURSEX << index;
    w.writeValue(ss.str(), cl->MovementGetCourse().x);
    ss.str("");

    ss << REQUEST_SHIPSINAREA_ANSWER_HR_COURSEY << index;
    w.writeValue(ss.str(), cl->MovementGetCourse().y);
    ss.str("");

    ss << REQUEST_SHIPSINAREA_ANSWER_HR_SHIPCLASS << index;
    w.writeValue(ss.str(), cl->getFortressClassID());
    ss.str("");

    ss << REQUEST_SHIPSINAREA_ANSWER_HR_PLAYERNAME << index;
    w.writeValue(ss.str(), cl->getFortressRealm()->getPlayerName());
    ss.str("");

    if (cl->MovementIsOrbiting())
    {
        ss << REQUEST_SHIPSINAREA_ANSWER_HR_ORBITING << index;
        w.writeValue(ss.str(), (unsigned long)1);
        ss.str("");

        dist_t velocity;
        cl->MovementGetAngularSpeed(velocity);
        ss << REQUEST_SHIPSINAREA_ANSWER_HR_ORBITING_VELOCITY << index;
        w.writeValue(ss.str(), velocity);
        ss.str("");
        
        vector_dist_t pivot;
        cl->MovementGetOrbitingPivot(pivot);

        ss << REQUEST_SHIPSINAREA_ANSWER_HR_ORBITING_PIVOT_X << index;
        w.writeValue(ss.str(), pivot.x);
        ss.str("");

        ss << REQUEST_SHIPSINAREA_ANSWER_HR_ORBITING_PIVOT_Y << index;
        w.writeValue(ss.str(), pivot.y);
        ss.str("");
    } 
    else
    {
        ss << REQUEST_SHIPSINAREA_ANSWER_HR_ORBITING << index;
        w.writeValue(ss.str(), (unsigned long)0);
        ss.str("");
    }

    ss << REQUEST_SHIPSINAREA_ANSWER_HR_QUARRYING << index;
    w.writeValue(ss.str(), (unsigned long)(cl->isSomethingQuarrying() ? 1 : 0));
    ss.str("");

    if (cl->getWeaponsTargetID() != NOT_VALID_ID)
    {
        fortressClass* ft = actx->cacheFortressesList.getItem<fortressClass>(cl->getWeaponsTargetID());
        if (ft != NULL)
        {
            if (ft->getFortressType() == FT_BASE)
            {
                baseClass* bc = dynamic_cast<baseClass*>(ft);   

                ss << REQUEST_SHIPSINAREA_ANSWER_HR_TARGET << index;
                w.writeValue(ss.str(), (unsigned long)bc->getFortressSpaceObjectHolder()->getParentSpaceObject());
                ss.str("");

                ss << REQUEST_SHIPSINAREA_ANSWER_HR_TARGET_IS_SHIP << index;
                w.writeValue(ss.str(), false);
                ss.str("");
            }
            else
            {
                ss << REQUEST_SHIPSINAREA_ANSWER_HR_TARGET << index;
                w.writeValue(ss.str(), (unsigned long)ft->getID());
                ss.str("");

                ss << REQUEST_SHIPSINAREA_ANSWER_HR_TARGET_IS_SHIP << index;
                w.writeValue(ss.str(), true);
                ss.str("");
            }
        }
        else
        {
            errLogicalError("Cannot access fortress %u !", (unsigned long long)(cl->getWeaponsTargetID()));
        }
    }


    ss << REQUEST_SHIPSINAREA_ANSWER_HR_INBASE << index;
    w.writeValue(ss.str(), cl->MovementIsDockedInBase());
    ss.str("");

    ss << REQUEST_SHIPSINAREA_ANSWER_HR_INWARP << index;
    w.writeValue(ss.str(), cl->MovementIsInWarp());
    ss.str("");

    ss << REQUEST_SHIPSINAREA_ANSWER_HR_INNORMALSPACE << index;
    w.writeValue(ss.str(), cl->MovementIsInNormalSpace());
    ss.str("");


    if (cl->MovementIsInWarp())
    {
        vector_dist_t pivot = cl->MovementEstimateWarpPosition();   

        ss << REQUEST_SHIPSINAREA_ANSWER_HR_WARP_PIVOT_X << index;
        w.writeValue(ss.str(), pivot.x);
        ss.str("");

        ss << REQUEST_SHIPSINAREA_ANSWER_HR_WARP_PIVOT_Y << index;
        w.writeValue(ss.str(), pivot.y);
        ss.str("");
    }

    if (cl->MovementIsDockedInBase())
    {
        spaceFortressObject* fobj = actx->cacheSpaceObjectList.getItem<spaceFortressObject>(cl->MovementGetSpaceObjectActuallyIn());
        if (fobj != NULL)
        {
            vector_dist_t pivot = fobj->getAbsolutePosition();   

            ss << REQUEST_SHIPSINAREA_ANSWER_HR_BASE_PIVOT_X << index;
            w.writeValue(ss.str(), pivot.x);
            ss.str("");

            ss << REQUEST_SHIPSINAREA_ANSWER_HR_BASE_PIVOT_Y << index;
            w.writeValue(ss.str(), pivot.y);
            ss.str("");
        }
        else
        {
            errLogicalError("Cannot find space fortress object %u for ship %u !", (unsigned long long)cl->getID(),
                cl->MovementGetSpaceObjectActuallyIn());
        }
    }
}

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

static void write_own_ship(protocolWriter& w, int index, shipClass* cl)
{
    vector_dist_t pos = cl->MovementGetShipPosition();
    std :: stringstream ss;

    ss << REQUEST_SHIPSINAREA_ANSWER_OWN_POSX << index;
    w.writeValue(ss.str(), (long long)(pos.x) );
    ss.str("");

    ss << REQUEST_SHIPSINAREA_ANSWER_OWN_POSY << index;
    w.writeValue(ss.str(), (long long)pos.y);
    ss.str("");

    ss << REQUEST_SHIPSINAREA_ANSWER_OWN_SHIPID << index;
    w.writeValue(ss.str(), cl->getID());
    ss.str("");

    ss << REQUEST_SHIPSINAREA_ANSWER_OWN_SHIPNAME << index;
    w.writeValue(ss.str(), cl->getFortressName());
    ss.str("");

    ss << REQUEST_SHIPSINAREA_ANSWER_OWN_SPEED << index;
    w.writeValue(ss.str(), cl->MovementGetCurrentSpeed());
    ss.str("");

    ss << REQUEST_SHIPSINAREA_ANSWER_OWN_ACCELERATION << index;
    w.writeValue(ss.str(), cl->MovementGetCurrentAcceleration());
    ss.str("");

    ss << REQUEST_SHIPSINAREA_ANSWER_OWN_COURSEX << index;
    w.writeValue(ss.str(), cl->MovementGetCourse().x);
    ss.str("");

    ss << REQUEST_SHIPSINAREA_ANSWER_OWN_COURSEY << index;
    w.writeValue(ss.str(), cl->MovementGetCourse().y);
    ss.str("");

    ss << REQUEST_SHIPSINAREA_ANSWER_OWN_SHIPCLASS << index;
    w.writeValue(ss.str(), cl->getFortressClassID());
    ss.str("");

    ss << REQUEST_SHIPSINAREA_ANSWER_OWN_PLAYERNAME << index;
    w.writeValue(ss.str(), cl->getFortressRealm()->getPlayerName());
    ss.str("");

    ss << REQUEST_SHIPSINAREA_ANSWER_OWN_ESTIMATION_DISTANCE << index;
    w.writeValue(ss.str(), (long long)cl->MovementEstimationDistance());
    ss.str("");

    ss << REQUEST_SHIPSINAREA_ANSWER_OWN_STRUCT_INT_PERC << index;
    w.writeValue(ss.str(), (unsigned long)cl->getStructuralIntegrityPerc());
    ss.str("");

    ss << REQUEST_SHIPSINAREA_ANSWER_OWN_SHIELD_PERC << index;
    w.writeValue(ss.str(), (unsigned long)cl->getShieldPerc());
    ss.str("");

    if (cl->MovementIsOrbiting())
    {
        ss << REQUEST_SHIPSINAREA_ANSWER_OWN_ORBITING << index;
        w.writeValue(ss.str(), (unsigned long)1);
        ss.str("");

        dist_t velocity;
        cl->MovementGetAngularSpeed(velocity);
        ss << REQUEST_SHIPSINAREA_ANSWER_OWN_ORBITING_VELOCITY << index;
        w.writeValue(ss.str(), (long long)velocity);
        ss.str("");
        
        vector_dist_t pivot;
        cl->MovementGetOrbitingPivot(pivot);

        ss << REQUEST_SHIPSINAREA_ANSWER_OWN_ORBITING_PIVOT_X << index;
        w.writeValue(ss.str(), (long long)pivot.x);
        ss.str("");

        ss << REQUEST_SHIPSINAREA_ANSWER_OWN_ORBITING_PIVOT_Y << index;
        w.writeValue(ss.str(), (long long)pivot.y);
        ss.str("");
    } 
    else
    {
        ss << REQUEST_SHIPSINAREA_ANSWER_OWN_ORBITING << index;
        w.writeValue(ss.str(), (unsigned long)0);
        ss.str("");
    }

    ss << REQUEST_SHIPSINAREA_ANSWER_OWN_QUARRYING << index;
    w.writeValue(ss.str(), (unsigned long)(cl->isSomethingQuarrying() ? 1 : 0));
    ss.str("");

    if (cl->getWeaponsTargetID() != NOT_VALID_ID)
    {
        fortressClass* ft = actx->cacheFortressesList.getItem<fortressClass>(cl->getWeaponsTargetID());
        if (ft != NULL)
        {
            if (ft->getFortressType() == FT_BASE)
            {
                baseClass* bc = dynamic_cast<baseClass*>(ft);   

                ss << REQUEST_SHIPSINAREA_ANSWER_OWN_TARGET << index;
                w.writeValue(ss.str(), (unsigned long)bc->getFortressSpaceObjectHolder()->getParentSpaceObject());
                ss.str("");

                ss << REQUEST_SHIPSINAREA_ANSWER_OWN_TARGET_IS_SHIP << index;
                w.writeValue(ss.str(), false);
                ss.str("");
            }
            else
            {
                ss << REQUEST_SHIPSINAREA_ANSWER_OWN_TARGET << index;
                w.writeValue(ss.str(), (unsigned long)ft->getID());
                ss.str("");

                ss << REQUEST_SHIPSINAREA_ANSWER_OWN_TARGET_IS_SHIP << index;
                w.writeValue(ss.str(), true);
                ss.str("");
            }
        }
        else
        {
            errLogicalError("Cannot access fortress %u !", (unsigned long long)(cl->getWeaponsTargetID()));
        }
    }

    ss << REQUEST_SHIPSINAREA_ANSWER_OWN_INBASE << index;
    w.writeValue(ss.str(), cl->MovementIsDockedInBase());
    ss.str("");

    ss << REQUEST_SHIPSINAREA_ANSWER_OWN_INWARP << index;
    w.writeValue(ss.str(), cl->MovementIsInWarp());
    ss.str("");

    ss << REQUEST_SHIPSINAREA_ANSWER_OWN_INNORMALSPACE << index;
    w.writeValue(ss.str(), cl->MovementIsInNormalSpace());
    ss.str("");

    if (cl->MovementIsInWarp())
    {
        vector_dist_t pivot = cl->MovementEstimateWarpPosition();   

        ss << REQUEST_SHIPSINAREA_ANSWER_OWN_WARP_PIVOT_X << index;
        w.writeValue(ss.str(), (long long)pivot.x);
        ss.str("");

        ss << REQUEST_SHIPSINAREA_ANSWER_OWN_WARP_PIVOT_Y << index;
        w.writeValue(ss.str(), (long long)pivot.y);
        ss.str("");
    }

    if (cl->MovementIsDockedInBase())
    {
        spaceFortressObject* fobj = actx->cacheSpaceObjectList.getItem<spaceFortressObject>(cl->MovementGetSpaceObjectActuallyIn());
        if (fobj != NULL)
        {
            vector_dist_t pivot = fobj->getAbsolutePosition();   

            ss << REQUEST_SHIPSINAREA_ANSWER_OWN_BASE_PIVOT_X << index;
            w.writeValue(ss.str(), (long long)pivot.x);
            ss.str("");

            ss << REQUEST_SHIPSINAREA_ANSWER_OWN_BASE_PIVOT_Y << index;
            w.writeValue(ss.str(), (long long)pivot.y);
            ss.str("");
        }
        else
        {
            errLogicalError("Cannot find space fortress object %u for ship %u !", (unsigned long long)cl->getID(),
                cl->MovementGetSpaceObjectActuallyIn());
        }
    }
}

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

static void write_ns_lr_ship(protocolWriter& w, int index, shipClass* cl, const dist_t distance)
{
    vector_dist_t pos = cl->MovementGetShipPosition();
    std :: stringstream ss;

    ss << REQUEST_NAVIGATION_STATUS_ANSWER_LR_POSX << index;
    w.writeValue(ss.str(), (long long)pos.x);
    ss.str("");

    ss << REQUEST_NAVIGATION_STATUS_ANSWER_LR_POSY << index;
    w.writeValue(ss.str(), (long long)pos.y);
    ss.str("");

    ss << REQUEST_NAVIGATION_STATUS_ANSWER_LR_SHIPID << index;
    w.writeValue(ss.str(), cl->getID());
    ss.str("");

    ss << REQUEST_NAVIGATION_STATUS_ANSWER_LR_DISTANCE << index;
    w.writeValue(ss.str(), distance);
    ss.str("");
}

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

static void write_ns_hr_ship(protocolWriter& w, int index, shipClass* cl, const dist_t distance)
{
    vector_dist_t pos = cl->MovementGetShipPosition();
    std :: stringstream ss;

    ss << REQUEST_NAVIGATION_STATUS_ANSWER_HR_POSX << index;
    w.writeValue(ss.str(), (long long)pos.x);
    ss.str("");

    ss << REQUEST_NAVIGATION_STATUS_ANSWER_HR_POSY << index;
    w.writeValue(ss.str(), (long long)pos.y);
    ss.str("");

    ss << REQUEST_NAVIGATION_STATUS_ANSWER_HR_SHIPID << index;
    w.writeValue(ss.str(), cl->getID());
    ss.str("");

    ss << REQUEST_NAVIGATION_STATUS_ANSWER_HR_SHIPNAME << index;
    w.writeValue(ss.str(), cl->getFortressName());
    ss.str("");

    ss << REQUEST_NAVIGATION_STATUS_ANSWER_HR_SPEED << index;
    w.writeValue(ss.str(), cl->MovementGetCurrentSpeed());
    ss.str("");

    ss << REQUEST_NAVIGATION_STATUS_ANSWER_HR_ACCELERATION << index;
    w.writeValue(ss.str(), cl->MovementGetCurrentAcceleration());
    ss.str("");

    ss << REQUEST_NAVIGATION_STATUS_ANSWER_HR_COURSEX << index;
    w.writeValue(ss.str(), cl->MovementGetCourse().x);
    ss.str("");

    ss << REQUEST_NAVIGATION_STATUS_ANSWER_HR_COURSEY << index;
    w.writeValue(ss.str(), cl->MovementGetCourse().y);
    ss.str("");

    ss << REQUEST_NAVIGATION_STATUS_ANSWER_HR_SHIPCLASS << index;
    w.writeValue(ss.str(), cl->getFortressClassID());
    ss.str("");

    ss << REQUEST_NAVIGATION_STATUS_ANSWER_HR_PLAYERNAME << index;
    w.writeValue(ss.str(), cl->getFortressRealm()->getPlayerName());
    ss.str("");

    ss << REQUEST_NAVIGATION_STATUS_ANSWER_HR_DISTANCE << index;
    w.writeValue(ss.str(), (long long)distance);
    ss.str("");
}

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

id request_update_shipsinarea(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    dtIdentifier shipid = strtoul(parameters[REQUEST_SHIPSINAREA_SHIPID].c_str(), NULL, 0);
    shipClass* ship = actx->cacheFortressesList.getItem<shipClass>(shipid);

    /* pokud lod neexistuje, vrat chybu */
    if (ship == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: shipsinarea_notexisting(shipid));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (ship->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: shipsinarea_notown(shipid));
        return cl;
    }

    /* lod existuje a hraci patri */
    if (ship->MovementIsInWarp())
    {
        gctx.sendToClient(cl, answerWriter :: shipsinarea_inwarp(shipid));
        return cl;
    }

    vector_dist_t position = ship->MovementGetShipPosition();

    /* projedeme vsechny lode */ 
    spaceIndexItem* itm = actx->spaceObjectIndex.getNearestItem(position);
    if (itm == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: shipsinarea_ie(shipid));
        return cl;
    }

    /* projedeme vsechny lode */
    std :: list<shipClass*> hi_ships;
    std :: list<shipClass*> lo_ships;
    std :: list<shipClass*> own_ships;

    dtIdentifierList shipsInRangeForScanning;
    dtIdentifierList shipsInRangeForObserving;
    dtIdentifierList basesInRangeForScanning;
    dtIdentifierList basesInRangeForObserving;

    ship->getFortressesInRangeForScanning(&basesInRangeForScanning, &shipsInRangeForScanning);
    ship->getFortressesInRangeForObserving(&basesInRangeForObserving, &shipsInRangeForObserving);

    std :: set<dtIdentifier> lShipsIds;
    std :: set<dtIdentifier> hShipsIds;
    std :: set<dtIdentifier> oShipsIds;

    lShipsIds.insert(shipsInRangeForObserving.begin(), shipsInRangeForObserving.end());
    hShipsIds.insert(shipsInRangeForScanning.begin(), shipsInRangeForScanning.end());

    // smazeme vsechny lode z lShips, ktere uz jsou v hShips
    for (std :: set<dtIdentifier> :: const_iterator iter = hShipsIds.begin(); iter != hShipsIds.end(); iter++)
    {
        lShipsIds.erase(*iter);
    }

    // najdeme vlastni lode
    dtIdentifierList starShips;
    actx->spaceObjectIndex.getShipsInArea(itm->spaceSystemIndex_, starShips);

    // pridame vlastni lode do seznamu vlastnich lodi
    for (dtIdentifierList :: const_iterator iter = starShips.begin(); iter != starShips.end(); iter++)
    {
        shipClass* otherShip = actx->cacheFortressesList.getItem<shipClass>(*iter);
        if (otherShip != NULL)
        {
            if (otherShip->getFortressRealmID() == cl.first)
            {
                oShipsIds.insert(*iter);
            }
        }
        else
        {
            errLogicalError("Ship %u does not exist!", (unsigned long long)(*iter));
        }
    }

    for (std :: set<dtIdentifier> :: const_iterator iter = lShipsIds.begin(); iter != lShipsIds.end(); iter++)
    {
        shipClass* otherShip = actx->cacheFortressesList.getItem<shipClass>(*iter);
        if (otherShip != NULL)
        {
            if (otherShip->getFortressRealmID() == cl.first)
            {
                oShipsIds.insert(*iter);
            }
        }
        else
        {
            errLogicalError("Ship %u does not exist!", (unsigned long long)(*iter));
        }
    }

    for (std :: set<dtIdentifier> :: const_iterator iter = hShipsIds.begin(); iter != hShipsIds.end(); iter++)
    {
        shipClass* otherShip = actx->cacheFortressesList.getItem<shipClass>(*iter);
        if (otherShip != NULL)
        {
            if (otherShip->getFortressRealmID() == cl.first)
            {
                oShipsIds.insert(*iter);
            }
        }
        else
        {
            errLogicalError("Ship %u does not exist!", (unsigned long long)(*iter));
        }
    }

    // smazeme vlastni lode z lShips a hShips
    for (std :: set<dtIdentifier> :: const_iterator iter = oShipsIds.begin(); iter != oShipsIds.end(); iter++)
    {
        lShipsIds.erase(*iter);
        hShipsIds.erase(*iter);
    }

    // naplnime lo_ships
    for (std :: set<dtIdentifier> :: const_iterator iter = lShipsIds.begin(); iter != lShipsIds.end(); iter++)
    {
        shipClass* otherShip = actx->cacheFortressesList.getItem<shipClass>(*iter);
        if (otherShip != NULL)
        {
            lo_ships.push_back(otherShip);
        }
        else
        {
            errLogicalError("Ship %u does not exist!", (unsigned long long)(*iter));
        } 
    }

    // naplnime hi_ships
    for (std :: set<dtIdentifier> :: const_iterator iter = hShipsIds.begin(); iter != hShipsIds.end(); iter++)
    {
        shipClass* otherShip = actx->cacheFortressesList.getItem<shipClass>(*iter);
        if (otherShip != NULL)
        {
            hi_ships.push_back(otherShip);
        }
        else
        {
            errLogicalError("Ship %u does not exist!", (unsigned long long)(*iter));
        } 
    }

    // naplnime own_ships
    for (std :: set<dtIdentifier> :: const_iterator iter = oShipsIds.begin(); iter != oShipsIds.end(); iter++)
    {
        shipClass* otherShip = actx->cacheFortressesList.getItem<shipClass>(*iter);
        if (otherShip != NULL)
        {
            own_ships.push_back(otherShip);
        }
        else
        {
            errLogicalError("Ship %u does not exist!", (unsigned long long)(*iter));
        } 
    }

    protocolWriter w;
    w.beginMessage(MT_ANSWER, REQUEST_SHIPSINAREA);

    int cntr = 1;
    w.writeValue(REQUEST_SHIPSINAREA_ANSWER_LR_COUNT, (unsigned long long)lo_ships.size());
    for (std :: list<shipClass*> :: iterator iter = lo_ships.begin(); iter != lo_ships.end(); iter++)
    {
        write_lr_ship(w, cntr, *iter);
        cntr++;
    }

    cntr = 1;
    w.writeValue(REQUEST_SHIPSINAREA_ANSWER_HR_COUNT, (unsigned long long)hi_ships.size());
    for (std :: list<shipClass*> :: iterator iter = hi_ships.begin(); iter != hi_ships.end(); iter++)
    {
        write_hr_ship(w, cntr, *iter);
        cntr++;
    }

    cntr = 1;
    w.writeValue(REQUEST_SHIPSINAREA_ANSWER_OWN_COUNT, (unsigned long long)own_ships.size());
    for (std :: list<shipClass*> :: iterator iter = own_ships.begin(); iter != own_ships.end(); iter++)
    {
        write_own_ship(w, cntr, *iter);
        cntr++;
    }

    w.endMessage(true);
    gctx.sendToClient(cl, w.copyMessage());

    stopReadOnlyRequest();

    return cl;
}

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

id request_navigation_stop(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    dtIdentifier shipid = strtoul(parameters[REQUEST_NAVIGATION_SHIPID].c_str(), NULL, 0);
    shipClass* ship = actx->cacheFortressesList.getItem<shipClass>(shipid);

    /* pokud lod neexistuje, vrat chybu */
    if (ship == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_not_exists(shipid, REQUEST_NAVIGATION_STOP));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (ship->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_not_owned(shipid, REQUEST_NAVIGATION_STOP));
        return cl;
    }

	/* pokud lod neni kontrolovatelna, vrat chybu */
	if (!ship->isControllable()) 
	{
		 gctx.sendToClient(cl, answerWriter :: navigation_ship_not_controllable(shipid, REQUEST_NAVIGATION_STOP));
	}

    /* lod existuje a hraci patri, ale je ve warpu */
    if (ship->MovementIsInWarp())
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_in_warp(shipid, REQUEST_NAVIGATION_STOP));
        return cl;
    }

    ship->MovementTargetStopShip();
    ship->MovementUpdateShipMovementStatus();
    ship->MovementNotifyOtherPlayers();

    /* posleme zpravu o uspechu */
    gctx.sendToClient(cl, answerWriter :: navigation_OK(REQUEST_NAVIGATION_STOP, shipid));

    return cl;
}

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

id request_navigation_warp(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    dtIdentifier shipid = strtoul(parameters[REQUEST_NAVIGATION_SHIPID].c_str(), NULL, 0);
    shipClass* ship = actx->cacheFortressesList.getItem<shipClass>(shipid);

    /* pokud lod neexistuje, vrat chybu */
    if (ship == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_not_exists(shipid, REQUEST_NAVIGATION_WARP));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (ship->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_not_owned(shipid, REQUEST_NAVIGATION_WARP));
        return cl;
    }

	/* pokud lod neni kontrolovatelna, vrat chybu */
	if (!ship->isControllable()) 
	{
		 gctx.sendToClient(cl, answerWriter :: navigation_ship_not_controllable(shipid, REQUEST_NAVIGATION_WARP));
	}

    /* lod existuje a hraci patri, ale je ve warpu */
    if (ship->MovementIsInWarp())
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_in_warp(shipid, REQUEST_NAVIGATION_WARP));
        return cl;
    }

    /* pokud lod pristala na zaklade, nelze spustit warp pohon */
    if (ship->MovementIsDockedInBase())
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_docked_in_base(shipid, REQUEST_NAVIGATION_WARP));
        return cl;
    }

    ship->MovementUpdateShipMovementStatus();
    ship->MovementNotifyOtherPlayers();
    if (ship->MovementWarpTravel(vector_dist_t((dist_t)_atoi64(parameters[REQUEST_NAVIGATION_POSITIONX].c_str()), 
        (dist_t)_atoi64(parameters[REQUEST_NAVIGATION_POSITIONY].c_str()))))
    {   
        /* posleme zpravu o uspechu */
        gctx.sendToClient(cl, answerWriter :: navigation_OK(REQUEST_NAVIGATION_WARP, shipid));
    }
    else
        gctx.sendToClient(cl, answerWriter :: navigation_FAIL(REQUEST_NAVIGATION_WARP, shipid));
    return cl;
}

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

id request_navigation_move_to(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    dtIdentifier shipid = strtoul(parameters[REQUEST_NAVIGATION_SHIPID].c_str(), NULL, 0);
    shipClass* ship = actx->cacheFortressesList.getItem<shipClass>(shipid);

    /* pokud lod neexistuje, vrat chybu */
    if (ship == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_not_exists(shipid, REQUEST_NAVIGATION_MOVE_TO));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (ship->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_not_owned(shipid, REQUEST_NAVIGATION_MOVE_TO));
        return cl;
    }

	/* pokud lod neni kontrolovatelna, vrat chybu */
	if (!ship->isControllable()) 
	{
		 gctx.sendToClient(cl, answerWriter :: navigation_ship_not_controllable(shipid, REQUEST_NAVIGATION_MOVE_TO));
	}

    /* lod existuje a hraci patri, ale je ve warpu */
    if (ship->MovementIsInWarp())
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_in_warp(shipid, REQUEST_NAVIGATION_MOVE_TO));
        return cl;
    }

    /* pokud lod pristala na zaklade, nelze spustit warp pohon */
    if (ship->MovementIsDockedInBase())
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_docked_in_base(shipid, REQUEST_NAVIGATION_MOVE_TO));
        return cl;
    }

    ship->MovementSetEngineIgnitionLimit(atof(parameters[REQUEST_NAVIGATION_ENGINELIMIT].c_str()));
    ship->MovementTargetMoveTo((dist_t)_atoi64(parameters[REQUEST_NAVIGATION_POSITIONX].c_str()), 
        (dist_t)_atoi64(parameters[REQUEST_NAVIGATION_POSITIONY].c_str()));  
    //ship->MovementUpdateShipMovementStatus();
    /* posleme zpravu o uspechu */
    gctx.sendToClient(cl, answerWriter :: navigation_OK(REQUEST_NAVIGATION_MOVE_TO, shipid));
    ship->MovementNotifyOtherPlayers();

    return cl;
}

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

id request_navigation_dock_down(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    dtIdentifier shipid = strtoul(parameters[REQUEST_NAVIGATION_DOCK_DOWN_SHIP_ID].c_str(), NULL, 0);
    shipClass* ship = actx->cacheFortressesList.getItem<shipClass>(shipid);

    /* pokud lod neexistuje, vrat chybu */
    if (ship == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_not_exists(shipid, REQUEST_NAVIGATION_DOCK_DOWN));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (ship->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_not_owned(shipid, REQUEST_NAVIGATION_DOCK_DOWN));
        return cl;
    }

	/* pokud lod neni kontrolovatelna, vrat chybu */
	if (!ship->isControllable()) 
	{
		 gctx.sendToClient(cl, answerWriter :: navigation_ship_not_controllable(shipid, REQUEST_NAVIGATION_DOCK_DOWN));
	}

    /* lod existuje a hraci patri, ale je ve warpu */
    if (ship->MovementIsInWarp())
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_in_warp(shipid, REQUEST_NAVIGATION_DOCK_DOWN));
        return cl;
    }

    dtIdentifier baseid = strtoul(parameters[REQUEST_NAVIGATION_DOCK_DOWN_BASE_ID].c_str(), NULL, 0);
    baseClass* base = actx->cacheFortressesList.getItem<baseClass>(baseid);

	if (base == NULL) {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_target_not_exits(shipid, REQUEST_NAVIGATION_DOCK_DOWN));  
        return cl;
	}

	dockingResult result = ship->dockDown(base);

	gctx.sendToClient(cl, answerWriter :: navigation_dock_down(shipid, baseid, result));  

    return cl;
}

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

id request_navigation_unbound(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    dtIdentifier shipid = strtoul(parameters[REQUEST_NAVIGATION_UNBOUND_SHIP_ID].c_str(), NULL, 0);
    shipClass* ship = actx->cacheFortressesList.getItem<shipClass>(shipid);

    /* pokud lod neexistuje, vrat chybu */
    if (ship == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_not_exists(shipid, REQUEST_NAVIGATION_UNBOUND));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (ship->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_not_owned(shipid, REQUEST_NAVIGATION_UNBOUND));
        return cl;
    }

	/* pokud lod neni kontrolovatelna, vrat chybu */
	if (!ship->isControllable()) 
	{
		 gctx.sendToClient(cl, answerWriter :: navigation_ship_not_controllable(shipid, REQUEST_NAVIGATION_UNBOUND));
	}

    /* lod existuje a hraci patri, ale je ve warpu */
    if (ship->MovementIsInWarp())
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_in_warp(shipid, REQUEST_NAVIGATION_UNBOUND));
        return cl;
    }

	dockingResult result = ship->unboundUp();

	gctx.sendToClient(cl, answerWriter :: navigation_unbound(shipid, result));  

    return cl;
}

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

id request_navigation_orbit(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    dtIdentifier shipid = strtoul(parameters[REQUEST_NAVIGATION_SHIPID].c_str(), NULL, 0);
    shipClass* ship = actx->cacheFortressesList.getItem<shipClass>(shipid);

    /* pokud lod neexistuje, vrat chybu */
    if (ship == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_not_exists(shipid, REQUEST_NAVIGATION_ORBIT));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (ship->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_not_owned(shipid, REQUEST_NAVIGATION_ORBIT));
        return cl;
    }

	/* pokud lod neni kontrolovatelna, vrat chybu */
	if (!ship->isControllable()) 
	{
		 gctx.sendToClient(cl, answerWriter :: navigation_ship_not_controllable(shipid, REQUEST_NAVIGATION_ORBIT));
	}

    /* lod existuje a hraci patri, ale je ve warpu */
    if (ship->MovementIsInWarp())
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_in_warp(shipid, REQUEST_NAVIGATION_ORBIT));
        return cl;
    }

    /* pokud lod pristala na zaklade, nelze spustit warp pohon */
    if (ship->MovementIsDockedInBase())
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_docked_in_base(shipid, REQUEST_NAVIGATION_ORBIT));
        return cl;
    }

    if (ship->MovementTargetOrbit())
    {   
        /* posleme zpravu o uspechu */
        gctx.sendToClient(cl, answerWriter :: navigation_OK(REQUEST_NAVIGATION_ORBIT, shipid));
    }
    else
        gctx.sendToClient(cl, answerWriter :: navigation_FAIL(REQUEST_NAVIGATION_ORBIT, shipid));

    ship->MovementNotifyOtherPlayers();

    return cl;
}

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

id request_navigation_pursuit(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    dtIdentifier shipid = strtoul(parameters[REQUEST_NAVIGATION_SHIPID].c_str(), NULL, 0);
    shipClass* ship = actx->cacheFortressesList.getItem<shipClass>(shipid);

    /* pokud lod neexistuje, vrat chybu */
    if (ship == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_not_exists(shipid, REQUEST_NAVIGATION_PURSUIT));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (ship->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_not_owned(shipid, REQUEST_NAVIGATION_PURSUIT));
        return cl;
    }

	/* pokud lod neni kontrolovatelna, vrat chybu */
	if (!ship->isControllable()) 
	{
		 gctx.sendToClient(cl, answerWriter :: navigation_ship_not_controllable(shipid, REQUEST_NAVIGATION_PURSUIT));
	}

    /* lod existuje a hraci patri, ale je ve warpu */
    if (ship->MovementIsInWarp())
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_in_warp(shipid, REQUEST_NAVIGATION_PURSUIT));
        return cl;
    }

    /* pokud lod pristala na zaklade, nelze spustit warp pohon */
    if (ship->MovementIsDockedInBase())
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_docked_in_base(shipid, REQUEST_NAVIGATION_PURSUIT));
        return cl;
    }

    /* ziskame id cizi lode */
    dtIdentifier target = strtoul(parameters[REQUEST_NAVIGATION_TARGET].c_str(), NULL, 0);
    shipClass*   sc     = actx->cacheFortressesList.getItem<shipClass>(target);

    /* pokud lod neexistuje, ohlas chybu */
    if (sc == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_target_not_exits(shipid, REQUEST_NAVIGATION_PURSUIT));
        return cl;
    }

    /* lod musi byt v dosahu senzoru, nebo byt vlastni */

    /* zjistime, zda dana lod neni ve warpu, popr. na zakladne */
    if (!sc->MovementIsInNormalSpace())
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_target_not_in_normal_space(shipid, REQUEST_NAVIGATION_PURSUIT));
        return cl;
    }

    ship->MovementSetEngineIgnitionLimit(atof(parameters[REQUEST_NAVIGATION_ENGINELIMIT].c_str()));
    if (ship->MovementTargetPursuit(target))
    {   
        /* posleme zpravu o uspechu */
        gctx.sendToClient(cl, answerWriter :: navigation_OK(REQUEST_NAVIGATION_PURSUIT, shipid));
    }
    else
        gctx.sendToClient(cl, answerWriter :: navigation_FAIL(REQUEST_NAVIGATION_PURSUIT, shipid));
    ship->MovementNotifyOtherPlayers();

    return cl;
}

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

id request_navigation_move_to_spobj(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    dtIdentifier shipid = strtoul(parameters[REQUEST_NAVIGATION_SHIPID].c_str(), NULL, 0);
    shipClass* ship = actx->cacheFortressesList.getItem<shipClass>(shipid);

    /* pokud lod neexistuje, vrat chybu */
    if (ship == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_not_exists(shipid, REQUEST_NAVIGATION_MOVE_TO_SPOBJ));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (ship->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_not_owned(shipid, REQUEST_NAVIGATION_MOVE_TO_SPOBJ));
        return cl;
    }

    /* pokud lod neni kontrolovatelna, vrat chybu */
	if (!ship->isControllable())
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_not_controllable(shipid, REQUEST_NAVIGATION_MOVE_TO_SPOBJ));
        return cl;
    }

    /* lod existuje a hraci patri, ale je ve warpu */
    if (ship->MovementIsInWarp())
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_in_warp(shipid, REQUEST_NAVIGATION_MOVE_TO_SPOBJ));
        return cl;
    }

    /* pokud lod pristala na zaklade, nelze spustit warp pohon */
    if (ship->MovementIsDockedInBase())
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_docked_in_base(shipid, REQUEST_NAVIGATION_MOVE_TO_SPOBJ));
        return cl;
    }

    /* ziskame id cizi lode */
    dtIdentifier target = strtoul(parameters[REQUEST_NAVIGATION_SPACEOBJECT].c_str(), NULL, 0);
    spaceObject*   obj  = actx->cacheSpaceObjectList.getItem<spaceObject>(target);

    /* pokud cilovy vesmirny objekt neexistuje, ohlas chybu */
    if (obj == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_target_not_exits(shipid, REQUEST_NAVIGATION_MOVE_TO_SPOBJ));
        return cl;
    }

    ship->MovementSetEngineIgnitionLimit(atof(parameters[REQUEST_NAVIGATION_ENGINELIMIT].c_str()));
    if (ship->MovementTargetMoveToSpaceObject(target))
    {   
        /* posleme zpravu o uspechu */
        gctx.sendToClient(cl, answerWriter :: navigation_OK(REQUEST_NAVIGATION_MOVE_TO_SPOBJ, shipid));
    }
    else
        gctx.sendToClient(cl, answerWriter :: navigation_FAIL(REQUEST_NAVIGATION_MOVE_TO_SPOBJ, shipid));
    ship->MovementNotifyOtherPlayers();

    return cl;
}

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

id request_navigation_move_to_spobj_by_warp(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    dtIdentifier shipid = strtoul(parameters[REQUEST_NAVIGATION_SHIPID].c_str(), NULL, 0);
    shipClass* ship = actx->cacheFortressesList.getItem<shipClass>(shipid);

    /* pokud lod neexistuje, vrat chybu */
    if (ship == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_not_exists(shipid, REQUEST_NAVIGATION_MOVE_TO_SPOBJ_BY_WARP));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (ship->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_not_owned(shipid, REQUEST_NAVIGATION_MOVE_TO_SPOBJ_BY_WARP));
        return cl;
    }

    /* pokud lod neni kontrolovatelna, vrat chybu */
	if (!ship->isControllable())
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_not_controllable(shipid, REQUEST_NAVIGATION_MOVE_TO_SPOBJ_BY_WARP));
        return cl;
    }

    /* lod existuje a hraci patri, ale je ve warpu */
    if (ship->MovementIsInWarp())
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_in_warp(shipid, REQUEST_NAVIGATION_MOVE_TO_SPOBJ_BY_WARP));
        return cl;
    }

    /* pokud lod pristala na zaklade, nelze spustit warp pohon */
    if (ship->MovementIsDockedInBase())
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_docked_in_base(shipid, REQUEST_NAVIGATION_MOVE_TO_SPOBJ_BY_WARP));
        return cl;
    }

    /* ziskame id cizi lode */
    dtIdentifier target = strtoul(parameters[REQUEST_NAVIGATION_SPACEOBJECT].c_str(), NULL, 0);
    spaceObject*   obj  = actx->cacheSpaceObjectList.getItem<spaceObject>(target);

    /* pokud cilovy vesmirny objekt neexistuje, ohlas chybu */
    if (obj == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_target_not_exits(shipid, REQUEST_NAVIGATION_MOVE_TO_SPOBJ_BY_WARP));
        return cl;
    }

    vector_dist_t targetPos = obj->getAbsolutePosition();
    dtIdentifier pid = obj->getParentSpaceObject();
    if (obj->getType() == SOT_BASE)
        obj = obj->getParentSpaceObjectInstance();

    /* pokud cilovy vesmirny objekt neexistuje, ohlas chybu */
    if (obj == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_target_not_exits(shipid, REQUEST_NAVIGATION_MOVE_TO_SPOBJ_BY_WARP));
        return cl;
    }

    spaceRegularObject* robj = dynamic_cast<spaceRegularObject*>(obj);
    if (robj == NULL)
    {
        errLogicalError("Expected regular space object with id %u, but is NULL!", (unsigned long long)pid);
        return make_pair(0, 0);
    }

    targetPos.x = targetPos.x - robj->getAreaRadius() * 0.5L;

    if (ship->MovementWarpTravel(targetPos))
    {   
        /* posleme zpravu o uspechu */
        gctx.sendToClient(cl, answerWriter :: navigation_OK(REQUEST_NAVIGATION_MOVE_TO_SPOBJ_BY_WARP, shipid));
    }
    else
    {
        gctx.sendToClient(cl, answerWriter :: navigation_FAIL(REQUEST_NAVIGATION_MOVE_TO_SPOBJ_BY_WARP, shipid));
    }

    ship->MovementNotifyOtherPlayers();

    return cl;
}


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

id request_navigation_break_warp(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    dtIdentifier shipid = strtoul(parameters[REQUEST_NAVIGATION_SHIPID].c_str(), NULL, 0);
    shipClass* ship = actx->cacheFortressesList.getItem<shipClass>(shipid);

    /* pokud lod neexistuje, vrat chybu */
    if (ship == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_not_exists(shipid, REQUEST_NAVIGATION_BREAK_WARP));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (ship->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_not_owned(shipid, REQUEST_NAVIGATION_BREAK_WARP));
        return cl;
    }

    /* pokud lod neni kontrolovatelna, vrat chybu */
	if (!ship->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: navigation_ship_not_controllable(shipid, REQUEST_NAVIGATION_BREAK_WARP));
        return cl;
    }

    /* lod existuje a hraci patri, ale neni ve warpu */
    if (!ship->MovementIsInWarp())
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_not_in_warp(shipid, REQUEST_NAVIGATION_BREAK_WARP));
        return cl;
    }

    ship->MovementAfterWarpEmergencyShutdown();
    ship->MovementUpdateShipMovementStatus();

    /* posleme zpravu o uspechu */
    gctx.sendToClient(cl, answerWriter :: navigation_OK(REQUEST_NAVIGATION_BREAK_WARP, shipid));
    ship->MovementNotifyOtherPlayers();

    return cl;
}

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

id request_update_ship_journey_details(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    dtIdentifier shipid = strtoul(parameters[REQUEST_SHIP_JOURNEY_DETAILS_SHIPID].c_str(), NULL, 0);
    shipClass* ship = actx->cacheFortressesList.getItem<shipClass>(shipid);

    /* pokud lod neexistuje, vrat chybu */
    if (ship == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: ship_journey_details_FAIL(shipid, REQUEST_SHIP_JOURNEY_ANSWER_SHIPNE));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (ship->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: ship_journey_details_FAIL(shipid, REQUEST_SHIP_JOURNEY_ANSWER_SHIPNO));
        return cl;
    }

    /* pokud lod neni kontrolovatelna, vrat chybu */
	if (!ship->isControllable())
    {
        gctx.sendToClient(cl, answerWriter :: ship_journey_details_FAIL(shipid, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

	ship->startReadingForClient();

    /* ok, lod je v poradku, posleme udaje */
    vector_dist_t position  = ship->MovementGetShipPosition();
    vector_dist_t tposition = ship->MovementGetTargetPosition();
    shipMovementState ms    = ship->MovementGetMovementState();
    shipMoveTarget mt       = ship->MovementGetMovementTarget();
    const char* strMS       = movementStateToStr(ms);
    const char* strMT       = movementTargetToStr(mt);

    switch (mt)
    {
    case SMT_MOVE_TO_SPACE_OBJECT:   
        {
        dtIdentifier   spobjid = ship->MovementGetTargetSpaceObject();
        spaceObject*   spobj   = actx->cacheSpaceObjectList.getItem<spaceObject>(spobjid);
        if (spobj == NULL)
        {
            gctx.sendToClient(cl, answerWriter :: ship_journey_details_FAIL(shipid, REQUEST_SHIP_JOURNEY_ANSWER_BADSPOBJ));
            return cl;
        }

        const dist_t estimationDistance = ship->MovementEstimationDistance(); 
        gctx.sendToClient(cl, answerWriter :: ship_journey_details_MOVE_TO_SPACE_OBJECT(shipid, strMS, strMT, ship->MovementGetTargetSpaceObject(),
            spobj->getName(), estimationDistance, gt2wtRelative(ship->MovementEstimationTime(estimationDistance)), position.x, position.y,
            (unsigned long long)abs(ship->MovementGetCurrentSpeed()), (unsigned long long)ship->MovementGetCurrentAcceleration(), ship->canBeUnbounded()));
        }
        break;
    case SMT_MOVE_TO_POSITION:
        {
        const dist_t estimationDistance = ship->MovementEstimationDistance(); 
        gctx.sendToClient(cl, answerWriter :: ship_journey_details_MOVE_TO_POS(shipid, strMS, strMT, tposition.x, tposition.y,
            estimationDistance, gt2wtRelative(ship->MovementEstimationTime(estimationDistance)), position.x, position.y,
            (unsigned long long)abs(ship->MovementGetCurrentSpeed()), (unsigned long long)ship->MovementGetCurrentAcceleration(), ship->canBeUnbounded()));
        }
        break;
    case SMT_MOVE_TO_SHIP: 
        {
        const dist_t estimationDistance = ship->MovementEstimationDistance(); 
        gctx.sendToClient(cl, answerWriter :: ship_journey_details_PURSUIT(shipid, strMS, strMT, ship->MovementGetTargetShip(),
            estimationDistance, gt2wtRelative(ship->MovementEstimationTime(estimationDistance)), position.x, position.y,
            (unsigned long long)abs(ship->MovementGetCurrentSpeed()), (unsigned long long)ship->MovementGetCurrentAcceleration(), ship->canBeUnbounded()));
        }
        break;

    /* nasledujici tri cile vraci stejny stav */
    case SMT_ORBIT:                     
    case SMT_NONE:                                     
    case SMT_STOP:  
        gctx.sendToClient(cl, answerWriter :: ship_journey_details_STANDARD(shipid, position.x, position.y, strMS, strMT,
			(unsigned long long)abs(ship->MovementGetCurrentSpeed()), (unsigned long long)ship->MovementGetCurrentAcceleration(), ship->MovementIsDockedInBase(), ship->canBeUnbounded()));
        break;
    default:
        errExceptionError("Invalid target state %s at ship [%u]", strMT, (unsigned long long) shipid);
    }

    return cl;
}

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

void writeEnergyDivisionClass(const energyDivisionClass& edc, answerDeviceEnergyState& output)
{
    output.maxPowerDrain            = edc.maxPowerDrain;
    output.priority                 = edc.priority;
    output.ratio                    = edc.ratio;
    output.shutDownOnEnergyLack     = edc.shutDownOnEnergyLack;
}

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

id request_update_device_energy_state(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    dtIdentifier fortressid = strtoul(parameters[REQUEST_DEVICE_ENERGY_STATE_FORTRESSID].c_str(), NULL, 0);
    fortressClass* fortress = actx->cacheFortressesList.getItem<fortressClass>(fortressid);

    /* pokud lod neexistuje, vrat chybu */
    if (fortress == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: device_energy_state_error(fortressid, REQUEST_DEVICE_ENERGY_ANSWER_FORTRESSNE));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (fortress->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: device_energy_state_error(fortressid, REQUEST_DEVICE_ENERGY_ANSWER_FORTRESSNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!fortress->isControllable())
    {
        gctx.sendToClient(cl, answerWriter :: device_energy_state_error(fortressid, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

	fortress->startReadingForClient();

    answerDeviceEnergy ade;
    
	ade.ACC_CURR_ENERGY         = fortress->energeticSystem.getEnergy(fortress);
    ade.ACC_MAX_ENERGY          = fortress->energeticSystem.energeticAccumulator()->actualAccumulator();
    ade.CURR_ENERGY             = fortress->updateEng();
    ade.MAX_ENERGY              = fortress->energyLimitInTeraJoules();
    ade.MAX_ENERGY_PRIORITY     = ED_MAX_PRIORITY;
    ade.MAX_RATIO               = ULONG_MAX;
    ade.MIN_ENERGY_PRIORITY     = ED_MIN_PRIORITY;
    ade.MIN_MAX_ENERGY          = 0;
    ade.MIN_RATIO               = 1;

    writeEnergyDivisionClass(fortress->deflectorShields.deflectorsEnergyDivision,   ade.SHIELDS);
    writeEnergyDivisionClass(fortress->mechanics.androidsEnergyDivision,            ade.ANDROIDS);
    writeEnergyDivisionClass(fortress->sensors.sensorsHREnergyDivision,             ade.HR_SENSORS);
    writeEnergyDivisionClass(fortress->otherEquipment.lifeSupportEnergyDivision,    ade.LIFE_SUPPORT);
    writeEnergyDivisionClass(fortress->sensors.sensorsLREnergyDivision,             ade.LR_SENSORS);
    writeEnergyDivisionClass(fortress->mainframeSystem.mainframeEnergyDivision,     ade.MAINFRAME);
    writeEnergyDivisionClass(fortress->cloaking.cloakingEnergyDivision,             ade.MASKING);
    writeEnergyDivisionClass(fortress->transportBeam.tBeamEnergyDivision,           ade.TRANSPORT);
    writeEnergyDivisionClass(fortress->weapons.weaponsEnergyDivision,               ade.WEAPONS);

	ade.SHIELDS.consumption             = fortress->deflectorShields.getActualEnergyConsumption();
	ade.SHIELDS.maxMaxPowerDrain        = fortress->deflectorShields.deflectorShieldsGenerator()->maxPossibleConsumption();
    ade.ANDROIDS.consumption            = fortress->mechanics.getActualEnergyConsumption();
	ade.ANDROIDS.maxMaxPowerDrain       = fortress->mechanics.androids()->maxPossibleConsumption();
    ade.HR_SENSORS.consumption          = fortress->sensors.getActualEnergyConsumptionHR();
	ade.HR_SENSORS.maxMaxPowerDrain     = fortress->sensors.highResolutionSensors()->maxPossibleConsumption();
	ade.LIFE_SUPPORT.consumption        = fortress->otherEquipment.getActualEnergyConsumption();
	ade.LIFE_SUPPORT.maxMaxPowerDrain   = fortress->otherEquipment.lifeSupport()->maxPossibleConsumption();
    ade.LR_SENSORS.consumption          = fortress->sensors.getActualEnergyConsumptionLR();
	ade.LR_SENSORS.maxMaxPowerDrain     = fortress->sensors.longRangeSensors()->maxPossibleConsumption();
    ade.MAINFRAME.consumption           = fortress->mainframeSystem.getActualEnergyConsumption();
	ade.MAINFRAME.maxMaxPowerDrain      = fortress->mainframeSystem.mainframe()->maxPossibleConsumption();
    ade.MASKING.consumption             = fortress->cloaking.getActualEnergyConsumption();
	ade.MASKING.maxMaxPowerDrain        = fortress->cloaking.cloakingDevice()->maxPossibleConsumption();
    ade.TRANSPORT.consumption           = fortress->transportBeam.getActualEnergyConsumption();
	ade.TRANSPORT.maxMaxPowerDrain      = fortress->transportBeam.transportBeamGenerator()->maxPossibleConsumption();
    ade.WEAPONS.consumption             = fortress->weapons.getActualEnergyConsumption();
	ade.WEAPONS.maxMaxPowerDrain        = fortress->weapons.weaponEnergyCircuit()->maxPossibleConsumption();

	ade.accumulatorGradient = fortress->energeticSystem.getGradient(fortress);
	ade.totalEnergyGradient = fortress->energyGradient();

    gctx.sendToClient(cl, answerWriter :: device_energy_state(fortressid, ade));

    return cl;
}

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

void readEnergyDivisionClass(energyDivisionClass& input, requestDeviceEnergyState& redc)
{
    input.maxPowerDrain            = redc.maxPowerDrain;
    input.priority                 = redc.priority;
    input.ratio                    = redc.ratio;
    input.shutDownOnEnergyLack     = redc.shutDownOnEnergyLack;
}

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

void loadDESFromParameters(const char* devName, std :: map<std :: string, std :: string>& parameters, 
                           requestDeviceEnergyState& redc)
{
    std :: stringstream ss;

    ss << devName << REQUEST_CHANGE_DEVICE_ENERGY_STATE_ANSWER_ES_PRIORITY;
    redc.priority = (unsigned char)_atoi64(parameters[ss.str()].c_str());
    ss.str(std :: string(""));

    ss << devName << REQUEST_CHANGE_DEVICE_ENERGY_STATE_ANSWER_ES_RATIO;
    redc.ratio = (unsigned int)_atoi64(parameters[ss.str()].c_str());
    ss.str(std :: string(""));

    ss << devName << REQUEST_CHANGE_DEVICE_ENERGY_STATE_ANSWER_ES_MAX_POWER_DRAIN;
    redc.maxPowerDrain = strtod(parameters[ss.str()].c_str(), NULL);
    ss.str(std :: string(""));

    ss << devName << REQUEST_CHANGE_DEVICE_ENERGY_STATE_ANSWER_ES_SHUT_DOWN_ON_EL;
    redc.shutDownOnEnergyLack = _atoi64(parameters[ss.str()].c_str()) != 0;
    ss.str(std :: string(""));
}

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

id request_change_device_energy_state(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    dtIdentifier fortressid = strtoul(parameters[REQUEST_CHANGE_DEVICE_ENERGY_STATE_ANSWER_FORTRESSID].c_str(), NULL, 0);
    fortressClass* fortress = actx->cacheFortressesList.getItem<fortressClass>(fortressid);

    /* pokud lod neexistuje, vrat chybu */
    if (fortress == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: change_device_energy_state_error(fortressid, REQUEST_CHANGE_DEVICE_ENERGY_ANSWER_FORTRESSNE));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (fortress->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: change_device_energy_state_error(fortressid, REQUEST_CHANGE_DEVICE_ENERGY_ANSWER_FORTRESSNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!fortress->isControllable())
    {
        gctx.sendToClient(cl, answerWriter :: change_device_energy_state_error(fortressid, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

    /* zmenime data podle klienta */
    requestDeviceEnergy rde;

    loadDESFromParameters(REQUEST_CHANGE_DEVICE_ENERGY_STATE_CHANGE_SHIELDS, parameters,         rde.SHIELDS);
    loadDESFromParameters(REQUEST_CHANGE_DEVICE_ENERGY_STATE_CHANGE_ANDROIDS, parameters,        rde.ANDROIDS);
    loadDESFromParameters(REQUEST_CHANGE_DEVICE_ENERGY_STATE_CHANGE_HR_SENSORS, parameters,      rde.HR_SENSORS);
    loadDESFromParameters(REQUEST_CHANGE_DEVICE_ENERGY_STATE_CHANGE_LIFE_SUPPORT, parameters,    rde.LIFE_SUPPORT);
    loadDESFromParameters(REQUEST_CHANGE_DEVICE_ENERGY_STATE_CHANGE_LR_SENSORS, parameters,      rde.LR_SENSORS);
    loadDESFromParameters(REQUEST_CHANGE_DEVICE_ENERGY_STATE_CHANGE_MAINFRAME, parameters,       rde.MAINFRAME);
    loadDESFromParameters(REQUEST_CHANGE_DEVICE_ENERGY_STATE_CHANGE_MASKING, parameters,         rde.MASKING);
    loadDESFromParameters(REQUEST_CHANGE_DEVICE_ENERGY_STATE_CHANGE_TRANSPORT, parameters,       rde.TRANSPORT);
    loadDESFromParameters(REQUEST_CHANGE_DEVICE_ENERGY_STATE_CHANGE_WEAPONS, parameters,         rde.WEAPONS);

    readEnergyDivisionClass(fortress->deflectorShields.deflectorsEnergyDivision,   rde.SHIELDS);
    readEnergyDivisionClass(fortress->mechanics.androidsEnergyDivision,            rde.ANDROIDS);
    readEnergyDivisionClass(fortress->sensors.sensorsHREnergyDivision,             rde.HR_SENSORS);
    readEnergyDivisionClass(fortress->otherEquipment.lifeSupportEnergyDivision,    rde.LIFE_SUPPORT);
    readEnergyDivisionClass(fortress->sensors.sensorsLREnergyDivision,             rde.LR_SENSORS);
    readEnergyDivisionClass(fortress->mainframeSystem.mainframeEnergyDivision,     rde.MAINFRAME);
    readEnergyDivisionClass(fortress->cloaking.cloakingEnergyDivision,             rde.MASKING);
    readEnergyDivisionClass(fortress->transportBeam.tBeamEnergyDivision,           rde.TRANSPORT);
    readEnergyDivisionClass(fortress->weapons.weaponsEnergyDivision,               rde.WEAPONS);

    fortress->energyDistributionPhaseAndWeaponsFire();

    /* odpovime clientovi s novym nastavenim */
    answerDeviceEnergy ade;
    
    ade.ACC_CURR_ENERGY         = fortress->energeticSystem.energeticAccumulatorEnergyState.energy;
    ade.ACC_MAX_ENERGY          = fortress->energeticSystem.energeticAccumulator()->actualAccumulator();
    ade.CURR_ENERGY             = fortress->updateEng();
    ade.MAX_ENERGY              = fortress->energyLimitInTeraJoules();
    ade.MAX_ENERGY_PRIORITY     = ED_MAX_PRIORITY;
    ade.MAX_RATIO               = ULONG_MAX;
    ade.MIN_ENERGY_PRIORITY     = ED_MIN_PRIORITY;
    ade.MIN_MAX_ENERGY          = 0;
    ade.MIN_RATIO               = 1;

    writeEnergyDivisionClass(fortress->deflectorShields.deflectorsEnergyDivision,   ade.SHIELDS);
    writeEnergyDivisionClass(fortress->mechanics.androidsEnergyDivision,            ade.ANDROIDS);
    writeEnergyDivisionClass(fortress->sensors.sensorsHREnergyDivision,             ade.HR_SENSORS);
    writeEnergyDivisionClass(fortress->otherEquipment.lifeSupportEnergyDivision,    ade.LIFE_SUPPORT);
    writeEnergyDivisionClass(fortress->sensors.sensorsLREnergyDivision,             ade.LR_SENSORS);
    writeEnergyDivisionClass(fortress->mainframeSystem.mainframeEnergyDivision,     ade.MAINFRAME);
    writeEnergyDivisionClass(fortress->cloaking.cloakingEnergyDivision,             ade.MASKING);
    writeEnergyDivisionClass(fortress->transportBeam.tBeamEnergyDivision,           ade.TRANSPORT);
    writeEnergyDivisionClass(fortress->weapons.weaponsEnergyDivision,               ade.WEAPONS);

	ade.SHIELDS.consumption             = fortress->deflectorShields.getActualEnergyConsumption();
	ade.SHIELDS.maxMaxPowerDrain        = fortress->deflectorShields.deflectorShieldsGenerator()->maxPossibleConsumption();
    ade.ANDROIDS.consumption            = fortress->mechanics.getActualEnergyConsumption();
	ade.ANDROIDS.maxMaxPowerDrain       = fortress->mechanics.androids()->maxPossibleConsumption();
    ade.HR_SENSORS.consumption          = fortress->sensors.getActualEnergyConsumptionHR();
	ade.HR_SENSORS.maxMaxPowerDrain     = fortress->sensors.highResolutionSensors()->maxPossibleConsumption();
	ade.LIFE_SUPPORT.consumption        = fortress->otherEquipment.getActualEnergyConsumption();
	ade.LIFE_SUPPORT.maxMaxPowerDrain   = fortress->otherEquipment.lifeSupport()->maxPossibleConsumption();
    ade.LR_SENSORS.consumption          = fortress->sensors.getActualEnergyConsumptionLR();
	ade.LR_SENSORS.maxMaxPowerDrain     = fortress->sensors.longRangeSensors()->maxPossibleConsumption();
    ade.MAINFRAME.consumption           = fortress->mainframeSystem.getActualEnergyConsumption();
	ade.MAINFRAME.maxMaxPowerDrain      = fortress->mainframeSystem.mainframe()->maxPossibleConsumption();
    ade.MASKING.consumption             = fortress->cloaking.getActualEnergyConsumption();
	ade.MASKING.maxMaxPowerDrain        = fortress->cloaking.cloakingDevice()->maxPossibleConsumption();
    ade.TRANSPORT.consumption           = fortress->transportBeam.getActualEnergyConsumption();
	ade.TRANSPORT.maxMaxPowerDrain      = fortress->transportBeam.transportBeamGenerator()->maxPossibleConsumption();
    ade.WEAPONS.consumption             = fortress->weapons.getActualEnergyConsumption();
	ade.WEAPONS.maxMaxPowerDrain        = fortress->weapons.weaponEnergyCircuit()->maxPossibleConsumption();

	ade.accumulatorGradient = fortress->energeticSystem.getGradient(fortress);
	ade.totalEnergyGradient = fortress->energyGradient();

    gctx.sendToClient(cl, answerWriter :: device_energy_state(fortressid, ade));

    return cl;
}

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

static void ns_write_ship(protocolWriter& w, int index, dtIdentifier shipid, dist_t distance, const std :: string& name)
{
    std :: stringstream ss;

    ss << REQUEST_NAVIGATION_STATUS_ANSWER_MYSHIPID << index;
    w.writeValue(ss.str(), shipid);
    ss.str(std :: string(""));

    ss << REQUEST_NAVIGATION_STATUS_ANSWER_MYSHIPNAME << index;
    w.writeValue(ss.str(), name);
    ss.str(std :: string(""));

    ss << REQUEST_NAVIGATION_STATUS_ANSWER_MYSHIPDISTANCE << index;
    w.writeValue(ss.str(), (unsigned long long)distance);
    ss.str(std :: string(""));
}

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

static void ns_write_base(protocolWriter& w, int index, dtIdentifier baseid, dist_t distance, const std :: string& name, dockingResult canShipDockDown)
{
    std :: stringstream ss;

    ss << REQUEST_NAVIGATION_STATUS_ANSWER_MYBASEID << index;
    w.writeValue(ss.str(), baseid);
    ss.str(std :: string(""));

    ss << REQUEST_NAVIGATION_STATUS_ANSWER_MYBASENAME << index;
    w.writeValue(ss.str(), name);
    ss.str(std :: string(""));

    ss << REQUEST_NAVIGATION_STATUS_ANSWER_MYBASEDISTANCE << index;
    w.writeValue(ss.str(), (unsigned long long)distance);
    ss.str(std :: string(""));

    ss << REQUEST_NAVIGATION_STATUS_ANSWER_CAN_SHIP_DOCK_DOWN << index;
    w.writeValue(ss.str(), (unsigned long) canShipDockDown);
    ss.str(std :: string(""));
}

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

static void ns_write_discovered_star(protocolWriter& w, int index, dtIdentifier starid, dist_t distance, const std :: string& name)
{
    std :: stringstream ss;

    ss << REQUEST_NAVIGATION_STATUS_ANSWER_DISCOVERED_STAR_ID << index;
    w.writeValue(ss.str(), starid);
    ss.str(std :: string(""));

    ss << REQUEST_NAVIGATION_STATUS_ANSWER_DISCOVERED_STAR_DISTANCE << index;
    w.writeValue(ss.str(), (unsigned long long)distance);
    ss.str(std :: string(""));

    ss << REQUEST_NAVIGATION_STATUS_ANSWER_DISCOVERED_STAR_NAME << index;
    w.writeValue(ss.str(), name);
    ss.str(std :: string(""));
}

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

id request_update_navigation_status(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    dtIdentifier shipid = strtoul(parameters[REQUEST_NAVIGATION_SHIPID].c_str(), NULL, 0);
    shipClass* ship = actx->cacheFortressesList.getItem<shipClass>(shipid);

    /* pokud lod neexistuje, vrat chybu */
    if (ship == NULL)
    {
		gctx.sendToClient(cl, answerWriter :: navigation_ship_not_exists(shipid, REQUEST_NAVIGATION_STATUS));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (ship->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_not_owned(shipid, REQUEST_NAVIGATION_STATUS));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!ship->isControllable())
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_not_controllable(shipid, REQUEST_NAVIGATION_STATUS));
        return cl;
    }

    /* lod existuje a hraci patri, ale je ve warpu */
    if (ship->MovementIsInWarp())
    {
        gctx.sendToClient(cl, answerWriter :: navigation_ship_in_warp(shipid, REQUEST_NAVIGATION_STATUS));
        return cl;
    }

    realmClass* realm = actx->cacheRealmsList.getItem<realmClass>(cl.first);
    const vector_dist_t position = ship->MovementGetShipPosition();
    protocolWriter w;
    w.beginMessage(MT_ANSWER, REQUEST_NAVIGATION_STATUS);

    /* retrieve list of ships */
    std :: list<shipClass*> ships;
    if (realm != NULL)
    {
        const dtIdentifierVector& vships = realm->getShipList();
        for (dtIdentifierVector :: const_iterator iter = vships.begin(); iter != vships.end(); iter++)
        {
           shipClass* f = actx->cacheFortressesList.getItem<shipClass>(*iter);
            if (f!= NULL)
            {
                if (f->getFortressType() == FT_SHIP) 
                {
                    ships.push_back(f);
                }
                else
                {
                    errExceptionError("Base [%u] in ships list!", (unsigned long long) f->getID());
                    return make_pair(0, 0);
                }
            }
            else
            {
                errExceptionError("Ship with id %u not found!", (unsigned long long) *iter);
                return make_pair(0, 0);
            }
        }
    }
    else
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) cl.first);
        return make_pair(0, 0);
    }

    /* vypiseme lode */
    int shipIndex = 1;
    w.writeValue(REQUEST_NAVIGATION_STATUS_ANSWER_MYSHIPCOUNT, (unsigned long long)ships.size());
    for (std :: list<shipClass*> :: iterator iter = ships.begin(); iter != ships.end(); iter++)
    {
		ns_write_ship(w, shipIndex, (*iter)->getID(), (position - (*iter)->MovementGetShipPosition()).norm(), (*iter)->getFortressName());
        shipIndex++;
    }

    /* retrieve list of bases */
    std :: list<baseClass*> bases;
    if (realm != NULL)
    {
        const dtIdentifierVector& vbases = realm->getBaseList();
        for (dtIdentifierVector :: const_iterator iter = vbases.begin(); iter != vbases.end(); iter++)
        {
            baseClass* f = actx->cacheFortressesList.getItem<baseClass>(*iter);
            if (f!= NULL)
            {
                if (f->getFortressType() == FT_BASE) 
                {
                    bases.push_back(f);                 
                }
                else
                {
                    errExceptionError("Ship [%u] in bases list!", (unsigned long long) f->getID());
                    return make_pair(0, 0);
                }
            }
            else
            {
                errExceptionError("Ship with id %u not found!", (unsigned long long) *iter);
                return make_pair(0, 0);
            }
        }
    }
    else
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) cl.first);
        return make_pair(0, 0);
    }

    /* vypiseme zakladny */
    int baseIndex = 1;
    w.writeValue(REQUEST_NAVIGATION_STATUS_ANSWER_MYBASECOUNT, (unsigned long long)bases.size());
    for (std :: list<baseClass*> :: iterator iter = bases.begin(); iter != bases.end(); iter++)
    {
		ns_write_base(w, baseIndex, (*iter)->getID(), (position - (*iter)->MovementGetBasePosition()).norm(), (*iter)->getFortressName(), ship->canDockDown((*iter)));
        baseIndex++;
    }

    /* vypiseme nepratelske lode */
    /* projedeme vsechny lode */ 
    spaceIndexItem* itm = actx->spaceObjectIndex.getNearestItem(position);
    if (itm == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: shipsinarea_ie(shipid));
        return cl;
    }

    /* projedeme vsechny lode */
    std :: list<shipClass*> hi_ships;
    std :: list<shipClass*> lo_ships;

    dtIdentifierList shipsInRangeForScanning;
    dtIdentifierList shipsInRangeForObserving;
    dtIdentifierList basesInRangeForScanning;
    dtIdentifierList basesInRangeForObserving;

    ship->getFortressesInRangeForScanning(&basesInRangeForScanning, &shipsInRangeForScanning);
    ship->getFortressesInRangeForObserving(&basesInRangeForObserving, &shipsInRangeForObserving);

    std :: set<dtIdentifier> lShipsIds;
    std :: set<dtIdentifier> hShipsIds;
    std :: set<dtIdentifier> oShipsIds;

    lShipsIds.insert(shipsInRangeForObserving.begin(), shipsInRangeForObserving.end());
    hShipsIds.insert(shipsInRangeForScanning.begin(), shipsInRangeForScanning.end());

    // smazeme vsechny lode z lShips, ktere uz jsou v hShips
    for (std :: set<dtIdentifier> :: const_iterator iter = hShipsIds.begin(); iter != hShipsIds.end(); iter++)
    {
        lShipsIds.erase(*iter);
    }

    // najdeme vlastni lode
    dtIdentifierList starShips;
    actx->spaceObjectIndex.getShipsInArea(itm->spaceSystemIndex_, starShips);

    // pridame vlastni lode do seznamu vlastnich lodi
    for (dtIdentifierList :: const_iterator iter = starShips.begin(); iter != starShips.end(); iter++)
    {
        shipClass* otherShip = actx->cacheFortressesList.getItem<shipClass>(*iter);
        if (otherShip != NULL)
        {
            if (otherShip->getFortressRealmID() == cl.first)
            {
                oShipsIds.insert(*iter);
            }
        }
        else
        {
            errLogicalError("Ship %u does not exist!", (unsigned long long)(*iter));
        }
    }

    for (std :: set<dtIdentifier> :: const_iterator iter = lShipsIds.begin(); iter != lShipsIds.end(); iter++)
    {
        shipClass* otherShip = actx->cacheFortressesList.getItem<shipClass>(*iter);
        if (otherShip != NULL)
        {
            if (otherShip->getFortressRealmID() == cl.first)
            {
                oShipsIds.insert(*iter);
            }
        }
        else
        {
            errLogicalError("Ship %u does not exist!", (unsigned long long)(*iter));
        }
    }

    for (std :: set<dtIdentifier> :: const_iterator iter = hShipsIds.begin(); iter != hShipsIds.end(); iter++)
    {
        shipClass* otherShip = actx->cacheFortressesList.getItem<shipClass>(*iter);
        if (otherShip != NULL)
        {
            if (otherShip->getFortressRealmID() == cl.first)
            {
                oShipsIds.insert(*iter);
            }
        }
        else
        {
            errLogicalError("Ship %u does not exist!", (unsigned long long)(*iter));
        }
    }

    // smazeme vlastni lode z lShips a hShips
    for (std :: set<dtIdentifier> :: const_iterator iter = oShipsIds.begin(); iter != oShipsIds.end(); iter++)
    {
        lShipsIds.erase(*iter);
        hShipsIds.erase(*iter);
    }

    // naplnime lo_ships
    for (std :: set<dtIdentifier> :: const_iterator iter = lShipsIds.begin(); iter != lShipsIds.end(); iter++)
    {
        shipClass* otherShip = actx->cacheFortressesList.getItem<shipClass>(*iter);
        if (otherShip != NULL)
        {
            lo_ships.push_back(otherShip);
        }
        else
        {
            errLogicalError("Ship %u does not exist!", (unsigned long long)(*iter));
        } 
    }

    // naplnime hi_ships
    for (std :: set<dtIdentifier> :: const_iterator iter = hShipsIds.begin(); iter != hShipsIds.end(); iter++)
    {
        shipClass* otherShip = actx->cacheFortressesList.getItem<shipClass>(*iter);
        if (otherShip != NULL)
        {
            hi_ships.push_back(otherShip);
        }
        else
        {
            errLogicalError("Ship %u does not exist!", (unsigned long long)(*iter));
        } 
    }

    unsigned long cntr = 1;
    w.writeValue(REQUEST_NAVIGATION_STATUS_ANSWER_LR_COUNT, (unsigned long long)lo_ships.size());
    for (std :: list<shipClass*> :: iterator iter = lo_ships.begin(); iter != lo_ships.end(); iter++)
    {
        write_ns_lr_ship(w, cntr, *iter, (position - (*iter)->MovementGetShipPosition()).norm());
        cntr++;
    }

    cntr = 1;
    // z technickych duvodu jsou tady jmena poli stejna jako u shipsinarea - pozn. nevim proc (Jakub)
    w.writeValue(REQUEST_NAVIGATION_STATUS_ANSWER_HR_COUNT, (unsigned long long)hi_ships.size());
    for (std :: list<shipClass*> :: iterator iter = hi_ships.begin(); iter != hi_ships.end(); iter++)
    {
        write_ns_hr_ship(w, cntr, *iter, (position - (*iter)->MovementGetShipPosition()).norm());
        cntr++;
    }

    /* vypiseme objevene hvezdne systemy */
    w.writeValue(REQUEST_NAVIGATION_STATUS_ANSWER_DISCOVERED_STAR_COUNT, realm->discoveredStarsCount());
    for (cntr = 1; cntr <= realm->discoveredStarsCount(); cntr++)
    {
        spaceObject* obj = actx->cacheSpaceObjectList.getItem<spaceObject>(realm->discoveredStarID(cntr-1));
        if (obj != NULL)
        {
            dist_t starDistance = (position - obj->getAbsolutePosition()).norm();
            ns_write_discovered_star(w, cntr, obj->getID(), starDistance, obj->getName());
        }
        else
        {
            errExceptionError("Bad space object index %u in discovered star systems", (unsigned long long)realm->discoveredStarID(cntr-1));
        }
    }

    w.endMessage(true);
    gctx.sendToClient(cl, w.copyMessage());

    return cl;
}

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

id request_update_science(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    /* najdeme objekt hrace*/
    std :: list<std :: pair<unsigned long, std :: string>> ships;
    realmClass* realm = actx->cacheRealmsList.getItem<realmClass>(cl.first);
    if (realm != NULL)
    {
        /* posleme vedu */
        gctx.sendToClient(cl, answerWriter :: science(realm->getScientificTree()));
    }
    else
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) cl.first);
        gctx.sendToClient(cl, answerWriter :: science_ie());
        return cl;
    }

    return cl;
}

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

id request_science_change(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    /* najdeme objekt hrace*/
    std :: list<std :: pair<unsigned long, std :: string>> ships;
    realmClass* realm = actx->cacheRealmsList.getItem<realmClass>(cl.first);
    if (realm != NULL)
    {
        scientificTree* sc = realm->getScientificTree();

        /* vynulujeme strom */
        sc->nullifyTreeTokens();

        /* zapiseme polozky */
        sc->setPureLeafTokens(SCIENCE_ENTITY_SHIPS,                             (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_SHIPS].c_str()));                             
        sc->setPureLeafTokens(SCIENCE_ENTITY_BASES,                             (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_BASES].c_str()));                              
        sc->setPureLeafTokens(SCIENCE_ENTITY_ENERGETIC_ACCUMULATOR,             (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_ENERGETIC_ACCUMULATOR].c_str()));  
        sc->setPureLeafTokens(SCIENCE_ENTITY_NAVIGATION_COMPUTER,               (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_NAVIGATION_COMPUTER].c_str()));  
        sc->setPureLeafTokens(SCIENCE_ENTITY_QUARK_GLUON_CORE,                  (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_QUARK_GLUON_CORE].c_str()));  
        sc->setPureLeafTokens(SCIENCE_ENTITY_SUBSPACE_BEACON,                   (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_SUBSPACE_BEACON].c_str()));  
        sc->setPureLeafTokens(SCIENCE_ENTITY_INERTIAL_DAMPERS,                  (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_INERTIAL_DAMPERS].c_str()));  
        sc->setPureLeafTokens(SCIENCE_ENTITY_IMPULS_JET_ENGINE,                 (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_IMPULS_JET_ENGINE].c_str()));  
        sc->setPureLeafTokens(SCIENCE_ENTITY_MECHANICAL_DAMPERS,                (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_MECHANICAL_DAMPERS].c_str()));  
        sc->setPureLeafTokens(SCIENCE_ENTITY_DEFLECTOR_SHIELDS,                 (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_DEFLECTOR_SHIELDS].c_str()));  
        sc->setPureLeafTokens(SCIENCE_ENTITY_WEAPON_ENERGY_CIRCUIT,             (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_WEAPON_ENERGY_CIRCUIT].c_str())); 
        sc->setPureLeafTokens(SCIENCE_ENTITY_DRONE_MISSILE_LAUNCHER,            (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_DRONE_MISSILE_LAUNCHER].c_str())); 
        sc->setPureLeafTokens(SCIENCE_ENTITY_DRONE_MISSILES,                    (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_DRONE_MISSILES].c_str())); 
        sc->setPureLeafTokens(SCIENCE_ENTITY_LASER_GUN,                         (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_LASER_GUN].c_str())); 
        sc->setPureLeafTokens(SCIENCE_ENTITY_TRANSPORT_BEAM_GENERATOR,          (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_TRANSPORT_BEAM_GENERATOR].c_str())); 
        sc->setPureLeafTokens(SCIENCE_ENTITY_MAGNETICAL_COLLECTORS_OF_PLASMA,   (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_MAGNETICAL_COLLECTORS_OF_PLASMA].c_str())); 
        sc->setPureLeafTokens(SCIENCE_ENTITY_SUBMERSIBLE_FILTRATION_TANK,       (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_SUBMERSIBLE_FILTRATION_TANK].c_str()));                 
        sc->setPureLeafTokens(SCIENCE_ENTITY_SUBMARINE_MINING_MACHINE,          (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_SUBMARINE_MINING_MACHINE].c_str())); 
        sc->setPureLeafTokens(SCIENCE_ENTITY_UNDERGROUND_DRILLING_MACHINE,      (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_UNDERGROUND_DRILLING_MACHINE].c_str())); 
        sc->setPureLeafTokens(SCIENCE_ENTITY_PROBE,                             (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_PROBE].c_str())); 
        sc->setPureLeafTokens(SCIENCE_ENTITY_HIGH_RESOLUTION_SENSORS,           (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_HIGH_RESOLUTION_SENSORS].c_str())); 
        sc->setPureLeafTokens(SCIENCE_ENTITY_LONG_RANGE_SENSORS,                (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_LONG_RANGE_SENSORS].c_str())); 
        sc->setPureLeafTokens(SCIENCE_ENTITY_CLOAKING_DEVICE,                   (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_CLOAKING_DEVICE].c_str())); 
        sc->setPureLeafTokens(SCIENCE_ENTITY_ANDROIDS,                          (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_ANDROIDS].c_str())); 
        sc->setPureLeafTokens(SCIENCE_ENTITY_SCIENTIFIC_LAB,                    (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_SCIENTIFIC_LAB].c_str())); 
        sc->setPureLeafTokens(SCIENCE_ENTITY_LIFE_SUPPORT,                      (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_LIFE_SUPPORT].c_str())); 
        sc->setPureLeafTokens(SCIENCE_ENTITY_MAINFRAME,                         (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_MAINFRAME].c_str())); 
        sc->setPureLeafTokens(SCIENCE_ENTITY_HANGAR,                            (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_HANGAR].c_str())); 
        sc->setPureLeafTokens(SCIENCE_ENTITY_MAGNETICAL_FILTER,                 (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_MAGNETICAL_FILTER].c_str())); 
        sc->setPureLeafTokens(SCIENCE_ENTITY_DEUTERIUM_DECOMPOSER,              (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_DEUTERIUM_DECOMPOSER].c_str())); 
        sc->setPureLeafTokens(SCIENCE_ENTITY_ZIRCONIUM_REACTOR,                 (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_ZIRCONIUM_REACTOR].c_str())); 
        sc->setPureLeafTokens(SCIENCE_ENTITY_ILMENITE_FURNACE,                  (unsigned short)atol(parameters[TOKENS_SCIENCE_ENTITY_ILMENITE_FURNACE].c_str())); 


        sc->setPureInnerTokens(SCIENCE_SUPREME_ENTITY_SCIENCE,                  (unsigned short)atol(parameters[TOKENS_SCIENCE_SUPREME_ENTITY_SCIENCE].c_str()));

        sc->setPureInnerTokens(SCIENCE_SUPREME_ENTITY_DRIVE,                    (unsigned short)atol(parameters[TOKENS_SCIENCE_SUPREME_ENTITY_DRIVE].c_str()));
        sc->setPureInnerTokens(SCIENCE_SUPREME_ENTITY_PLATFORM,                 (unsigned short)atol(parameters[TOKENS_SCIENCE_SUPREME_ENTITY_PLATFORM].c_str()));
        sc->setPureInnerTokens(SCIENCE_SUPREME_ENTITY_MODULES,                  (unsigned short)atol(parameters[TOKENS_SCIENCE_SUPREME_ENTITY_MODULES].c_str()));
        sc->setPureInnerTokens(SCIENCE_SUPREME_ENTITY_PRODUCTION,               (unsigned short)atol(parameters[TOKENS_SCIENCE_SUPREME_ENTITY_PRODUCTION].c_str()));

        sc->setPureInnerTokens(SCIENCE_SUPREME_ENTITY_SUBSPACE_DRIVE,           (unsigned short)atol(parameters[TOKENS_SCIENCE_SUPREME_ENTITY_SUBSPACE_DRIVE].c_str()));
        sc->setPureInnerTokens(SCIENCE_SUPREME_ENTITY_IMPULS_DRIVE,             (unsigned short)atol(parameters[TOKENS_SCIENCE_SUPREME_ENTITY_IMPULS_DRIVE].c_str()));
        sc->setPureInnerTokens(SCIENCE_SUPREME_ENTITY_CONSTRUCTION,             (unsigned short)atol(parameters[TOKENS_SCIENCE_SUPREME_ENTITY_CONSTRUCTION].c_str()));
        sc->setPureInnerTokens(SCIENCE_SUPREME_ENTITY_EQUIPMENT,                (unsigned short)atol(parameters[TOKENS_SCIENCE_SUPREME_ENTITY_EQUIPMENT].c_str()));
        sc->setPureInnerTokens(SCIENCE_SUPREME_ENTITY_ENERGETIC_RING,           (unsigned short)atol(parameters[TOKENS_SCIENCE_SUPREME_ENTITY_ENERGETIC_RING].c_str()));
        sc->setPureInnerTokens(SCIENCE_SUPREME_ENTITY_RECOGNITION_DEVICES,      (unsigned short)atol(parameters[TOKENS_SCIENCE_SUPREME_ENTITY_RECOGNITION_DEVICES].c_str()));
        sc->setPureInnerTokens(SCIENCE_SUPREME_ENTITY_FACTORIES,                (unsigned short)atol(parameters[TOKENS_SCIENCE_SUPREME_ENTITY_FACTORIES].c_str()));
        sc->setPureInnerTokens(SCIENCE_SUPREME_ENTITY_QUARRYING_MACHINES,       (unsigned short)atol(parameters[TOKENS_SCIENCE_SUPREME_ENTITY_QUARRYING_MACHINES].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_QUARK_GLUON_CORE,                  INDEX_QUARK_GLUON_CORE_SPEED,                           (unsigned short)atol(parameters[SPEC_PTS_QUARK_GLUON_CORE_SPEED].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_QUARK_GLUON_CORE,                  INDEX_QUARK_GLUON_CORE_CONSUMPTION,                     (unsigned short)atol(parameters[SPEC_PTS_QUARK_GLUON_CORE_CONSUMPTION].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_NAVIGATION_COMPUTER,               INDEX_NAVIGATION_COMPUTER_SPEED,                        (unsigned short)atol(parameters[SPEC_PTS_NAVIGATION_COMPUTER_SPEED].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_SUBSPACE_BEACON,                   INDEX_SUBSPACE_BEACON_SPEED,                            (unsigned short)atol(parameters[SPEC_PTS_SUBSPACE_BEACON_SPEED].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_INERTIAL_DAMPERS,                  INDEX_INERTIAL_DAMPERS_SPEED,                           (unsigned short)atol(parameters[SPEC_PTS_INERTIAL_DAMPERS_SPEED].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_IMPULS_JET_ENGINE,                 INDEX_IMPULS_ENGINE_FORCE,                              (unsigned short)atol(parameters[SPEC_PTS_IMPULS_ENGINE_FORCE].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_IMPULS_JET_ENGINE,                 INDEX_IMPULS_ENGINE_CONSUMPTION,                        (unsigned short)atol(parameters[SPEC_PTS_IMPULS_ENGINE_CONSUMPTION].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_MECHANICAL_DAMPERS,                INDEX_MECHANICAL_DAMPERS_ACCELERATION,                  (unsigned short)atol(parameters[SPEC_PTS_MECHANICAL_DAMPERS_ACCELERATION].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_DRONE_MISSILES,                    INDEX_DRONE_MISSILES_DAMAGE,                            (unsigned short)atol(parameters[SPEC_PTS_DRONE_MISSILES_DAMAGE].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_DRONE_MISSILES,                    INDEX_DRONE_MISSILES_PRECISION,                         (unsigned short)atol(parameters[SPEC_PTS_DRONE_MISSILES_PRECISION].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_DRONE_MISSILES,                    INDEX_DRONE_MISSILES_RANGE,                             (unsigned short)atol(parameters[SPEC_PTS_DRONE_MISSILES_RANGE].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_DRONE_MISSILE_LAUNCHER,            INDEX_DRONE_MISSILE_LAUNCHER_ACCUMULATOR,               (unsigned short)atol(parameters[SPEC_PTS_DRONE_MISSILE_LAUNCHER_ACCUMULATOR].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_DRONE_MISSILE_LAUNCHER,            INDEX_DRONE_MISSILE_LAUNCHER_CHARGING,                  (unsigned short)atol(parameters[SPEC_PTS_DRONE_MISSILE_LAUNCHER_CHARGING].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_SHIPS,                             INDEX_SHIPS_LEVEL,                                      (unsigned short)atol(parameters[SPEC_PTS_SHIPS_LEVEL].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_BASES,                             INDEX_BASES_LEVEL,                                      (unsigned short)atol(parameters[SPEC_PTS_BASES_LEVEL].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_HANGAR,                            INDEX_HANGARS_LEVEL,                                    (unsigned short)atol(parameters[SPEC_PTS_HANGARS_LEVEL].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_ANDROIDS,                          INDEX_ANDROIDS_LEVEL,                                   (unsigned short)atol(parameters[SPEC_PTS_ANDROIDS_LEVEL].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_ANDROIDS,                          INDEX_ANDROIDS_CONSUMPTION,                             (unsigned short)atol(parameters[SPEC_PTS_ANDROIDS_CONSUMPTION].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_ENERGETIC_ACCUMULATOR,             INDEX_ENERGETIC_ACCUMULATOR_ACCUMULATOR,                (unsigned short)atol(parameters[SPEC_PTS_ENERGETIC_ACCUMULATOR_ACCUMULATOR].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_ENERGETIC_ACCUMULATOR,             INDEX_ENERGETIC_ACCUMULATOR_CHARGING,                   (unsigned short)atol(parameters[SPEC_PTS_ENERGETIC_ACCUMULATOR_CHARGING].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_MAINFRAME,                         INDEX_MAINFRAME_BIO_NODES,                              (unsigned short)atol(parameters[SPEC_PTS_MAINFRAME_BIO_NODES].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_MAINFRAME,                         INDEX_MAINFRAME_PREDICTION,                             (unsigned short)atol(parameters[SPEC_PTS_MAINFRAME_PREDICTION].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_MAINFRAME,                         INDEX_MAINFRAME_TIME_REUSABILITY,                       (unsigned short)atol(parameters[SPEC_PTS_MAINFRAME_TIME_REUSABILITY].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_MAINFRAME,                         INDEX_MAINFRAME_CONSUMPTION,                            (unsigned short)atol(parameters[SPEC_PTS_MAINFRAME_CONSUMPTION].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_SCIENTIFIC_LAB,                    INDEX_SCIENTIFIC_LABS_LEVEL,                            (unsigned short)atol(parameters[SPEC_PTS_SCIENTIFIC_LABS_LEVEL].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_LIFE_SUPPORT,                      INDEX_LIFE_SUPPORT_CAPACITY,                            (unsigned short)atol(parameters[SPEC_PTS_LIFE_SUPPORT_CAPACITY].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_LIFE_SUPPORT,                      INDEX_LIFE_SUPPORT_CONSUMPTION,                         (unsigned short)atol(parameters[SPEC_PTS_LIFE_SUPPORT_CONSUMPTION].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_WEAPON_ENERGY_CIRCUIT,             INDEX_WEAPON_ENERGY_CIRCUIT_CHARGING,                   (unsigned short)atol(parameters[SPEC_PTS_WEAPON_ENERGY_CIRCUIT_CHARGING].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_TRANSPORT_BEAM_GENERATOR,          INDEX_TRANSPORT_BEAM_GENERATOR_ACCUMULATOR,             (unsigned short)atol(parameters[SPEC_PTS_TRANSPORT_BEAM_GENERATOR_ACCUMULATOR].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_TRANSPORT_BEAM_GENERATOR,          INDEX_TRANSPORT_BEAM_GENERATOR_CHARGING,                (unsigned short)atol(parameters[SPEC_PTS_TRANSPORT_BEAM_GENERATOR_CHARGING].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_TRANSPORT_BEAM_GENERATOR,          INDEX_TRANSPORT_BEAM_GENERATOR_FORCIBILITY,             (unsigned short)atol(parameters[SPEC_PTS_TRANSPORT_BEAM_GENERATOR_FORCIBILITY].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_TRANSPORT_BEAM_GENERATOR,          INDEX_TRANSPORT_BEAM_GENERATOR_PRECISION,               (unsigned short)atol(parameters[SPEC_PTS_TRANSPORT_BEAM_GENERATOR_PRECISION].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_TRANSPORT_BEAM_GENERATOR,          INDEX_TRANSPORT_BEAM_GENERATOR_RANGE,                   (unsigned short)atol(parameters[SPEC_PTS_TRANSPORT_BEAM_GENERATOR_RANGE].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_LASER_GUN,                         INDEX_LASER_GUN_ACCUMULATOR,                            (unsigned short)atol(parameters[SPEC_PTS_LASER_GUN_ACCUMULATOR].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_LASER_GUN,                         INDEX_LASER_GUN_CHARGING,                               (unsigned short)atol(parameters[SPEC_PTS_LASER_GUN_CHARGING].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_LASER_GUN,                         INDEX_LASER_GUN_FORCIBILITY,                            (unsigned short)atol(parameters[SPEC_PTS_LASER_GUN_FORCIBILITY].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_LASER_GUN,                         INDEX_LASER_GUN_PRECISION,                              (unsigned short)atol(parameters[SPEC_PTS_LASER_GUN_PRECISION].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_LASER_GUN,                         INDEX_LASER_GUN_RANGE,                                  (unsigned short)atol(parameters[SPEC_PTS_LASER_GUN_RANGE].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_DEFLECTOR_SHIELDS,                 INDEX_DEFLECTOR_SHIELDS_GENERATOR_SOLIDITY,             (unsigned short)atol(parameters[SPEC_PTS_DEFLECTOR_SHIELDS_GENERATOR_SOLIDITY].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_DEFLECTOR_SHIELDS,                 INDEX_DEFLECTOR_SHIELDS_GENERATOR_ACCUMULATOR,          (unsigned short)atol(parameters[SPEC_PTS_DEFLECTOR_SHIELDS_GENERATOR_ACCUMULATOR].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_DEFLECTOR_SHIELDS,                 INDEX_DEFLECTOR_SHIELDS_GENERATOR_CHARGING,             (unsigned short)atol(parameters[SPEC_PTS_DEFLECTOR_SHIELDS_GENERATOR_CHARGING].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_HIGH_RESOLUTION_SENSORS,           INDEX_HIGH_RESOLUTION_SENSORS_LEVEL,                    (unsigned short)atol(parameters[SPEC_PTS_HIGH_RESOLUTION_SENSORS_LEVEL].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_HIGH_RESOLUTION_SENSORS,           INDEX_HIGH_RESOLUTION_SENSORS_RANGE,                    (unsigned short)atol(parameters[SPEC_PTS_HIGH_RESOLUTION_SENSORS_RANGE].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_HIGH_RESOLUTION_SENSORS,           INDEX_HIGH_RESOLUTION_SENSORS_CONSUMPTION,              (unsigned short)atol(parameters[SPEC_PTS_HIGH_RESOLUTION_SENSORS_CONSUMPTION].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_LONG_RANGE_SENSORS,                INDEX_LONG_RANGE_SENSORS_LEVEL,                         (unsigned short)atol(parameters[SPEC_PTS_LONG_RANGE_SENSORS_LEVEL].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_LONG_RANGE_SENSORS,                INDEX_LONG_RANGE_SENSORS_RANGE,                         (unsigned short)atol(parameters[SPEC_PTS_LONG_RANGE_SENSORS_RANGE].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_LONG_RANGE_SENSORS,                INDEX_LONG_RANGE_SENSORS_CONSUMPTION,                   (unsigned short)atol(parameters[SPEC_PTS_LONG_RANGE_SENSORS_CONSUMPTION].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_CLOAKING_DEVICE,                   INDEX_CLOAKING_DEVICE_LEVEL,                            (unsigned short)atol(parameters[SPEC_PTS_CLOAKING_DEVICE_LEVEL].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_CLOAKING_DEVICE,                   INDEX_CLOAKING_DEVICE_CONSUMPTION,                      (unsigned short)atol(parameters[SPEC_PTS_CLOAKING_DEVICE_CONSUMPTION].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_PROBE,                             INDEX_PROBE_DEVICE_LEVEL,                               (unsigned short)atol(parameters[SPEC_PTS_PROBE_DEVICE_LEVEL].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_MAGNETICAL_FILTER,                 INDEX_MAGNETICAL_FILTER_PRODUCTION,                     (unsigned short)atol(parameters[SPEC_PTS_MAGNETICAL_FILTER_PRODUCTION].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_DEUTERIUM_DECOMPOSER,              INDEX_DEUTERIUM_DECOMPOSER_PRODUCTION,                  (unsigned short)atol(parameters[SPEC_PTS_DEUTERIUM_DECOMPOSER_PRODUCTION].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_DEUTERIUM_DECOMPOSER,              INDEX_DEUTERIUM_DECOMPOSER_METAMORPHOSIS,               (unsigned short)atol(parameters[SPEC_PTS_DEUTERIUM_DECOMPOSER_METAMORPHOSIS].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_ZIRCONIUM_REACTOR,                 INDEX_ZIRCONIUM_REACTOR_PRODUCTION,                     (unsigned short)atol(parameters[SPEC_PTS_ZIRCONIUM_REACTOR_PRODUCTION].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_ZIRCONIUM_REACTOR,                 INDEX_ZIRCONIUM_REACTOR_METAMORPHOSIS,                  (unsigned short)atol(parameters[SPEC_PTS_ZIRCONIUM_REACTOR_METAMORPHOSIS].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_ILMENITE_FURNACE,                  INDEX_ILMENITE_FURNACE_PRODUCTION,                      (unsigned short)atol(parameters[SPEC_PTS_ILMENITE_FURNACE_PRODUCTION].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_ILMENITE_FURNACE,                  INDEX_ILMENITE_FURNACE_METAMORPHOSIS,                   (unsigned short)atol(parameters[SPEC_PTS_ILMENITE_FURNACE_METAMORPHOSIS].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_MAGNETICAL_COLLECTORS_OF_PLASMA,   INDEX_MAGNETICAL_COLLECTORS_OF_PLASMA_WINDING_SPEED,    (unsigned short)atol(parameters[SPEC_PTS_MAGNETICAL_COLLECTORS_OF_PLASMA_WINDING_SPEED].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_SUBMERSIBLE_FILTRATION_TANK,       INDEX_SUBMERSIBLE_FILTRATION_TANK_WINDING_SPEED,        (unsigned short)atol(parameters[SPEC_PTS_SUBMERSIBLE_FILTRATION_TANK_WINDING_SPEED].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_SUBMERSIBLE_FILTRATION_TANK,       INDEX_SUBMERSIBLE_FILTRATION_TANK_RANGE,                (unsigned short)atol(parameters[SPEC_PTS_SUBMERSIBLE_FILTRATION_TANK_RANGE].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_SUBMARINE_MINING_MACHINE,          INDEX_SUBMARINE_MINING_MACHINE_WINDING_SPEED,           (unsigned short)atol(parameters[SPEC_PTS_SUBMARINE_MINING_MACHINE_WINDING_SPEED].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_SUBMARINE_MINING_MACHINE,          INDEX_SUBMARINE_MINING_MACHINE_RANGE,                   (unsigned short)atol(parameters[SPEC_PTS_SUBMARINE_MINING_MACHINE_RANGE].c_str()));

        sc->setSpecLeafTokens(SCIENCE_ENTITY_UNDERGROUND_DRILLING_MACHINE,      INDEX_UNDERGROUND_DRILLING_MACHINE_WINDING_SPEED,       (unsigned short)atol(parameters[SPEC_PTS_UNDERGROUND_DRILLING_MACHINE_WINDING_SPEED].c_str()));
        sc->setSpecLeafTokens(SCIENCE_ENTITY_UNDERGROUND_DRILLING_MACHINE,      INDEX_UNDERGROUND_DRILLING_MACHINE_RANGE,               (unsigned short)atol(parameters[SPEC_PTS_UNDERGROUND_DRILLING_MACHINE_RANGE].c_str()));

        /* posleme vedu */
        gctx.sendToClient(cl, answerWriter :: science_change(sc));
    }
    else
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) cl.first);
        gctx.sendToClient(cl, answerWriter :: science_change_ie());
        return cl;
    }

    return cl;
}

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

id request_update_ship_central_information(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    dtIdentifier fortressid = strtoul(parameters[REQUEST_SHIP_CENTRAL_INFORMATION_SHIPID].c_str(), NULL, 0);
    fortressClass* fortress = actx->cacheFortressesList.getItem<fortressClass>(fortressid);

    /* pokud pevnost neexistuje, vrat chybu */
    if (fortress == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: ship_central_information_FAIL(fortressid, REQUEST_SHIP_CENTRAL_INFORMATION_ANSWER_SHIPNE));  
        return cl;
    }

    /* pokud pevnost hraci nepatri, vrat chybu */
    if (fortress->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: ship_central_information_FAIL(fortressid, REQUEST_SHIP_CENTRAL_INFORMATION_ANSWER_SHIPNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!fortress->isControllable())
    {
        gctx.sendToClient(cl, answerWriter :: ship_central_information_FAIL(fortressid, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

    gctx.sendToClient(cl, answerWriter :: ship_central_information(fortress));

    return cl;
}

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

id request_update_fortress_shields_information(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    dtIdentifier fortressid = strtoul(parameters[REQUEST_FORTRESS_SHIELDS_INFORMATION_FORTRESSID].c_str(), NULL, 0);
    fortressClass* fortress = actx->cacheFortressesList.getItem<fortressClass>(fortressid);

    /* pokud lod neexistuje, vrat chybu */
    if (fortress == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: fortress_shields_information_FAIL(fortressid, REQUEST_FORTRESS_SHIELDS_INFORMATION_ANSWER_FORTRESSNE));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (fortress->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: fortress_shields_information_FAIL(fortressid, REQUEST_FORTRESS_SHIELDS_INFORMATION_ANSWER_FORTRESSNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!fortress->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: fortress_shields_information_FAIL(fortressid, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

    gctx.sendToClient(cl, answerWriter :: fortress_shields_information(fortress));

    return cl;
}

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

id request_update_ship_subspace_drive_information(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    dtIdentifier shipid = strtoul(parameters[REQUEST_SHIP_SUBSPACE_DRIVE_INFORMATION_SHIPID].c_str(), NULL, 0);
    shipClass* ship = actx->cacheFortressesList.getItem<shipClass>(shipid);

    /* pokud lod neexistuje, vrat chybu */
    if (ship == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: ship_subspace_drive_information_FAIL(shipid, REQUEST_SHIP_SUBSPACE_DRIVE_INFORMATION_ANSWER_SHIPNE));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (ship->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: ship_subspace_drive_information_FAIL(shipid, REQUEST_SHIP_SUBSPACE_DRIVE_INFORMATION_ANSWER_SHIPNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!ship->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: ship_subspace_drive_information_FAIL(shipid, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

    subspace_drive_status sds;
    sds.actualConsumption                       = ship->subspaceDrive.actualConsumption();
    sds.actualSpeedToC                          = ship->subspaceDrive.actualSpeedToC();
    sds.inertial_dampers_max_speed              = ship->subspaceDrive.inertialDampers()->actualMaxSpeedToC();
    sds.inertial_dampers_status                 = ship->subspaceDrive.inertialDampers()->getStatus();
	sds.inertial_dampers_available 				= ship->subspaceDrive.inertialDampers()->getCount() > 0;
    sds.navigation_computer_max_speed           = ship->subspaceDrive.navigationComputer()->actualMaxSpeedToC();
    sds.navigation_computer_status              = ship->subspaceDrive.navigationComputer()->getStatus();
	sds.navigation_computer_available			= ship->subspaceDrive.navigationComputer()->getCount() > 0;
    sds.subspace_beacon_max_speed               = ship->subspaceDrive.subspaceBeacon()->actualMaxSpeedToC();
    sds.subspace_beacon_status                  = ship->subspaceDrive.subspaceBeacon()->getStatus();
	sds.subspace_beacon_available               = ship->subspaceDrive.subspaceBeacon()->getCount() > 0;
    sds.quark_gluon_core_consumption            = ship->subspaceDrive.quarkGluonCore()->actualConsumption();
    sds.quark_gluon_core_max_speed              = ship->subspaceDrive.quarkGluonCore()->actualMaxSpeedToC();
    sds.quark_gluon_core_status                 = ship->subspaceDrive.quarkGluonCore()->getStatus();
	sds.quark_gluon_core_available              = ship->subspaceDrive.quarkGluonCore()->getCount() > 0;

    gctx.sendToClient(cl, answerWriter :: ship_subspace_drive_information(shipid, sds));

    return cl;
}

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

id request_update_ship_impulse_drive_information(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    dtIdentifier shipid = strtoul(parameters[REQUEST_SHIP_IMPULSE_DRIVE_INFORMATION_SHIPID].c_str(), NULL, 0);
    shipClass* ship = actx->cacheFortressesList.getItem<shipClass>(shipid);

    /* pokud lod neexistuje, vrat chybu */
    if (ship == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: ship_impulse_drive_information_FAIL(shipid, REQUEST_SHIP_IMPULSE_DRIVE_INFORMATION_ANSWER_SHIPNE));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (ship->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: ship_impulse_drive_information_FAIL(shipid, REQUEST_SHIP_IMPULSE_DRIVE_INFORMATION_ANSWER_SHIPNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!ship->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: ship_impulse_drive_information_FAIL(shipid, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

    impulse_drive_status sds;
    sds.actualConsumption                           = ship->impulsDrive.actualConsumption();
    sds.actualJetForce                              = ship->impulsDrive.getActualJetForce();
    sds.impulse_jet_engine_actual_consumption       = ship->impulsDrive.impulsJetEngine()->actualConsumption();
    sds.impulse_jet_engine_actual_force             = ship->impulsDrive.impulsJetEngine()->actualForceInGN() * GIGA;
    sds.impulse_jet_engine_status                   = ship->impulsDrive.impulsJetEngine()->getStatus();
	sds.impulse_jet_engine_available 				= ship->impulsDrive.impulsJetEngine()->getCount() > 0;
    sds.mechanical_dampers_max_acceleration         = ship->impulsDrive.mechanicalDampers()->actualMaxAcceleration();
    sds.mechanical_dampers_status                   = ship->impulsDrive.mechanicalDampers()->getStatus();
	sds.mechanical_dampers_available 				= ship->impulsDrive.mechanicalDampers()->getCount() > 0;	

    gctx.sendToClient(cl, answerWriter :: ship_impulse_drive_information(shipid, sds));

    return cl;
}

void write_weapons_status(fortressClass * fortress, weapons_status & ws) 
{
    ws.drone_missiles_actual_damage             = fortress->weapons.droneMissiles()->actualDamage(fortress->getFortressRealmID());
    ws.drone_missiles_actual_launch             = fortress->weapons.droneMissiles()->actualLaunch(fortress->getFortressRealmID());
    ws.drone_missiles_actual_precision          = fortress->weapons.droneMissiles()->actualPrecision(fortress->getFortressRealmID());
    ws.drone_missiles_actual_range              = fortress->weapons.droneMissiles()->actualRange(fortress->getFortressRealmID());
    ws.drone_missiles_count                     = fortress->weapons.droneMissiles()->getCount();
    ws.drone_missiles_damaged                   = fortress->weapons.droneMissiles()->getDamaged();
    ws.drone_missiles_working                   = fortress->weapons.droneMissiles()->getWorking();

    ws.weapon_actual_energy_consumption         = fortress->weapons.getActualEnergyConsumption();
	dist_t distance;
	if (fortress->weapons.getDistanceToTheWeaponsTarget(fortress, distance))
	{
		ws.weapon_distance_to_the_weapons_target= ullUpRound(distance);
	}
	else
	{
		ws.weapon_distance_to_the_weapons_target= 0;
	}
    ws.weapon_energy_circuit_charging           = fortress->weapons.weaponEnergyCircuit()->actualCharging();
	ws.weapon_energy_circuit_client_charging	= fortress->weapons.weaponEnergyCircuit()->clientCharging();
    ws.weapon_energy_circuit_status             = fortress->weapons.weaponEnergyCircuit()->getStatus();
    ws.weapon_total_charging                    = fortress->weapons.getTotalWeaponsCharging(fortress, NULL);

	ws.avalWeaponEnergyCircuit = fortress->weapons.weaponEnergyCircuit()->getCount() > 0;
	ws.avalDroneMissiles = fortress->weapons.droneMissiles()->getCount() > 0;

	weaponIDGradientMap gradientMap;
	fortress->weapons.getGradients(fortress, &gradientMap);

	weaponIDEnergyMap energyMap;
	fortress->weapons.getEnergies(fortress, &gradientMap, &energyMap);

    /* posleme launchery dronich strel */
    for (unsigned long i = 0; i < fortress->weapons.getDroneMissileLaunchersCount(); i++)
    {
        droneMissileLauncherPEnergyStatePPair lp = fortress->weapons.droneMissileLaunchers(i);

        drone_missile_launcher_status ls;
        ls.actualAccumulator    = lp.first->actualAccumulator();
        ls.status               = lp.first->getStatus();		
        ls.targetEnergy         = lp.second->targetEnergy;
        ls.index                = i;
		ls.id					= lp.first->getID();
		ls.energy               = energyMap[ls.id];
		ls.gradient				= gradientMap[ls.id];

        ws.drone_missile_launchers.push_back(ls);
    }

    /* posleme laserove zbrane */
    for (unsigned long i = 0; i < fortress->weapons.getLaserGunsCount(); i++)
    {
        laserGunPEnergyStatePPair lg = fortress->weapons.laserGuns(i);

        laser_gun_status ls;
        ls.actualAccumulator    = lg.first->actualAccumulator();
        ls.actualForcibility    = lg.first->actualForcibility();
        ls.actualPrecision      = lg.first->actualPrecision();
        ls.actualRange          = lg.first->actualRange();
        ls.status               = lg.first->getStatus();
		ls.id					= lg.first->getID();		
        ls.targetEnergy         = lg.second->targetEnergy;
        ls.index                = i;		
		ls.energy               = energyMap[ls.id];
		ls.gradient				= gradientMap[ls.id];

        ws.laser_guns.push_back(ls);
    }

	fortressClassClass * fortressClazz = fortress->getFortressClass();

	if (fortressClazz == NULL) {
		errExceptionError("No fortress class class of fortress %u", (unsigned long long) fortress->getID());
		return;
	}

	ws.max_laser_guns = fortressClazz->getMaxLaserGuns();
	ws.max_drone_missile_launchers = fortressClazz->getMaxDroneMissileLaunchers();
}

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

id request_update_fortress_weapons_information(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    dtIdentifier fortressid = strtoul(parameters[REQUEST_FORTRESS_WEAPONS_INFORMATION_FORTRESSID].c_str(), NULL, 0);
    fortressClass* fortress = actx->cacheFortressesList.getItem<fortressClass>(fortressid);

    /* pokud lod neexistuje, vrat chybu */
    if (fortress == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: fortress_weapons_information_FAIL(fortressid, REQUEST_FORTRESS_WEAPONS_INFORMATION_ANSWER_FORTRESSNE));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (fortress->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: fortress_weapons_information_FAIL(fortressid, REQUEST_FORTRESS_WEAPONS_INFORMATION_ANSWER_FORTRESSNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!fortress->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: fortress_weapons_information_FAIL(fortressid, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

    weapons_status ws;
	write_weapons_status(fortress, ws);

	gctx.sendToClient(cl, answerWriter :: fortress_weapons_information(fortressid, ws));

    return cl;
}

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

id request_update_fortress_weapons_set(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    dtIdentifier fortressid = strtoul(parameters[REQUEST_FORTRESS_WEAPONS_SET_FORTRESSID].c_str(), NULL, 0);
    fortressClass* fortress = actx->cacheFortressesList.getItem<fortressClass>(fortressid);

    /* pokud lod neexistuje, vrat chybu */
    if (fortress == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: fortress_weapons_set_FAIL(fortressid, REQUEST_FORTRESS_WEAPONS_INFORMATION_ANSWER_FORTRESSNE));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (fortress->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: fortress_weapons_set_FAIL(fortressid, REQUEST_FORTRESS_WEAPONS_INFORMATION_ANSWER_FORTRESSNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!fortress->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: fortress_weapons_set_FAIL(fortressid, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

    /* nastavime parametry dronich strel */
    for (unsigned long i = 0; i < fortress->weapons.getDroneMissileLaunchersCount(); i++)
    {
        std :: stringstream ss;

		ss << REQUEST_FORTRESS_WEAPONS_LAUNCHER_IS_SET << i;
		bool isSet = atoi(parameters[ss.str()].c_str()) == 1 ? true : false;

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

		if (isSet) {
			ss << REQUEST_FORTRESS_WEAPONS_LAUNCHER_PREFIX << i;
			fortress->weapons.droneMissileLaunchers(i).second->targetEnergy = _atoi64(parameters[ss.str()].c_str());
		}
    }

    /* nastavime laserove zbrane */
    for (unsigned long i = 0; i < fortress->weapons.getLaserGunsCount(); i++)
    {		
        std :: stringstream ss;

		ss << REQUEST_FORTRESS_WEAPONS_LASER_IS_SET << i;
		bool isSet = atoi(parameters[ss.str()].c_str()) == 1 ? true : false;

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

		if (isSet) {
			ss << REQUEST_FORTRESS_WEAPONS_LASER_PREFIX << i;
			fortress->weapons.laserGuns(i).second->targetEnergy = _atoi64(parameters[ss.str()].c_str());
		}
    }

    weapons_status ws;
    write_weapons_status(fortress, ws);


    gctx.sendToClient(cl, answerWriter :: fortress_weapons_set(fortressid, ws));

    return cl;
}

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

id request_update_fortress_mainframe_information(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    dtIdentifier fortressid = strtoul(parameters[REQUEST_FORTRESS_MAINFRAME_INFORMATION_FORTRESSID].c_str(), NULL, 0);
    fortressClass* fortress = actx->cacheFortressesList.getItem<fortressClass>(fortressid);

    /* pokud lod neexistuje, vrat chybu */
    if (fortress == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: fortress_mainframe_information_FAIL(fortressid, REQUEST_FORTRESS_MAINFRAME_INFORMATION_ANSWER_FORTRESSNE));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (fortress->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: fortress_mainframe_information_FAIL(fortressid, REQUEST_FORTRESS_MAINFRAME_INFORMATION_ANSWER_FORTRESSNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!fortress->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: fortress_mainframe_information_FAIL(fortressid, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

    mainframe_status ms;
    ms.actualBioNodes           = fortress->mainframeSystem.mainframe()->actualBioNodes();
    ms.actualConsumption        = fortress->mainframeSystem.mainframe()->actualConsumption();
    ms.actualPrediction         = fortress->mainframeSystem.mainframe()->actualPrediction();
    ms.actualTimeReusability    = fortress->mainframeSystem.mainframe()->actualTimeReusability();
    ms.status                   = fortress->mainframeSystem.mainframe()->getStatus();

    gctx.sendToClient(cl, answerWriter :: fortress_mainframe_information(fortressid, ms));

    return cl;
}

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

id request_update_fortress_crew_information(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    dtIdentifier fortressid = strtoul(parameters[REQUEST_FORTRESS_CREW_INFORMATION_FORTRESSID].c_str(), NULL, 0);
    fortressClass* fortress = actx->cacheFortressesList.getItem<fortressClass>(fortressid);

    /* pokud lod neexistuje, vrat chybu */
    if (fortress == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: fortress_crew_information_FAIL(fortressid, REQUEST_FORTRESS_CREW_INFORMATION_ANSWER_FORTRESSNE));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (fortress->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: fortress_crew_information_FAIL(fortressid, REQUEST_FORTRESS_CREW_INFORMATION_ANSWER_FORTRESSNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!fortress->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: fortress_crew_information_FAIL(fortressid, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

    crew_status cs;
    cs.ABLE_CREW_CAPITAN            = fortress->crew.getAblesCountOf(CREW_CAPITAN);
    cs.ABLE_CREW_DOCTOR             = fortress->crew.getAblesCountOf(CREW_DOCTOR);
    cs.ABLE_CREW_ENGINEER           = fortress->crew.getAblesCountOf(CREW_ENGINEER);
    cs.ABLE_CREW_OFFICER            = fortress->crew.getAblesCountOf(CREW_OFFICER);
    cs.ABLE_CREW_PASSENGER          = fortress->crew.getAblesCountOf(CREW_PASSENGER);
    cs.ABLE_CREW_PILOT              = fortress->crew.getAblesCountOf(CREW_PILOT);
    cs.ABLE_CREW_SCIENTIST          = fortress->crew.getAblesCountOf(CREW_SCIENTIST);

    cs.WOUNDED_CREW_CAPITAN         = fortress->crew.getWoundedCountOf(CREW_CAPITAN);
    cs.WOUNDED_CREW_DOCTOR          = fortress->crew.getWoundedCountOf(CREW_DOCTOR);
    cs.WOUNDED_CREW_ENGINEER        = fortress->crew.getWoundedCountOf(CREW_ENGINEER);
    cs.WOUNDED_CREW_OFFICER         = fortress->crew.getWoundedCountOf(CREW_OFFICER);
    cs.WOUNDED_CREW_PASSENGER       = fortress->crew.getWoundedCountOf(CREW_PASSENGER);
    cs.WOUNDED_CREW_PILOT           = fortress->crew.getWoundedCountOf(CREW_PILOT);
    cs.WOUNDED_CREW_SCIENTIST       = fortress->crew.getWoundedCountOf(CREW_SCIENTIST);

    cs.TOTAL_CREW_CAPITAN           = fortress->crew.getTotalCountOf(CREW_CAPITAN);
    cs.TOTAL_CREW_DOCTOR            = fortress->crew.getTotalCountOf(CREW_DOCTOR);
    cs.TOTAL_CREW_ENGINEER          = fortress->crew.getTotalCountOf(CREW_ENGINEER);
    cs.TOTAL_CREW_OFFICER           = fortress->crew.getTotalCountOf(CREW_OFFICER);
    cs.TOTAL_CREW_PASSENGER         = fortress->crew.getTotalCountOf(CREW_PASSENGER);
    cs.TOTAL_CREW_PILOT             = fortress->crew.getTotalCountOf(CREW_PILOT);
    cs.TOTAL_CREW_SCIENTIST         = fortress->crew.getTotalCountOf(CREW_SCIENTIST);

    cs.ACT_PEOPLE_WEIGHT            = PEOPLE_WEIGHT;

    gctx.sendToClient(cl, answerWriter :: fortress_crew_information(fortressid, cs));

    return cl;
}

void write_quarry_status(fortressClass * fortress, quarry_status & cs) 
{
    cs.QuarkGluonPlasmaQuarryingSpeed                   = fortress->miningDevices.getQuarkGluonPlasmaQuarrying();
    cs.HeavyWaterQuarryingSpeed                         = fortress->miningDevices.getHeavyWaterQuarrying();
    cs.ZirconiumCrystalQuarryingSpeed                   = fortress->miningDevices.getZirconiumCrystalQuarrying();
    cs.IlmeniteQuarryingSpeed                           = fortress->miningDevices.getIlmeniteQuarrying();

    cs.isPossibleToQuarryQuarkGluonPlasma               = fortress->isPossibleToQuarryQGP();
    cs.isPossibleToQuarryHeavyWater                     = fortress->isPossibleToQuarryHeW();
    cs.isPossibleToQuarryZirconiumCrystals              = fortress->isPossibleToQuarryZrC();
    cs.isPossibleToQuarryIlmenite                       = fortress->isPossibleToQuarryIlm();

    cs.isActuallyQuarryingQuarkGluonPlasma              = fortress->miningDevices.isActuallyQuarkGluonPlasmaQuarrying();
    cs.isActuallyQuarryingHeavyWater                    = fortress->miningDevices.isActuallyHeavyWaterQuarrying();
    cs.isActuallyQuarryingZirconiumCrystals             = fortress->miningDevices.isActuallyZirconiumCrystalQuarrying();
    cs.isActuallyQuarryingIlmenite                      = fortress->miningDevices.isActuallyIlmeniteQuarrying();

    cs.HeavyWaterQuarryingCount                         = fortress->miningDevices.submersibleFiltrationTank()->getCount();
    cs.IlmeniteQuarryingCount                           = fortress->miningDevices.undergroundDrillingMachine()->getCount();
    cs.QuarkGluonPlasmaQuarryingCount                   = fortress->miningDevices.magneticalCollectorsOfPlasma()->getCount();
    cs.ZirconiumCrystalQuarryingCount                   = fortress->miningDevices.submarineMiningMachine()->getCount();

    cs.HeavyWaterQuarryingActualRange                   = fortress->miningDevices.submersibleFiltrationTank()->actualRange(fortress->getFortressRealmID());
    cs.IlmeniteQuarryingActualRange                     = fortress->miningDevices.undergroundDrillingMachine()->actualRange(fortress->getFortressRealmID());
    cs.QuarkGluonPlasmaQuarryingActualRange             = fortress->miningDevices.magneticalCollectorsOfPlasma()->actualRange(fortress->getFortressRealmID());
    cs.ZirconiumCrystalQuarryingActualRange             = fortress->miningDevices.submarineMiningMachine()->actualRange(fortress->getFortressRealmID());

    cs.HeavyWaterQuarryingActualMaximalSpeed            = fortress->miningDevices.submersibleFiltrationTank()->actualTotalWindingSpeed(fortress->getFortressRealmID());
    cs.IlmeniteQuarryingActualMaximalSpeed              = fortress->miningDevices.undergroundDrillingMachine()->actualTotalWindingSpeedInGrams(fortress->getFortressRealmID());
    cs.QuarkGluonPlasmaQuarryingActualMaximalSpeed      = fortress->miningDevices.magneticalCollectorsOfPlasma()->actualTotalWindingSpeedInMilligrams(fortress->getFortressRealmID());
    cs.ZirconiumCrystalQuarryingActualMaximalSpeed      = fortress->miningDevices.submarineMiningMachine()->actualTotalWindingSpeedInGrams(fortress->getFortressRealmID());

    cs.HeavyWaterQuarryingWorking                       = fortress->miningDevices.submersibleFiltrationTank()->getWorking();
    cs.IlmeniteQuarryingWorking                         = fortress->miningDevices.undergroundDrillingMachine()->getWorking();
    cs.QuarkGluonPlasmaQuarryingWorking                 = fortress->miningDevices.magneticalCollectorsOfPlasma()->getWorking();
    cs.ZirconiumCrystalQuarryingWorking                 = fortress->miningDevices.submarineMiningMachine()->getWorking();

    cs.HeavyWaterQuarryingDamaged                       = fortress->miningDevices.submersibleFiltrationTank()->getDamaged();
    cs.IlmeniteQuarryingDamaged                         = fortress->miningDevices.undergroundDrillingMachine()->getDamaged();
    cs.QuarkGluonPlasmaQuarryingDamaged                 = fortress->miningDevices.magneticalCollectorsOfPlasma()->getDamaged();
    cs.ZirconiumCrystalQuarryingDamaged                 = fortress->miningDevices.submarineMiningMachine()->getDamaged();

	cs.avalSubmersibleFiltrationTank					= fortress->miningDevices.submersibleFiltrationTank()->getCount() > 0;
	cs.avalUndergroundDrillingMachine					= fortress->miningDevices.undergroundDrillingMachine()->getCount() > 0;
	cs.avalMagneticalCollectorsOfPlasma					= fortress->miningDevices.magneticalCollectorsOfPlasma()->getCount() > 0;
	cs.avalSubmarineMiningMachine						= fortress->miningDevices.submarineMiningMachine()->getCount() > 0;
}

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

id request_update_fortress_quarry_information(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    dtIdentifier fortressid = strtoul(parameters[REQUEST_FORTRESS_QUARRY_INFORMATION_FORTRESSID].c_str(), NULL, 0);
    fortressClass* fortress = actx->cacheFortressesList.getItem<fortressClass>(fortressid);

    /* pokud lod neexistuje, vrat chybu */
    if (fortress == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: fortress_quarry_information_FAIL(fortressid, REQUEST_FORTRESS_QUARRY_INFORMATION_ANSWER_FORTRESSNE));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (fortress->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: fortress_quarry_information_FAIL(fortressid, REQUEST_FORTRESS_QUARRY_INFORMATION_ANSWER_FORTRESSNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!fortress->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: fortress_quarry_information_FAIL(fortressid, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

    quarry_status cs;
	write_quarry_status(fortress, cs);

    gctx.sendToClient(cl, answerWriter :: fortress_quarry_information(fortressid, cs));

    return cl;
}

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

id request_fortress_quarry_change_state(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    dtIdentifier fortressid = strtoul(parameters[REQUEST_FORTRESS_QUARRY_CHANGE_STATE_FORTRESS_ID].c_str(), NULL, 0);
    fortressClass* fortress = actx->cacheFortressesList.getItem<fortressClass>(fortressid);

    /* pokud lod neexistuje, vrat chybu */
    if (fortress == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: fortress_quarry_change_state_FAIL(fortressid, REQUEST_FORTRESS_QUARRY_CHANGE_STATE_ANSWER_FORTRESSNE));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (fortress->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: fortress_quarry_change_state_FAIL(fortressid, REQUEST_FORTRESS_QUARRY_CHANGE_STATE_ANSWER_FORTRESSNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!fortress->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: fortress_quarry_change_state_FAIL(fortressid, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

    protQuarryType pqt   = (protQuarryType)atoi(parameters[REQUEST_FORTRESS_QUARRY_CHANGE_STATE_PQ_TYPE].c_str());
    bool        newState = atoi(parameters[REQUEST_FORTRESS_QUARRY_CHANGE_STATE_NEW_STATE].c_str()) != 0;

    switch (pqt)
    {
    case PQT_All:
        if (newState)
        {
            // zacneme tezit vse
            fortress->startQuarryQuarkGluonPlasma();
            fortress->startQuarryHeavyWater();
            fortress->startQuarryZirconiumCrystal();
            fortress->startQuarryIlmenite();
        }
        else
        {
            // stopneme tezit vse
            fortress->stopAllQuarrying();
        }
        break;
    case PQT_QuarkGluonPlasma:
        if (newState)
        {
            // zacneme tezit prislusnou surovinu
            fortress->startQuarryQuarkGluonPlasma();
        }
        else
        {
            // prestaneme tezit prislusnou surovinu
            fortress->stopQuarryQuarkGluonPlasma();
        }
        break;
    case PQT_HeavyWater:
        if (newState)
        {
            // zacneme tezit prislusnou surovinu
            fortress->startQuarryHeavyWater();
        }
        else
        {
            // prestaneme tezit prislusnou surovinu
            fortress->stopQuarryHeavyWater();
        }
        break;
    case PQT_ZirconiumCrystal:
        if (newState)
        {
            // zacneme tezit prislusnou surovinu
            fortress->startQuarryZirconiumCrystal();
        }
        else
        {
            // prestaneme tezit prislusnou surovinu
            fortress->stopQuarryZirconiumCrystal();
        }
        break;
    case PQT_Ilmenite:
        if (newState)
        {
            // zacneme tezit prislusnou surovinu
            fortress->startQuarryIlmenite();
        }
        else
        {
            // prestaneme tezit prislusnou surovinu
            fortress->stopQuarryIlmenite();
        }
        break;
    default:
        gctx.sendToClient(cl, answerWriter :: fortress_quarry_change_state_FAIL(fortressid, REQUEST_FORTRESS_QUARRY_CHANGE_STATE_ANSWER_BAD_TYPE));
        return cl;
    };

    quarry_status cs;
	write_quarry_status(fortress, cs);

    gctx.sendToClient(cl, answerWriter :: fortress_quarry_information(fortressid, cs));

    return cl;
}

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

id request_update_fortress_accommodations_information(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    dtIdentifier fortressid = strtoul(parameters[REQUEST_FORTRESS_ACCOMMODATIONS_INFORMATION_FORTRESSID].c_str(), NULL, 0);
    fortressClass* fortress = actx->cacheFortressesList.getItem<fortressClass>(fortressid);

    /* pokud lod neexistuje, vrat chybu */
    if (fortress == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: fortress_accommodations_information_FAIL(fortressid, REQUEST_FORTRESS_ACCOMMODATIONS_INFORMATION_ANSWER_FORTRESSNE));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (fortress->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: fortress_accommodations_information_FAIL(fortressid, REQUEST_FORTRESS_ACCOMMODATIONS_INFORMATION_ANSWER_FORTRESSNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!fortress->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: fortress_accommodations_information_FAIL(fortressid, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

	accommodation_status status;
	
	status.accommodationsSize = fortress->accommodations.getAccomodationsSize();
	status.accommodationsWeight = fortress->accommodations.getAccomodationsWeight();
	status.comfortableRoomsCount = fortress->accommodations.getComfortableRooms();
	status.commonCabinsCount = fortress->accommodations.getCommonCabins();
	status.luxuryAccommodationsCount = fortress->accommodations.getLuxuryApartments();
	status.warehousesWithLifeSupportCount = fortress->accommodations.getWarehousesWithLifeSupport();

	fortress->accommodations.getFreeAccomodationUnits(fortress, status.freeLuxuryAccommodations, status.freeComfortableRooms, status.freeCommonCabins,status.freeWarehousesWithLifeSupport, false);

	status.comfortableRoomsPrice = POINTS_FOR_ROOM;
	status.commonCabinsPrice = POINTS_FOR_CABIN;
	status.luxuryAccommodationsPrice = POINTS_FOR_APARTMENT;
	status.warehousesWithLifeSupportPrice = POINTS_FOR_WAREHOUSE;

	status.totalPoints = fortress->getFortressClass()->getAccomodationPointsTotal();
	status.consumedPoints = fortress->accommodations.getConsumedPoints();

    gctx.sendToClient(cl, answerWriter :: fortress_accommodations_information(fortressid, status));

    return cl;
}

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

id request_fortress_add_accommodations(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

	dtIdentifier fortressid = strtoul(parameters[REQUEST_FORTRESS_ADD_ACCOMMODATIONS_FORTRESS_ID].c_str(), NULL, 0);
    fortressClass* fortress = actx->cacheFortressesList.getItem<fortressClass>(fortressid);

    /* pokud lod neexistuje, vrat chybu */
    if (fortress == NULL)
    {
		gctx.sendToClient(cl, answerWriter :: fortress_add_accommodations_FAIL(fortressid, REQUEST_FORTRESS_ADD_ACCOMMODATIONS_ANSWER_FORTRESSNE)); 
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (fortress->getFortressRealmID() != cl.first)
    {
		gctx.sendToClient(cl, answerWriter :: fortress_add_accommodations_FAIL(fortressid, REQUEST_FORTRESS_ADD_ACCOMMODATIONS_ANSWER_FORTRESSNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!fortress->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: fortress_add_accommodations_FAIL(fortressid, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

	accommodation_type accommodationType = (accommodation_type) strtoul(parameters[REQUEST_FORTRESS_ADD_ACCOMMODATIONS_ACCOMMODATION_TYPE].c_str(), NULL, 0);
	unsigned long count = strtoul(parameters[REQUEST_FORTRESS_ADD_ACCOMMODATIONS_ACCOMMODATION_COUNT].c_str(), NULL, 0);

	switch (accommodationType) {
	case ACCOMMODATION_COMFORTABLE_ROOM:
		fortress->accommodations.addComfortableRooms(fortress, count);
		break;
	case ACCOMMODATION_COMMON_CABIN:
		fortress->accommodations.addCommonCabins(fortress, count);
		break;
	case ACCOMMODATION_LUXURY_APPARTEMENT:
		fortress->accommodations.addLuxuryApartments(fortress, count);
		break;
	case ACCOMMODATION_WAREHOUSE_WITH_LIFE_SUPPORT:
		fortress->accommodations.addWarehousesWithLifeSupport(fortress, count);
		break;
	}
	
    gctx.sendToClient(cl, answerWriter :: fortress_add_accommodations(fortressid, count, accommodationType));

    return cl;
}

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

id request_fortress_add_crew(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	dtIdentifier fortressid = strtoul(parameters[REQUEST_FORTRESS_ADD_CREW_FORTRESS_ID].c_str(), NULL, 0);
    fortressClass* fortress = actx->cacheFortressesList.getItem<fortressClass>(fortressid);

    /* pokud lod neexistuje, vrat chybu */
    if (fortress == NULL)
    {
		gctx.sendToClient(cl, answerWriter :: fortress_add_crew_FAIL(fortressid, REQUEST_FORTRESS_ADD_CREW_ANSWER_FORTRESSNE)); 
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (fortress->getFortressRealmID() != cl.first)
    {
		gctx.sendToClient(cl, answerWriter :: fortress_add_crew_FAIL(fortressid, REQUEST_FORTRESS_ADD_CREW_ANSWER_FORTRESSNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!fortress->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: fortress_add_crew_FAIL(fortressid, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

	crew_type crewType = (crew_type) strtoul(parameters[REQUEST_FORTRESS_ADD_CREW_CREW_TYPE].c_str(), NULL, 0);
	unsigned long ableCount = strtoul(parameters[REQUEST_FORTRESS_ADD_CREW_ABLE_COUNT].c_str(), NULL, 0);
	unsigned long woundedCount = strtoul(parameters[REQUEST_FORTRESS_ADD_CREW_WOUNDED_COUNT].c_str(), NULL, 0);

	switch (crewType) {
	case CREW_TYPE_CAPTAIN:
		fortress->crew.acceptSomeNewAbles(fortress, CREW_CAPITAN, ableCount);
		fortress->crew.acceptSomeNewWounded(fortress, CREW_CAPITAN, woundedCount);
		break;
	case CREW_TYPE_OFFICERS:
		fortress->crew.acceptSomeNewAbles(fortress, CREW_OFFICER, ableCount);
		fortress->crew.acceptSomeNewWounded(fortress, CREW_OFFICER, woundedCount);
		break;
	case CREW_TYPE_ENGINEERS:
		fortress->crew.acceptSomeNewAbles(fortress, CREW_ENGINEER, ableCount);
		fortress->crew.acceptSomeNewWounded(fortress, CREW_ENGINEER, woundedCount);
		break;
	case CREW_TYPE_SCIENTISTS:
		fortress->crew.acceptSomeNewAbles(fortress, CREW_SCIENTIST, ableCount);
		fortress->crew.acceptSomeNewWounded(fortress, CREW_SCIENTIST, woundedCount);
		break;
	case CREW_TYPE_PILOTS:
		fortress->crew.acceptSomeNewAbles(fortress, CREW_PILOT, ableCount);
		fortress->crew.acceptSomeNewWounded(fortress, CREW_PILOT, woundedCount);
		break;
	case CREW_TYPE_DOCTORS:
		fortress->crew.acceptSomeNewAbles(fortress, CREW_DOCTOR, ableCount);
		fortress->crew.acceptSomeNewWounded(fortress, CREW_DOCTOR, woundedCount);
		break;
	case CREW_TYPE_PASSENGERS:
		fortress->crew.acceptSomeNewAbles(fortress, CREW_PASSENGER, ableCount);
		fortress->crew.acceptSomeNewWounded(fortress, CREW_PASSENGER, woundedCount);
		break;
	}
	
    gctx.sendToClient(cl, answerWriter :: fortress_add_crew(fortressid, ableCount, woundedCount, crewType));

    return cl;
}

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

id request_fortress_remove_crew(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	dtIdentifier fortressid = strtoul(parameters[REQUEST_FORTRESS_REMOVE_CREW_FORTRESS_ID].c_str(), NULL, 0);
    fortressClass* fortress = actx->cacheFortressesList.getItem<fortressClass>(fortressid);

    /* pokud lod neexistuje, vrat chybu */
    if (fortress == NULL)
    {
		gctx.sendToClient(cl, answerWriter :: fortress_remove_crew_FAIL(fortressid, REQUEST_FORTRESS_REMOVE_CREW_ANSWER_FORTRESSNE)); 
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (fortress->getFortressRealmID() != cl.first)
    {
		gctx.sendToClient(cl, answerWriter :: fortress_remove_crew_FAIL(fortressid, REQUEST_FORTRESS_REMOVE_CREW_ANSWER_FORTRESSNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!fortress->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: fortress_remove_crew_FAIL(fortressid, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

	crew_type crewType = (crew_type) strtoul(parameters[REQUEST_FORTRESS_REMOVE_CREW_CREW_TYPE].c_str(), NULL, 0);
	unsigned long ableCount = strtoul(parameters[REQUEST_FORTRESS_REMOVE_CREW_ABLE_COUNT].c_str(), NULL, 0);
	unsigned long woundedCount = strtoul(parameters[REQUEST_FORTRESS_REMOVE_CREW_WOUNDED_COUNT].c_str(), NULL, 0);

	switch (crewType) {
	case CREW_TYPE_CAPTAIN:
		fortress->crew.releaseSomeAbles(CREW_CAPITAN, ableCount);
		fortress->crew.releaseSomeWounded(CREW_CAPITAN, woundedCount);
		break;
	case CREW_TYPE_OFFICERS:
		fortress->crew.releaseSomeAbles(CREW_OFFICER, ableCount);
		fortress->crew.releaseSomeWounded(CREW_OFFICER, woundedCount);
		break;
	case CREW_TYPE_ENGINEERS:
		fortress->crew.releaseSomeAbles(CREW_ENGINEER, ableCount);
		fortress->crew.releaseSomeWounded(CREW_ENGINEER, woundedCount);
		break;
	case CREW_TYPE_SCIENTISTS:
		fortress->crew.releaseSomeAbles(CREW_SCIENTIST, ableCount);
		fortress->crew.releaseSomeWounded(CREW_SCIENTIST, woundedCount);
		break;
	case CREW_TYPE_PILOTS:
		fortress->crew.releaseSomeAbles(CREW_PILOT, ableCount);
		fortress->crew.releaseSomeWounded(CREW_PILOT, woundedCount);
		break;
	case CREW_TYPE_DOCTORS:
		fortress->crew.releaseSomeAbles(CREW_DOCTOR, ableCount);
		fortress->crew.releaseSomeWounded(CREW_DOCTOR, woundedCount);
		break;
	case CREW_TYPE_PASSENGERS:
		fortress->crew.releaseSomeAbles(CREW_PASSENGER, ableCount);
		fortress->crew.releaseSomeWounded(CREW_PASSENGER, woundedCount);
		break;
	}
	
    gctx.sendToClient(cl, answerWriter :: fortress_remove_crew(fortressid, ableCount, woundedCount, crewType));

    return cl;
}

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

id request_update_fortress_other_equipment_information(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    dtIdentifier fortressid = strtoul(parameters[REQUEST_FORTRESS_OTHER_EQUIPMENT_INFORMATION_FORTRESSID].c_str(), NULL, 0);
    fortressClass* fortress = actx->cacheFortressesList.getItem<fortressClass>(fortressid);

    /* pokud lod neexistuje, vrat chybu */
    if (fortress == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: fortress_other_equipment_information_FAIL(fortressid, REQUEST_FORTRESS_OTHER_EQUIPMENT_INFORMATION_ANSWER_FORTRESSNE));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (fortress->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: fortress_other_equipment_information_FAIL(fortressid, REQUEST_FORTRESS_OTHER_EQUIPMENT_INFORMATION_ANSWER_FORTRESSNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!fortress->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: fortress_other_equipment_information_FAIL(fortressid, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

	other_equipment_status status;

	status.actualEnergyConsumption = fortress->otherEquipment.getActualEnergyConsumption();
	status.otherEquipmentWeight = fortress->otherEquipment.getOtherEquipmentWeight();
		
	status.isPlasmaFilterAvailable = fortress->otherEquipment.plasmaFilter()->getCount() > 0;

	if ((FT_SHIP == fortress->getFortressType()       ) &&
		(((shipClass *)(fortress))->MovementIsInWarp()))
	{
		status.plasmaFilterActualTotalFilteringSpeed = ulRound(fortress->otherEquipment.plasmaFilter()->actualTotalFilteringSpeed(fortress->getFortressRealmID(), 1));
	}
	else
	{
		status.plasmaFilterActualTotalFilteringSpeed = ulRound(fortress->otherEquipment.plasmaFilter()->actualTotalFilteringSpeed(fortress->getFortressRealmID(), 0));
	}
	status.plasmaFilterStatus = fortress->otherEquipment.plasmaFilter()->getStatus();
	
	status.isLifeSupportAvailable = fortress->otherEquipment.lifeSupport()->getCount() > 0;
	status.lifeSupportActualCapacity = fortress->otherEquipment.lifeSupport()->actualCapacity();

	status.lifeSupportActualConsumption = fortress->otherEquipment.lifeSupport()->actualConsumption(fortress->crew.getTotalCrewCount());
	status.lifeSupportStatus = fortress->otherEquipment.lifeSupport()->getStatus();	

	status.isScietificLabAvailable = fortress->otherEquipment.scientificLab()->getCount() > 0;
	status.scientificLabActualLevel = fortress->otherEquipment.scientificLab()->actualLevel();
	status.scientificLabActualCapacity = fortress->otherEquipment.scientificLab()->actualCapacity();
	status.scientificLabStatus = fortress->otherEquipment.scientificLab()->getStatus();

	status.isSubspaceTransmitterAvailable = fortress->otherEquipment.subspaceTransmitter()->getCount() > 0;
	status.subspaceTransmitterActualMessageCost = fortress->otherEquipment.subspaceTransmitter()->actualMessageCost();
	status.subspaceTransmitterStatus = fortress->otherEquipment.subspaceTransmitter()->getStatus();

    gctx.sendToClient(cl, answerWriter :: fortress_other_equipment_information(fortressid, status));

    return cl;
}

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

id request_admin_players(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	size_t realmsCount = actx->cacheRealmsList.getSize();

	std::string nameFilter = parameters[REQUEST_ADMIN_PLAYERS_PLAYER_LOGIN_FILTER];

	std :: list<realm_information> realmInformations;

	for (size_t i = 0; i < realmsCount; ++i) {
		realmClass * realm = actx->cacheRealmsList.getItem<realmClass>((unsigned long)i);				

		if (realm == NULL) {
			continue;
		}

		if (realm->getLogin().find(nameFilter) == string::npos) {
			continue;
		}

		realm_information realmInformation;

		realmInformation.id = realm->getID();
		realmInformation.login = realm->getLogin();
		realmInformation.name = realm->getPlayerName();
		realmInformation.hasBan = realm->hasBan();

		realmInformations.push_back(realmInformation);
	}

    /* posleme seznam moznych prijemcu */
	gctx.sendToClient(cl, adminAnswerWriter :: players(realmInformations));

    return cl;
}

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

id request_admin_ban_player(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	dtIdentifier playerId = strtoul(parameters[REQUEST_ADMIN_BAN_PLAYER_PLAYER_ID].c_str(), NULL, 0);

	std::string banReason = parameters[REQUEST_ADMIN_BAN_PLAYER_BAN_REASON];
	int banDayDuration = strtoul(parameters[REQUEST_ADMIN_BAN_PLAYER_BAN_DURATION_IN_DAYS].c_str(), NULL, 0);
	int banLevel = atoi(parameters[REQUEST_ADMIN_BAN_PLAYER_BAN_LEVEL].c_str());
	bool hasBan = atoi(parameters[REQUEST_ADMIN_BAN_PLAYER_PLAYER_HAS_BAN].c_str()) == 1;

    realmClass* realm = actx->cacheRealmsList.getItem<realmClass>(playerId);

	std::string banResult;

    if (realm != NULL)
    {
		if (hasBan) {
			if (realm->getBan())
			{
				realm->makeBan(banLevel, banDayDuration, banReason);
				banResult = REQUEST_ADMIN_BAN_PLAYER_RESULT_UPDATED;
			}
			else 
			{
				realm->makeBan(banLevel, banDayDuration, banReason);
				banResult = REQUEST_ADMIN_BAN_PLAYER_RESULT_ADDED;
			}

            // pokud banujeme hrace, odhlasime ho
            gctx.closeClient(make_pair(playerId, 0));

			hasBan = true;
		}
		else 
		{
			realm->cancelBan();
			banResult = REQUEST_ADMIN_BAN_PLAYER_RESULT_CANCELED;
			hasBan = false;
		}
	}
    else
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) playerId);
        return make_pair(0, 0);
    }

    /* posleme seznam moznych prijemcu */
	gctx.sendToClient(cl, adminAnswerWriter :: ban_player(playerId, banResult, hasBan));

    return cl;
}

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

id request_admin_player_ban_information(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	dtIdentifier playerId = strtoul(parameters[REQUEST_ADMIN_PLAYER_BAN_INFORMATION_PLAYER_ID].c_str(), NULL, 0);


    realmClass* realm = actx->cacheRealmsList.getItem<realmClass>(playerId);

    if (realm == NULL)
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) playerId);
        return make_pair(0, 0);
    }

    /* posleme seznam moznych prijemcu */
	gctx.sendToClient(cl, adminAnswerWriter :: player_ban_information(playerId, realm->getBan()));

    return cl;
}

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

id request_admin_player_information(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    std :: list<shipClass*> ships;
	std :: list<baseClass*> bases;

	dtIdentifier playerId = strtoul(parameters[REQUEST_ADMIN_PLAYER_INFORMATION_PLAYER_ID].c_str(), NULL, 0);

    realmClass* realm = actx->cacheRealmsList.getItem<realmClass>(playerId);
    if (realm != NULL)
    {
        const dtIdentifierVector& vships = realm->getShipList();
        for (dtIdentifierVector :: const_iterator iter = vships.begin(); iter != vships.end(); iter++)
        {
            fortressClass* f = actx->cacheFortressesList.getItem<fortressClass>(*iter);
            if (f!= NULL)
            {
                if (f->getFortressType() == FT_SHIP) 
                {
                    ships.push_back(dynamic_cast<shipClass*>(f));
                }
                else
                {
                    errExceptionError("Base [%u] in ships list!", (unsigned long long) f->getID());
                    return make_pair(0, 0);
                }
            }
            else
            {
                errExceptionError("Ship with id %u not found!", (unsigned long long) *iter);
                return make_pair(0, 0);
            }
        }

		const dtIdentifierVector& vbases = realm->getBaseList();
        for (dtIdentifierVector :: const_iterator iter = vbases.begin(); iter != vbases.end(); iter++)
        {
            fortressClass* f = actx->cacheFortressesList.getItem<fortressClass>(*iter);
            if (f!= NULL)
            {
                if (f->getFortressType() == FT_BASE) 
                {
                    bases.push_back(dynamic_cast<baseClass*>(f));
                }
                else
                {
                    errExceptionError("Ship [%u] in bases list!", (unsigned long long) f->getID());
                    return make_pair(0, 0);
                }
            }
            else
            {
                errExceptionError("Base with id %u not found!", (unsigned long long) *iter);
                return make_pair(0, 0);
            }
        }

		realm_information realmState;

		realmState.id = realm->getID();
		realmState.login = realm->getLogin();
		realmState.name = realm->getPlayerName();
		realmState.hasBan = realm->hasBan();

        /* posleme seznam moznych prijemcu */
		gctx.sendToClient(cl, adminAnswerWriter :: player_information(realmState, ships, bases));
    }
    else
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) playerId);
        return make_pair(0, 0);
    }

    return cl;
}

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

id request_admin_ship_information(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	dtIdentifier fortressid = strtoul(parameters[REQUEST_ADMIN_SHIP_INFORMATION_FORTRESS_ID].c_str(), NULL, 0);
    shipClass* fortress = actx->cacheFortressesList.getItem<shipClass>(fortressid);

    /* pokud lod neexistuje, vrat chybu */
    if (fortress == NULL)
    {
        // gctx.sendToClient(cl, adminAnswerWriter :: ship_information_FAIL(fortressid, ADMIN_PROBLEM_FORTRESSNE));  
        return cl;
    }

	if (fortress->getFortressType() != FT_SHIP) {
		//gctx.sendToClient(cl, adminAnswerWriter :: ship_information_FAIL(fortressid, ADMIN_PROBLEM_FORTRESSNOTSHIP));
		return cl;
	}

    gctx.sendToClient(cl, adminAnswerWriter :: ship_information(fortress));

	return cl;
}

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

id request_admin_base_information(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	dtIdentifier fortressid = strtoul(parameters[REQUEST_ADMIN_BASE_INFORMATION_FORTRESS_ID].c_str(), NULL, 0);
    baseClass* fortress = actx->cacheFortressesList.getItem<baseClass>(fortressid);

    /* pokud lod neexistuje, vrat chybu */
    if (fortress == NULL)
    {
        // gctx.sendToClient(cl, adminAnswerWriter :: base_information_FAIL(fortressid, ADMIN_PROBLEM_FORTRESSNE));  
        return cl;
    }

	if (fortress->getFortressType() != FT_BASE) {
		//gctx.sendToClient(cl, adminAnswerWriter :: base_information_FAIL(fortressid, ADMIN_PROBLEM_FORTRESSNOTSHIP));
		return cl;
	}

    gctx.sendToClient(cl, adminAnswerWriter :: base_information(fortress));

	return cl;
}

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

std::string get_pattern_name_from_pattern_id(dtIdentifier patternID)
{
	switch (patternID) 
	{
	case PATTERN_ID_ENERGETIC_ACCUMULATOR:
		return PROTOCOL_HANGARS_PATTERN_ID_ENERGETIC_ACCUMULATOR;
	case PATTERN_ID_NAVIGATION_COMPUTER:
		return PROTOCOL_HANGARS_PATTERN_ID_NAVIGATION_COMPUTER;
	case PATTERN_ID_QUARK_GLUON_CORE:
		return PROTOCOL_HANGARS_PATTERN_ID_QUARK_GLUON_CORE;
	case PATTERN_ID_SUBSPACE_BEACON:
		return PROTOCOL_HANGARS_PATTERN_ID_SUBSPACE_BEACON;
	case PATTERN_ID_INERTIAL_DAMPERS:
		return PROTOCOL_HANGARS_PATTERN_ID_INERTIAL_DAMPERS;
	case PATTERN_ID_IMPULS_JET_ENGINE:
		return PROTOCOL_HANGARS_PATTERN_ID_IMPULS_JET_ENGINE;
	case PATTERN_ID_MECHANICAL_DAMPERS:
		return PROTOCOL_HANGARS_PATTERN_ID_MECHANICAL_DAMPERS;
	case PATTERN_ID_DEFLECTOR_SHIELDS:
		return PROTOCOL_HANGARS_PATTERN_ID_DEFLECTOR_SHIELDS;
	case PATTERN_ID_WEAPON_ENERGY_CIRCUIT:
		return PROTOCOL_HANGARS_PATTERN_ID_WEAPON_ENERGY_CIRCUIT;
	case PATTERN_ID_DRONE_MISSILES:
		return PROTOCOL_HANGARS_PATTERN_ID_DRONE_MISSILES;
	case PATTERN_ID_DRONE_MISSILE_LAUNCHER:
		return PROTOCOL_HANGARS_PATTERN_ID_DRONE_MISSILE_LAUNCHER;
	case PATTERN_ID_LASER_GUN:
		return PROTOCOL_HANGARS_PATTERN_ID_LASER_GUN;
	case PATTERN_ID_TRANSPORT_BEAM_GENERATOR:
		return PROTOCOL_HANGARS_PATTERN_ID_TRANSPORT_BEAM_GENERATOR;
	case PATTERN_ID_MAGNETICAL_COLLECTORS_OF_PLASMA:
		return PROTOCOL_HANGARS_PATTERN_ID_MAGNETICAL_COLLECTORS_OF_PLASMA;
	case PATTERN_ID_SUBMERSIBLE_FILTRATION_TANK:
		return PROTOCOL_HANGARS_PATTERN_ID_SUBMERSIBLE_FILTRATION_TANK;
	case PATTERN_ID_SUBMARINE_MINING_MACHINE:
		return PROTOCOL_HANGARS_PATTERN_ID_SUBMARINE_MINING_MACHINE;
	case PATTERN_ID_UNDERGROUND_DRILLIG_MACHINE:
		return PROTOCOL_HANGARS_PATTERN_ID_UNDERGROUND_DRILLIG_MACHINE;
	case PATTERN_ID_PROBE:
		return PROTOCOL_HANGARS_PATTERN_ID_PROBE;
	case PATTERN_ID_HIGH_RESOLUTION_SENSORS:
		return PROTOCOL_HANGARS_PATTERN_ID_HIGH_RESOLUTION_SENSORS;
	case PATTERN_ID_LONG_RANGE_SENSORS:
		return PROTOCOL_HANGARS_PATTERN_ID_LONG_RANGE_SENSORS;
	case PATTERN_ID_CLOAKING_DEVICE:
		return PROTOCOL_HANGARS_PATTERN_ID_CLOAKING_DEVICE;
	case PATTERN_ID_ANDROIDS:
		return PROTOCOL_HANGARS_PATTERN_ID_ANDROIDS;
	case PATTERN_ID_MAGNETICAL_GRID:
		return PROTOCOL_HANGARS_PATTERN_ID_MAGNETICAL_GRID;
	case PATTERN_ID_TRANSPORT_CONTAINER:
		return PROTOCOL_HANGARS_PATTERN_ID_TRANSPORT_CONTAINER;
	case PATTERN_ID_ENERGETIC_CELL:
		return PROTOCOL_HANGARS_PATTERN_ID_ENERGETIC_CELL;
	case PATTERN_ID_PLASMA_FILTER:
		return PROTOCOL_HANGARS_PATTERN_ID_PLASMA_FILTER;
	case PATTERN_ID_SCIENTIFIC_LAB:
		return PROTOCOL_HANGARS_PATTERN_ID_SCIENTIFIC_LAB;
	case PATTERN_ID_LIFE_SUPPORT:
		return PROTOCOL_HANGARS_PATTERN_ID_LIFE_SUPPORT;
	case PATTERN_ID_SUBSPACE_TRANSMITTER:
		return PROTOCOL_HANGARS_PATTERN_ID_SUBSPACE_TRANSMITTER;
	case PATTERN_ID_MAINFRAME:
		return PROTOCOL_HANGARS_PATTERN_ID_MAINFRAME;
	case PATTERN_ID_HANGAR:
		return PROTOCOL_HANGARS_PATTERN_ID_HANGAR;
	case PATTERN_ID_MAGNETICAL_FILTER:
		return PROTOCOL_HANGARS_PATTERN_ID_MAGNETICAL_FILTER;
	case PATTERN_ID_DEUTERIUM_DECOMPOSER:
		return PROTOCOL_HANGARS_PATTERN_ID_DEUTERIUM_DECOMPOSER;
	case PATTERN_ID_ZIRCONIUM_REACTOR:
		return PROTOCOL_HANGARS_PATTERN_ID_ZIRCONIUM_REACTOR;
	case PATTERN_ID_ILMENITE_FURNACE:
		return PROTOCOL_HANGARS_PATTERN_ID_ILMENITE_FURNACE;
	default:			
		errLogicalError("Bad items type");
	}

	return "";
}

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

dtIdentifier get_pattern_id_from_pattern_name(std::string patternID)
{
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_ENERGETIC_ACCUMULATOR) {
		return PATTERN_ID_ENERGETIC_ACCUMULATOR;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_NAVIGATION_COMPUTER) {
		return PATTERN_ID_NAVIGATION_COMPUTER;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_QUARK_GLUON_CORE) {
		return PATTERN_ID_QUARK_GLUON_CORE;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_SUBSPACE_BEACON) {
		return PATTERN_ID_SUBSPACE_BEACON;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_INERTIAL_DAMPERS) {
		return PATTERN_ID_INERTIAL_DAMPERS;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_IMPULS_JET_ENGINE) {
		return PATTERN_ID_IMPULS_JET_ENGINE;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_MECHANICAL_DAMPERS) {
		return PATTERN_ID_MECHANICAL_DAMPERS;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_DEFLECTOR_SHIELDS) {
		return PATTERN_ID_DEFLECTOR_SHIELDS;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_WEAPON_ENERGY_CIRCUIT) {
		return PATTERN_ID_WEAPON_ENERGY_CIRCUIT;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_DRONE_MISSILES) {
		return PATTERN_ID_DRONE_MISSILES;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_DRONE_MISSILE_LAUNCHER) {
		return PATTERN_ID_DRONE_MISSILE_LAUNCHER;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_LASER_GUN) {
		return PATTERN_ID_LASER_GUN;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_TRANSPORT_BEAM_GENERATOR) {
		return PATTERN_ID_TRANSPORT_BEAM_GENERATOR;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_MAGNETICAL_COLLECTORS_OF_PLASMA) {
		return PATTERN_ID_MAGNETICAL_COLLECTORS_OF_PLASMA;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_SUBMERSIBLE_FILTRATION_TANK) {
		return PATTERN_ID_SUBMERSIBLE_FILTRATION_TANK;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_SUBMARINE_MINING_MACHINE) {
		return PATTERN_ID_SUBMARINE_MINING_MACHINE;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_UNDERGROUND_DRILLIG_MACHINE) {
		return PATTERN_ID_UNDERGROUND_DRILLIG_MACHINE;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_PROBE) {
		return PATTERN_ID_PROBE;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_HIGH_RESOLUTION_SENSORS) {
		return PATTERN_ID_HIGH_RESOLUTION_SENSORS;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_LONG_RANGE_SENSORS) {
		return PATTERN_ID_LONG_RANGE_SENSORS;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_CLOAKING_DEVICE) {
		return PATTERN_ID_CLOAKING_DEVICE;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_ANDROIDS) {
		return PATTERN_ID_ANDROIDS;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_MAGNETICAL_GRID) {
		return PATTERN_ID_MAGNETICAL_GRID;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_TRANSPORT_CONTAINER) {
		return PATTERN_ID_TRANSPORT_CONTAINER;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_ENERGETIC_CELL) {
		return PATTERN_ID_ENERGETIC_CELL;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_PLASMA_FILTER) {
		return PATTERN_ID_PLASMA_FILTER;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_SCIENTIFIC_LAB) {
		return PATTERN_ID_SCIENTIFIC_LAB;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_LIFE_SUPPORT) {
		return PATTERN_ID_LIFE_SUPPORT;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_SUBSPACE_TRANSMITTER) {
		return PATTERN_ID_SUBSPACE_TRANSMITTER;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_MAINFRAME) {
		return PATTERN_ID_MAINFRAME;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_HANGAR) {
		return PATTERN_ID_HANGAR;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_MAGNETICAL_FILTER) {
		return PATTERN_ID_MAGNETICAL_FILTER;	
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_DEUTERIUM_DECOMPOSER) {
		return PATTERN_ID_DEUTERIUM_DECOMPOSER;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_ZIRCONIUM_REACTOR) {
		return PATTERN_ID_ZIRCONIUM_REACTOR;
	}
	if (patternID == PROTOCOL_HANGARS_PATTERN_ID_ILMENITE_FURNACE) {
		return PATTERN_ID_ILMENITE_FURNACE;
	}		

	return NOT_VALID_ID;
}

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

std::string mounting_result_to_string(mountingResult result)
{
	switch (result) 
	{
	case MR_DONE:
		return PROTOCOL_MOUNTING_RESULT_DONE;
	case MR_SLOT_OCCUPIED:
		return PROTOCOL_MOUNTING_RESULT_SLOT_OCCUPIED;
	case MR_SLOT_EMPTY:
		return PROTOCOL_MOUNTING_SLOT_EMPTY;
	case MR_NOT_ENOUGH_ANDROIDS:
		return PROTOCOL_MOUNTING_RESULT_NOT_ENOUGH_ANDROIDS;
	case MR_NOT_ENOUGH_ENERGY:
		return PROTOCOL_MOUNTING_RESULT_NOT_ENOUGH_ENERGY;
	case MR_NOT_ENOUGH_STORAGE_SPACE:
		return PROTOCOL_MOUNTING_RESULT_NOT_ENOUGH_STORAGE_SPACE;
	case MR_BAD_FORTRESS_TYPE:
		return PROTOCOL_MOUNTING_RESULT_BAD_FORTRESS_TYPE;
	case MR_HANGAR_NOT_EMPTY:
		return PROTOCOL_MOUNTING_RESULT_HANGAR_NOT_EMPTY;
	default:
		return PROTOCOL_MOUNTING_RESULT_UNKNOWN_FAIL;
	}
}

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

mountingResult string_to_mounting_result(const std::string& result)
{
	if (result == PROTOCOL_MOUNTING_RESULT_DONE) 
	{
		return MR_DONE;
	}
	else if (result == PROTOCOL_MOUNTING_RESULT_SLOT_OCCUPIED) 
	{
		return MR_SLOT_OCCUPIED;
	}
	else if (result == PROTOCOL_MOUNTING_SLOT_EMPTY) 
	{
		return MR_SLOT_EMPTY;
	}
	else if (result == PROTOCOL_MOUNTING_RESULT_NOT_ENOUGH_ANDROIDS) 
	{
		return MR_NOT_ENOUGH_ANDROIDS;
	}
	else if (result == PROTOCOL_MOUNTING_RESULT_NOT_ENOUGH_ENERGY) 
	{
		return MR_NOT_ENOUGH_ENERGY;
	}
	else if (result == PROTOCOL_MOUNTING_RESULT_NOT_ENOUGH_STORAGE_SPACE) 
	{
		return MR_NOT_ENOUGH_STORAGE_SPACE;
	}
	else
	{
		return MR_UNKNOWN_FAIL;
	}
}

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

hangar_item_status create_item_pattern(int patternID) 
{	
	hangar_item_status item;

	if (patternID == NOT_VALID_ID) 
	{
		return item;
	}

	itemsPatternClass * itemPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(patternID);

	if (itemPattern == NULL)
	{
		return item;
	}	

	item.patternName = get_pattern_name_from_pattern_id(patternID);
	
	item.constructionDeuterium = itemPattern->getConstructionDeuterium();
	item.constructionHeavyWater = itemPattern->getConstructionHeavyWater();
	item.constructionTitanium = itemPattern->getConstructionTitanium();
	item.constructionUlrei = itemPattern->getConstructionUlrei();
	item.isStackable = itemPattern->isItemStackable();
	item.itemName = itemPattern->getItemName();
	item.minWeight = itemPattern->getMinWeight();
	item.maxWeight = itemPattern->getMaxWeight();
	item.density = itemPattern->getDensity();

	return item;
}

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

id request_update_base_hangars_information(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    dtIdentifier baseid = strtoul(parameters[REQUEST_BASE_HANGARS_INFORMATION_FORTRESSID].c_str(), NULL, 0);		
	std::string selectedItemPattern = parameters[REQUEST_BASE_HANGARS_INFORMATION_SELECTED_ITEM_ID];

    baseClass* base = actx->cacheFortressesList.getItem<baseClass>(baseid);
	
    /* pokud zakladna neexistuje, vrat chybu */
    if (base == NULL)
    {
		gctx.sendToClient(cl, answerWriter :: base_hangars_information_FAIL(baseid, REQUEST_BASE_HANGARS_INFORMATION_ANSWER_FORTRESSNE));  
        return cl;
    }

    /* pokud zakladna hraci nepatri, vrat chybu */
    if (base->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: base_hangars_information_FAIL(baseid, REQUEST_BASE_HANGARS_INFORMATION_ANSWER_FORTRESSNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!base->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: base_hangars_information_FAIL(baseid, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }
	
	if (base->getFortressType() != FT_BASE) {
		gctx.sendToClient(cl, answerWriter :: base_hangars_information_FAIL(baseid, REQUEST_BASE_HANGARS_INFORMATION_ANSWER_FORTRESSNOTBASE));
		return cl;
	}		

	hangarsPortClass & hangarsPort = base->hangarsPort;

	hangars_status status;

	for (std::deque<unsigned long>::const_iterator it = hangarsPort.beginHangarsIdentifiers(); it != hangarsPort.endHangarsIdentifiers(); ++it) 
	{
		status.hangarIds.push_back(*it);
	}
	
	status.selectedHangarId = strtoul(parameters[REQUEST_BASE_HANGARS_INFORMATION_HANGAR_ID].c_str(), NULL, 0);	
		
	// Pokud je ID vybraneho hangaru 0, tak uzivatel chce libovolny hangar, nema preference
	bool arbitraryHangar = status.selectedHangarId == 0;

	if (arbitraryHangar) 
	{
		// Vratime prvni hangar, na ktery narazime
		if (hangarsPort.getHangarsCount() > 0) {
			status.selectedHangarId = *(hangarsPort.beginHangarsIdentifiers());
			hangarClass * hangar = hangarsPort.hangarByIdentifier(status.selectedHangarId);	
		}
	}

	hangarClass * hangar = hangarsPort.hangarByIdentifier(status.selectedHangarId);	

	if (hangar == NULL) 
	{		
		// Uzivatel nechce konkretni hangar, takze pokud tam zadny neni, neni to chyba a jednoduse nevratime zadny hangar.
		// V opacnem pripade uzivatel chtel hangar, ktery neexistuje, to je chyba

		if (arbitraryHangar) 
		{
			status.selectedHangarId = 0;
		}
		else
		{
			gctx.sendToClient(cl, answerWriter :: base_hangars_information_FAIL(baseid, REQUEST_BASE_HANGARS_INFORMATION_ANSWER_HANGAR_NOT_EXISTS));
			return cl;
		}
	}
	else 
	{
		hangar->checkConstruction(base);

		status.damageStatus = hangar->getStatus();
		status.actualLevel = hangar->actualLevel();		
		status.isShipInDock = hangar->isShipInDock();	
		status.selectedHangarId = hangar->getID();
		
		status.isShipUnderConstruction = hangar->isShipUnderConstruction();
		status.isWhateverUnderConstruction = hangar->isWhateverUnderConstruction();
		status.isItemUnderConstruction = hangar->isItemUnderConstruction();
		status.isHangarFree = hangar->isHangerFree();

		status.actualConstructedPoints = hangar->getActualConstructedPoints();
		status.targetConstructedPoints = hangar->getTargetConstructedPoints();
		status.constructionGradient = hangar->getGradient();				

		if (status.isItemUnderConstruction)
		{
			status.constructedItem = create_item_pattern(hangar->getItemUnderConstructionPatternID());
			status.constructedItem.count = hangar->getCreationsCount();
		}
		else if (status.isShipUnderConstruction)
		{
			dtIdentifier constructedShipClassID = hangar->getShipUnderConstructionClassID();

			fortressClassClass * shipsClass = actx->cacheFortressClassesList.getItem<fortressClassClass>(constructedShipClassID);

			if (shipsClass != NULL)
			{
				shipClass ship;
			}
		}		

		if (status.isItemUnderConstruction) {
			status.constructedItem.actSize = 0;

			if (status.constructedItem.density != 0) {
				itemDimensionsClass dimensions = hangar->getConstructedItemDimensions();
				status.constructedItem.actSize = dimensions.weight_ / (double) status.constructedItem.density;		
			}
			
			// U stackable itemu musime jeste nasobit poctem
			if (status.constructedItem.isStackable) {
				status.constructedItem.actSize = status.constructedItem.actSize * status.constructedItem.count;
			}

			status.constructedItem.actRequiredAndroidCount = structuralIntegrityVoidSectionClass::getMaxRepairingMechanicsBySize(status.constructedItem.actSize);
	
			status.constructedItem.minSize = 0;
			status.constructedItem.maxSize = 0;

			if (status.constructedItem.density != 0) {
				status.constructedItem.minSize = status.constructedItem.minWeight / (double) status.constructedItem.density;		
				status.constructedItem.maxSize = status.constructedItem.maxWeight / (double) status.constructedItem.density;		
			}

			status.constructedItem.minRequiredAndroidCount = structuralIntegrityVoidSectionClass::getMaxRepairingMechanicsBySize(status.constructedItem.minSize);
			status.constructedItem.maxRequiredAndroidCount = structuralIntegrityVoidSectionClass::getMaxRepairingMechanicsBySize(status.constructedItem.maxSize);

			if (status.constructionGradient != 0) {
				status.constructedItem.constructionTime = (unsigned long long) ((status.targetConstructedPoints  - status.actualConstructedPoints) / (double) status.constructionGradient);
			}
			else {
				status.constructedItem.constructionTime = 0;
			}
		}
		else {
			status.constructedItem.minRequiredAndroidCount = 0;
			status.constructedItem.maxRequiredAndroidCount = 0;
			status.constructedItem.actRequiredAndroidCount = 0;
		}		

		// Pokud se vyrabi jiny predmet, nez ktery uzivatel prohlizi v detailech, tak musime poslat jeste jeho informace
		if (status.selectedItem.patternName != status.constructedItem.patternName) {
			status.selectedItem = create_item_pattern(get_pattern_id_from_pattern_name(selectedItemPattern)); 

			// U vybraneho predmetu neurcujeme aktualni hmotnost, protoze kdyz se predmet nevyrabi, tak ji nezname
			status.selectedItem.actSize = 0;

			status.selectedItem.minSize = 0;
			status.selectedItem.maxSize = 0;

			if (status.selectedItem.density != 0) {
				status.selectedItem.minSize = status.selectedItem.minWeight / (double) status.selectedItem.density;		
				status.selectedItem.maxSize = status.selectedItem.maxWeight / (double) status.selectedItem.density;		
			}
			
			status.selectedItem.minRequiredAndroidCount = structuralIntegrityVoidSectionClass::getMaxRepairingMechanicsBySize(status.selectedItem.minSize);
			status.selectedItem.maxRequiredAndroidCount = structuralIntegrityVoidSectionClass::getMaxRepairingMechanicsBySize(status.selectedItem.maxSize);
		}
	}

	dtIdentifierList availableShipClasses;
	dtIdentifierList availableBaseClasses;
	base->getAvailableFortressClasses(&availableBaseClasses, &availableShipClasses);

	for (dtIdentifierList::const_iterator it = availableShipClasses.begin(); it != availableShipClasses.end(); ++it) 
	{
		fortressClassClass * fortressClazz = actx->cacheFortressClassesList.getItem<fortressClassClass>(*it);

		if (fortressClazz == NULL) 
		{
			errExceptionError("Fortress class [%u] not found",  (unsigned long long)*it);
			continue;
		}

		fortress_class_simple_data classData;
		classData.id = fortressClazz->getID();
		classData.name = fortressClazz->getClassName();
		classData.quality = fortressClazz->getQualityRating();

		status.availableShipClasses.push_back(classData);
	}

	/* posleme seznam moznych prijemcu */
	gctx.sendToClient(cl, answerWriter :: base_hangars_information(baseid, status));

	return cl;
}

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

id request_update_base_hangars_item_information(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

	std::string selectedItemPattern = parameters[REQUEST_BASE_HANGAR_ITEM_INFORMATION_ITEM_ID];

	hangar_item_status status = create_item_pattern(get_pattern_id_from_pattern_name(selectedItemPattern));

	// U vybraneho predmetu neurcujeme aktualni hmotnost, protoze kdyz se predmet nevyrabi, tak ji nezname
	status.actSize = 0;

	status.minSize = 0;
	status.maxSize = 0;

	if (status.density != 0) {
		status.minSize = status.minWeight / (double) status.density;		
		status.maxSize = status.maxWeight / (double) status.density;		
	}
			
	status.minRequiredAndroidCount = structuralIntegrityVoidSectionClass::getMaxRepairingMechanicsBySize(status.minSize);
	status.maxRequiredAndroidCount = structuralIntegrityVoidSectionClass::getMaxRepairingMechanicsBySize(status.maxSize);

	/* posleme seznam moznych prijemcu */
	gctx.sendToClient(cl, answerWriter :: base_hangars_item_information(status));

	return cl;
}

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

id request_base_hangar_build_item(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    dtIdentifier baseid = strtoul(parameters[REQUEST_HANGAR_BUILD_ITEM_FORTRESS_ID].c_str(), NULL, 0);		

	HangarServerInputData data;

	data.type = parameters[REQUEST_HANGAR_BUILD_ITEM_PATTERN_NAME];
	data.hangarId = strtoul(parameters[REQUEST_HANGAR_BUILD_ITEM_HANGAR_ID].c_str(), NULL, 0);		
	data.quantity = atoi(parameters[REQUEST_HANGAR_BUILD_ITEM_QUANTITY].c_str());
	data.weight = atoi(parameters[REQUEST_HANGAR_BUILD_ITEM_WEIGHT].c_str());;
	data.length = atoi(parameters[REQUEST_HANGAR_BUILD_ITEM_LENGTH].c_str());
	data.width = atoi(parameters[REQUEST_HANGAR_BUILD_ITEM_WIDTH].c_str());
	data.height = atoi(parameters[REQUEST_HANGAR_BUILD_ITEM_HEIGHT].c_str());

    baseClass* base = actx->cacheFortressesList.getItem<baseClass>(baseid);

    /* pokud zakladna neexistuje, vrat chybu */
    if (base == NULL)
    {
		gctx.sendToClient(cl, answerWriter :: base_hangar_build_item_FAIL(baseid, data.hangarId, REQUEST_HANGAR_BUILD_ITEM_FORTRESSNE));  
        return cl;
    }

    /* pokud zakladna hraci nepatri, vrat chybu */
    if (base->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: base_hangar_build_item_FAIL(baseid, data.hangarId, REQUEST_HANGAR_BUILD_ITEM_FORTRESSNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!base->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: base_hangar_build_item_FAIL(baseid, data.hangarId, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

	if (base->getFortressType() != FT_BASE) {
		gctx.sendToClient(cl, answerWriter :: base_hangar_build_item_FAIL(baseid, data.hangarId, REQUEST_HANGAR_BUILD_ITEM_FORTRESSNOTBASE));
		return cl;
	}		

	hangarClass * hangar = base->hangarsPort.hangarByIdentifier(data.hangarId);

	if (hangar == NULL) {
		gctx.sendToClient(cl, answerWriter :: base_hangar_build_item_FAIL(baseid, data.hangarId, REQUEST_HANGAR_BUILD_ITEM_HANGARNE));
		return cl;
	}

	dtIdentifier patternId = get_pattern_id_from_pattern_name(data.type);

	itemsCreationResult result;

	if (patternId == PATTERN_ID_HANGAR)
	{
		data.weight = 0;

		// U hangaru zadavame pouze rozmery, hmotnost se dopocte
		result = hangar->createNewItem(base, patternId, data.quantity, itemDimensionsClass(0, data.length, data.width, data.height));
	}
	else 
	{
		data.length = 0;
		data.width = 0;
		data.height = 0;

		// U ostatnich predmetu zadavame pouze hmotnost, rozmery se dopoctou
		result = hangar->createNewItem(base, patternId, data.quantity, itemDimensionsClass(data.weight, 0, 0, 0));
	}

	/* posleme seznam moznych prijemcu */
	gctx.sendToClient(cl, answerWriter :: base_hangar_build_item(baseid, data.hangarId, result));

	return cl;
}

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

id request_base_hangar_cancel_item(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    dtIdentifier baseid = strtoul(parameters[REQUEST_HANGAR_CANCEL_ITEM_FORTRESS_ID].c_str(), NULL, 0);		
	dtIdentifier hangarId = strtoul(parameters[REQUEST_HANGAR_CANCEL_ITEM_HANGAR_ID].c_str(), NULL, 0);		

    baseClass* base = actx->cacheFortressesList.getItem<baseClass>(baseid);

    /* pokud zakladna neexistuje, vrat chybu */
    if (base == NULL)
    {
		gctx.sendToClient(cl, answerWriter :: base_hangar_cancel_item_FAIL(baseid, hangarId, REQUEST_HANGAR_CANCEL_ITEM_FORTRESSNE));  
        return cl;
    }

    /* pokud zakladna hraci nepatri, vrat chybu */
    if (base->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: base_hangar_cancel_item_FAIL(baseid, hangarId, REQUEST_HANGAR_CANCEL_ITEM_FORTRESSNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!base->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: base_hangar_cancel_item_FAIL(baseid, hangarId, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

	if (base->getFortressType() != FT_BASE) {
		gctx.sendToClient(cl, answerWriter :: base_hangar_cancel_item_FAIL(baseid, hangarId, REQUEST_HANGAR_CANCEL_ITEM_FORTRESSNOTBASE));
		return cl;
	}		

	hangarClass * hangar = base->hangarsPort.hangarByIdentifier(hangarId);

	if (hangar == NULL) {
		gctx.sendToClient(cl, answerWriter :: base_hangar_cancel_item_FAIL(baseid, hangarId, REQUEST_HANGAR_CANCEL_ITEM_HANGARNE));
		return cl;
	}

	hangar->cancelConstruction();

	/* posleme seznam moznych prijemcu */
	gctx.sendToClient(cl, answerWriter :: base_hangar_cancel_item(baseid, hangarId));

	return cl;
}

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

id request_update_base_factories_information(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    dtIdentifier baseid = strtoul(parameters[REQUEST_BASE_FACTORIES_INFORMATION_FORTRESSID].c_str(), NULL, 0);
    baseClass* base = actx->cacheFortressesList.getItem<baseClass>(baseid);

    /* pokud zakladna neexistuje, vrat chybu */
    if (base == NULL)
    {
		gctx.sendToClient(cl, answerWriter :: base_factories_information_FAIL(baseid, REQUEST_BASE_FACTORIES_INFORMATION_ANSWER_FORTRESSNE));  
        return cl;
    }

    /* pokud zakladna hraci nepatri, vrat chybu */
    if (base->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: base_factories_information_FAIL(baseid, REQUEST_BASE_FACTORIES_INFORMATION_ANSWER_FORTRESSNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!base->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: base_factories_information_FAIL(baseid, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

	if (base->getFortressType() != FT_BASE) {
		gctx.sendToClient(cl, answerWriter :: base_factories_information_FAIL(baseid, REQUEST_BASE_FACTORIES_INFORMATION_ANSWER_FORTRESSNOTBASE));
		return cl;
	}

	factoriesClass & factories = base->getFactories();

	factories_status status;

	status.factoriesSize = factories.getFactoriesSize();
	status.factoriesWeight = factories.getFactoriesWeight();

	status.ilmeniteFurnace.isAvailable = factories.ilmeniteFurnace()->getCount() > 0;
	status.ilmeniteFurnace.count = factories.ilmeniteFurnace()->getCount();
	status.ilmeniteFurnace.actualTotalProduction = factories.ilmeniteFurnace()->actualTotalProduction(base->getFortressRealmID());
	status.ilmeniteFurnace.actualTotalConsumption = factories.ilmeniteFurnace()->actualTotalConsumption(base->getFortressRealmID());
	status.ilmeniteFurnace.actualMetamorphosisEffectivity = factories.ilmeniteFurnace()->actualMetamorphosisEffectivity(base->getFortressRealmID());
	status.ilmeniteFurnace.actualSpaceMetamorphosisEffectivity = factories.ilmeniteFurnace()->actualSpaceMetamorphosisEffectivity(base->getFortressRealmID());
	status.ilmeniteFurnace.damaged = factories.ilmeniteFurnace()->getDamaged();
	status.ilmeniteFurnace.working = factories.ilmeniteFurnace()->getWorking();
	
	status.magneticalFilter.isAvailable = factories.magneticalFilter()->getCount() > 0;
	status.magneticalFilter.count = factories.magneticalFilter()->getCount();
	status.magneticalFilter.actualTotalProduction = factories.magneticalFilter()->actualTotalProduction(base->getFortressRealmID());
	status.magneticalFilter.damaged = factories.magneticalFilter()->getDamaged();
	status.magneticalFilter.working = factories.magneticalFilter()->getWorking();

	status.zirconiumReactor.isAvailable = factories.zirconiumReactor()->getCount() > 0;
	status.zirconiumReactor.count = factories.zirconiumReactor()->getCount();
	status.zirconiumReactor.actualTotalProduction = factories.zirconiumReactor()->actualTotalProduction(base->getFortressRealmID());
	status.zirconiumReactor.actualTotalConsumption = (unsigned long)factories.zirconiumReactor()->actualTotalConsumption(base->getFortressRealmID());
	status.zirconiumReactor.actualMetamorphosisEffectivity = factories.zirconiumReactor()->actualMetamorphosisEffectivity(base->getFortressRealmID());
	status.zirconiumReactor.actualSpaceMetamorphosisEffectivity = factories.zirconiumReactor()->actualSpaceMetamorphosisEffectivity(base->getFortressRealmID());
	status.zirconiumReactor.damaged = factories.zirconiumReactor()->getDamaged();
	status.zirconiumReactor.working = factories.zirconiumReactor()->getWorking();

	status.deuteriumDecomposer.isAvailable = factories.deuteriumDecomposer()->getCount() > 0;
	status.deuteriumDecomposer.count = factories.deuteriumDecomposer()->getCount();
	status.deuteriumDecomposer.actualTotalProduction = factories.deuteriumDecomposer()->actualTotalProduction(base->getFortressRealmID());
	status.deuteriumDecomposer.actualTotalConsumption = factories.deuteriumDecomposer()->actualTotalConsumption(base->getFortressRealmID());
	status.deuteriumDecomposer.actualMetamorphosisEffectivity = factories.deuteriumDecomposer()->actualMetamorphosisEffectivity(base->getFortressRealmID());
	status.deuteriumDecomposer.actualSpaceMetamorphosisEffectivity = factories.zirconiumReactor()->actualSpaceMetamorphosisEffectivity(base->getFortressRealmID());
	status.deuteriumDecomposer.damaged = factories.deuteriumDecomposer()->getDamaged();
	status.deuteriumDecomposer.working = factories.deuteriumDecomposer()->getWorking();
	
    gctx.sendToClient(cl, answerWriter :: base_factories_information(baseid, status));

    return cl;
}

template <class T>
warehouse_parameter_type get_parameter_type(const T & value) {
	return WAREHOUSE_PARAMETER_OTHER;
}

template <>
warehouse_parameter_type get_parameter_type<unsigned long long>(const unsigned long long & value) {
	return WAREHOUSE_PARAMETER_UNSIGNED_LONG_LONG;
}

template <>
warehouse_parameter_type get_parameter_type<unsigned long>(const unsigned long & value) {
	return WAREHOUSE_PARAMETER_UNSIGNED_LONG;
}

template <>
warehouse_parameter_type get_parameter_type<long long>(const long long & value) {
	return WAREHOUSE_PARAMETER_SIGNED_LONG_LONG;
}

template <>
warehouse_parameter_type get_parameter_type<long>(const long & value) {
	return WAREHOUSE_PARAMETER_SIGNED_LONG;
}

template <>
warehouse_parameter_type get_parameter_type<double>(const double & value) {
	return WAREHOUSE_PARAMETER_DOUBLE;
}

template <class T>
void add_item_parameter(warehouse_item_status::parameters_list_t & parameters, const std::string & name, T value, bool scienceIndependent = true) {
	warehouse_item_status::parameter_t parameter;

	stringstream ss;	
	ss << value;

	parameter.name = name;
	parameter.value = ss.str();
	parameter.scienceIndependent = scienceIndependent;
	parameter.type = get_parameter_type(value);

	parameters.push_back(parameter);
}

template <class T>
bool cast_pattern(commonItemClass * item, T *& castedPattern) {
	castedPattern = dynamic_cast<T *>(item);

	if (castedPattern == NULL) {
		errLogicalError("Problem when castig item pattern class to its successor");
		return false;
	}

	return true;
}

void get_pattern_parameters(fortressClass * fortress, commonItemClass * item, warehouse_item_status::parameters_list_t & parameters)
{
	dtIdentifier realmID = fortress->getFortressRealmID();

	if (item == NULL) {
		return;
	}

	switch (item->getPatternID()) 
	{
	case PATTERN_ID_ENERGETIC_ACCUMULATOR:
		{
			energeticAccumulatorClass * castedPattern;
			if (!cast_pattern<energeticAccumulatorClass>(item, castedPattern)) {
				return;
			}

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_ACCUMULATOR, castedPattern->clientAccumulator());
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_CHARGING, castedPattern->clientCharging());
		}
		break;
	case PATTERN_ID_NAVIGATION_COMPUTER:
		{
			navigationComputerClass * castedPattern;
			if (!cast_pattern<navigationComputerClass>(item, castedPattern)) {
				return;
			}

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_MAX_SPEED_TOC, castedPattern->clientMaxSpeedToC());			
		}
		break;
	case PATTERN_ID_QUARK_GLUON_CORE:
		{
			quarkGluonCoreClass * castedPattern;
			if (!cast_pattern<quarkGluonCoreClass>(item, castedPattern)) {
				return;
			}

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_CONSUMPTION, castedPattern->clientConsumption());
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_MAX_SPEED_TOC, castedPattern->clientMaxSpeedToC());
			
		}
		break;
	case PATTERN_ID_SUBSPACE_BEACON:
		{
			subspaceBeaconClass * castedPattern;
			if (!cast_pattern<subspaceBeaconClass>(item, castedPattern)) {
				return;
			}

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_MAX_SPEED_TOC, castedPattern->clientMaxSpeedToC());			
		}
		break;
	case PATTERN_ID_INERTIAL_DAMPERS:
		{
			inertialDampersClass * castedPattern;
			if (!cast_pattern<inertialDampersClass>(item, castedPattern)) {
				return;
			}

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_MAX_SPEED_TOC, castedPattern->clientMaxSpeedToC());			
		}
		break;
	case PATTERN_ID_IMPULS_JET_ENGINE:
		{
			impulsJetEngineClass * castedPattern;
			if (!cast_pattern<impulsJetEngineClass>(item, castedPattern)) {
				return;
			}

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_CONSUMPTION, castedPattern->clientConsumption());			
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_ENGINE_FORCE, castedPattern->clientForceInGN());			
		}
		break;
	case PATTERN_ID_MECHANICAL_DAMPERS:
		{
			mechanicalDampersClass * castedPattern;
			if (!cast_pattern<mechanicalDampersClass>(item, castedPattern)) {
				return;
			}

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_MAX_ACCELERATION, castedPattern->clientMaxAcceleration());		
		}
		break;

	case PATTERN_ID_DEFLECTOR_SHIELDS:
		{
			deflectorShieldsGeneratorClass * castedPattern;
			if (!cast_pattern<deflectorShieldsGeneratorClass>(item, castedPattern)) {
				return;
			}	

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_ACCUMULATOR, castedPattern->clientAccumulator());	
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_CHARGING, castedPattern->clientCharging());	
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_LEAK, castedPattern->clientLeak());	
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_SOLIDITY, castedPattern->clientSolidity());	
		}
		break;
	case PATTERN_ID_WEAPON_ENERGY_CIRCUIT:
		{
			weaponEnergyCircuitClass * castedPattern;
			if (!cast_pattern<weaponEnergyCircuitClass>(item, castedPattern)) {
				return;
			}	

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_CHARGING, castedPattern->clientCharging());	
		}
		break;
	case PATTERN_ID_DRONE_MISSILES:
		{
			droneMissilesClass * castedPattern;
			if (!cast_pattern<droneMissilesClass>(item, castedPattern)) {
				return;
			}	

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_CHARGING, castedPattern->actualLaunch(realmID), false);	
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_RANGE, castedPattern->actualRange(realmID), false);	
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_PRECISION, castedPattern->actualPrecision(realmID), false);	
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_DAMAGE, castedPattern->actualDamage(realmID), false);
		}
		break;
	case PATTERN_ID_DRONE_MISSILE_LAUNCHER:
		{
			droneMissileLauncherClass * castedPattern;
			if (!cast_pattern<droneMissileLauncherClass>(item, castedPattern)) {
				return;
			}	

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_ACCUMULATOR, castedPattern->clientAccumulator());	
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_CHARGING, castedPattern->clientCharging());	
		}
		break;
	case PATTERN_ID_LASER_GUN:
		{
			laserGunClass * castedPattern;
			if (!cast_pattern<laserGunClass>(item, castedPattern)) {
				return;
			}	

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_ACCUMULATOR, castedPattern->clientAccumulator());	
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_CHARGING, castedPattern->clientCharging());	
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_FORCIBILITY, castedPattern->clientForcibility());
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_PRECISION, castedPattern->clientPrecision());
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_RANGE, castedPattern->clientRange());
		}
		break;
	case PATTERN_ID_TRANSPORT_BEAM_GENERATOR:
		{
			transportBeamClass * castedPattern;
			if (!cast_pattern<transportBeamClass>(item, castedPattern)) {
				return;
			}	
		}
		break;
	case PATTERN_ID_MAGNETICAL_COLLECTORS_OF_PLASMA:
		{
			magneticalCollectorsOfPlasmaClass * castedPattern;
			if (!cast_pattern<magneticalCollectorsOfPlasmaClass>(item, castedPattern)) {
				return;
			}	

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_RANGE, castedPattern->actualRange(realmID), false);	
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_TOTAL_WINDING_SPEED, castedPattern->actualTotalWindingSpeedInMilligrams(realmID), false);	
		}
		break;
	case PATTERN_ID_SUBMERSIBLE_FILTRATION_TANK:
		{
			submersibleFiltrationTankClass * castedPattern;
			if (!cast_pattern<submersibleFiltrationTankClass>(item, castedPattern)) {
				return;
			}	

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_RANGE, castedPattern->actualRange(realmID), false);	
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_TOTAL_WINDING_SPEED, castedPattern->actualTotalWindingSpeed(realmID), false);	
		}
		break;
	case PATTERN_ID_SUBMARINE_MINING_MACHINE:
		{
			submarineMiningMachineClass * castedPattern;
			if (!cast_pattern<submarineMiningMachineClass>(item, castedPattern)) {
				return;
			}	

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_RANGE, castedPattern->actualRange(realmID), false);	
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_TOTAL_WINDING_SPEED, castedPattern->actualTotalWindingSpeedInGrams(realmID), false);	
		}
		break;
	case PATTERN_ID_UNDERGROUND_DRILLIG_MACHINE:
		{
			undergroundDrillingMachineClass * castedPattern;
			if (!cast_pattern<undergroundDrillingMachineClass>(item, castedPattern)) {
				return;
			}	

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_RANGE, castedPattern->actualRange(realmID), false);	
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_TOTAL_WINDING_SPEED, castedPattern->actualTotalWindingSpeedInGrams(realmID), false);	
		}
		break;
	case PATTERN_ID_PROBE:
		{
			probeClass * castedPattern;
			if (!cast_pattern<probeClass>(item, castedPattern)) {
				return;
			}	

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_LEVEL, castedPattern->clientLevel());	
		}
		break;
	case PATTERN_ID_HIGH_RESOLUTION_SENSORS:
		{
			highResolutionSensorsClass * castedPattern;
			if (!cast_pattern<highResolutionSensorsClass>(item, castedPattern)) {
				return;
			}	

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_CONSUMPTION, castedPattern->clientConsumption());	
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_LEVEL, castedPattern->clientLevel());	
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_RANGE, castedPattern->clientRange());	
		}
		break;
	case PATTERN_ID_LONG_RANGE_SENSORS:
		{
			longRangeSensorsClass * castedPattern;
			if (!cast_pattern<longRangeSensorsClass>(item, castedPattern)) {
				return;
			}	

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_CONSUMPTION, castedPattern->clientConsumption());	
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_LEVEL, castedPattern->clientLevel());	
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_RANGE, castedPattern->clientRange());	
		}
		break;
	case PATTERN_ID_CLOAKING_DEVICE:
		{
			cloakingDeviceClass * castedPattern;
			if (!cast_pattern<cloakingDeviceClass>(item, castedPattern)) {
				return;
			}	

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_CONSUMPTION, castedPattern->clientConsumption());	
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_LEVEL, castedPattern->clientLevel());	
		}
		break;
	case PATTERN_ID_ANDROIDS:
		{
			androidsClass * castedPattern;
			if (!cast_pattern<androidsClass>(item, castedPattern)) {
				return;
			}	

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_LEVEL, castedPattern->actualLevel(realmID), false);	
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_POINTS_PER_SECOND, castedPattern->actualPointsPerSecond(fortress), false);	
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_WORKING_CONSUMPTION, castedPattern->actualWorkingConsumption(realmID), false);	
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_CONSUMPTION, castedPattern->actualConsumption(realmID), false);	
		}
		break;
	case PATTERN_ID_MAGNETICAL_GRID:
		{
			magneticalGridClass * castedPattern;
			if (!cast_pattern<magneticalGridClass>(item, castedPattern)) {
				return;
			}	

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_CAPACITY, castedPattern->actualCapacity(), false);	
		}
		break;
	case PATTERN_ID_TRANSPORT_CONTAINER:
		{
			transportContainerClass * castedPattern;
			if (!cast_pattern<transportContainerClass>(item, castedPattern)) {
				return;
			}	

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_CAPACITY, castedPattern->actualCapacity(), false);	
		}
		break;
	case PATTERN_ID_ENERGETIC_CELL:
		{
			energeticCellClass * castedPattern;
			if (!cast_pattern<energeticCellClass>(item, castedPattern)) {
				return;
			}	

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_CAPACITY, castedPattern->actualCapacity(), false);	
		}
		break;
	case PATTERN_ID_PLASMA_FILTER:
		{
			plasmaFilterClass * castedPattern;
			if (!cast_pattern<plasmaFilterClass>(item, castedPattern)) {
				return;
			}	

			bool isInWarp = false;

			if (fortress->getFortressType() == FT_SHIP) {
				isInWarp = dynamic_cast<shipClass*>(fortress)->MovementIsInWarp();
			}

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_TOTAL_FILTERING_SPEED, castedPattern->actualTotalFilteringSpeed(realmID, isInWarp), false);	
		}
		break;
	case PATTERN_ID_SCIENTIFIC_LAB:
		{
			scientificLabClass * castedPattern;
			if (!cast_pattern<scientificLabClass>(item, castedPattern)) {
				return;
			}	

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_LEVEL, castedPattern->clientLevel());	
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_CAPACITY, castedPattern->clientCapacity());	
		}
		break;
	case PATTERN_ID_LIFE_SUPPORT:
		{
			lifeSupportClass * castedPattern;
			if (!cast_pattern<lifeSupportClass>(item, castedPattern)) {
				return;
			}	

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_CAPACITY, castedPattern->clientCapacity());	
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_CONSUMPTION_FOR_ONE_PERSON, castedPattern->clientConsumptionForOnePerson());	
		}
		break;
	case PATTERN_ID_SUBSPACE_TRANSMITTER:
		{
			subspaceTransmitterClass * castedPattern;
			if (!cast_pattern<subspaceTransmitterClass>(item, castedPattern)) {
				return;
			}	

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_MESSAGE_COST, castedPattern->clientMessageCost());		
		}
		break;
	case PATTERN_ID_MAINFRAME:
		{
			mainframeClass * castedPattern;
			if (!cast_pattern<mainframeClass>(item, castedPattern)) {
				return;
			}	

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_BIO_NODES, castedPattern->clientBioNodes());		
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_CONSUMPTION, castedPattern->clientConsumption());
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_PREDICTION, castedPattern->clientPrediction());
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_TIME_REUSABILITY, castedPattern->clientTimeReusability());
		}
		break;
	case PATTERN_ID_HANGAR:
		{
			hangarClass * castedPattern;
			if (!cast_pattern<hangarClass>(item, castedPattern)) {
				return;
			}	

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_HEIGHT, castedPattern->clientHeight());		
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_LENGTH, castedPattern->clientLength());
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_LEVEL, castedPattern->clientLevel());
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_WIDTH, castedPattern->clientWidth());
		}
		break;
	case PATTERN_ID_MAGNETICAL_FILTER:
		{
			magneticalFilterClass * castedPattern;
			if (!cast_pattern<magneticalFilterClass>(item, castedPattern)) {
				return;
			}	

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_TOTAL_PRODUCTION, castedPattern->actualTotalProduction(realmID), false);		
		}
		break;
	case PATTERN_ID_DEUTERIUM_DECOMPOSER:
		{
			deuteriumDecomposerClass * castedPattern;
			if (!cast_pattern<deuteriumDecomposerClass>(item, castedPattern)) {
				return;
			}	

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_TOTAL_PRODUCTION, castedPattern->actualTotalProduction(realmID), false);		
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_METAMORPHOSIS_EFFECTIVITY, castedPattern->actualMetamorphosisEffectivity(realmID), false);			
		}
		break;
	case PATTERN_ID_ZIRCONIUM_REACTOR:
		{
			zirconiumReactorClass * castedPattern;
			if (!cast_pattern<zirconiumReactorClass>(item, castedPattern)) {
				return;
			}	

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_TOTAL_PRODUCTION, castedPattern->actualTotalProduction(realmID), false);		
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_METAMORPHOSIS_EFFECTIVITY, castedPattern->actualMetamorphosisEffectivity(realmID), false);			
		}
		break;
	case PATTERN_ID_ILMENITE_FURNACE:
		{
			ilmeniteFurnaceClass * castedPattern;
			if (!cast_pattern<ilmeniteFurnaceClass>(item, castedPattern)) {
				return;
			}	

			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_TOTAL_PRODUCTION, castedPattern->actualTotalProduction(realmID), false);		
			add_item_parameter(parameters, PROTOCOL_PARAM_NAME_METAMORPHOSIS_EFFECTIVITY, castedPattern->actualMetamorphosisEffectivity(realmID), false);			
		}
		break;
	default:			
		errLogicalError("Bad items type");
	}
}

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

id request_update_fortress_warehouses_information(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    dtIdentifier fortressid = strtoul(parameters[REQUEST_FORTRESS_WAREHOUSES_INFORMATION_FORTRESSID].c_str(), NULL, 0);
    fortressClass* fortress = actx->cacheFortressesList.getItem<fortressClass>(fortressid);

    /* pokud lod neexistuje, vrat chybu */
    if (fortress == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: fortress_warehouses_information_FAIL(fortressid, REQUEST_FORTRESS_WAREHOUSES_INFORMATION_ANSWER_FORTRESSNE));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (fortress->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: fortress_warehouses_information_FAIL(fortressid, REQUEST_FORTRESS_WAREHOUSES_INFORMATION_ANSWER_FORTRESSNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!fortress->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: fortress_warehouses_information_FAIL(fortressid, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

	warehouses_status status;
	
	warehouseClass & warehouse = fortress->warehouse;

	status.energeticCell.isAvailable = warehouse.energeticCell()->getCount() > 0;
	status.energeticCell.actualCapacity = warehouse.energeticCell()->actualCapacity();
	status.energeticCell.working = warehouse.energeticCell()->getWorking();
	status.energeticCell.damaged = warehouse.energeticCell()->getDamaged();
	status.energeticCell.count = warehouse.energeticCell()->getCount();

	status.magneticGrid.isAvailable = warehouse.magneticalGrid()->getCount() > 0;
	status.magneticGrid.actualCapacity = warehouse.magneticalGrid()->actualCapacity();
	status.magneticGrid.working = warehouse.magneticalGrid()->getWorking();
	status.magneticGrid.damaged = warehouse.magneticalGrid()->getDamaged();
	status.magneticGrid.count = warehouse.magneticalGrid()->getCount();

	status.transportContainer.isAvailable = warehouse.transportContainer()->getCount() > 0;
	status.transportContainer.actualCapacity = warehouse.transportContainer()->actualCapacity();
	status.transportContainer.working = warehouse.transportContainer()->getWorking();
	status.transportContainer.damaged = warehouse.transportContainer()->getDamaged();
	status.transportContainer.count = warehouse.transportContainer()->getCount();

	status.weight = warehouse.getWarehouseWeight();
	status.size = warehouse.getSizeOfItemsInWarehouse();
	
	for (std::list<dtIdentifier>::const_iterator it = warehouse.storageBegin(); it != warehouse.storageEnd(); ++it )  {
		commonItemClass * item = actx->cacheItemsList.getItem<commonItemClass>(*it);

		if (item == NULL) {
			continue;
		}

		warehouse_item_status itemStatus;
		itemStatus.id = item->getID();
		itemStatus.patternName = get_pattern_name_from_pattern_id(item->getPatternID());
		itemStatus.isStackable = item->isStackable();

		if (item->isStackable()) {
			stackableItemClass * stackable = dynamic_cast<stackableItemClass *>(item);
			
			if (item == NULL) {
				errLogicalError("Cannot cast item to stackable item although it should be possible");
				continue;
			}

			itemStatus.working = stackable->getWorking();
			itemStatus.damaged = stackable->getDamaged();
		}
		else {
			itemStatus.working = item->getCount();
			itemStatus.damaged = 0;
		}

		get_pattern_parameters(fortress, item, itemStatus.parameters);

		status.warehouseItems.push_back(itemStatus);
	}

	gctx.sendToClient(cl, answerWriter :: fortress_warehouses_information(fortressid, status));

    return cl;
}

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

void write_androids_assignment(const androidsAssignmentClass & gameAssignment, androids_assignment & protocolAssignment) {
	protocolAssignment.priority = gameAssignment.priority;
	protocolAssignment.ratio = gameAssignment.ratio;
}

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

void write_androids_status(fortressClass * fortress, androids_status & status) {

	status.clientAndroidsStateSliderMax = fortress->mechanics.clientAndroidsStateSliderMax();
	status.clientAndroidsStateSliderBackground = fortress->mechanics.clientAndroidsStateSliderBackground();
	status.clientWorkingAndroidsSliderValue = fortress->mechanics.clientWorkingAndroidsSliderValue();
	status.clientWorkingAndroidsSliderBackground = fortress->mechanics.clientWorkingAndroidsSliderBackground();
	status.clientWorkingAndroidsSliderMax = fortress->mechanics.clientWorkingAndroidsSliderMax();
	status.clientRepConSliderMax = fortress->mechanics.clientRepConSliderMax();
	status.clientRepConSliderValue = fortress->mechanics.clientRepConSliderValue();
	status.clientRepConSliderBackground = fortress->mechanics.clientRepConSliderBackground();

	status.actualWorkingAndroids = fortress->mechanics.getActualWorkingAndroids();
	status.actualRepairingAndroids = fortress->mechanics.getActualRepairingAndroids();
	status.actualConstructingAndroids = fortress->mechanics.getActualConstructingAndroids();

	status.androidsMinPriority = AA_MIN_PRIORITY;
	status.androidsMaxPriority = AA_MAX_PRIORITY;

	status.androidsMinRatio = 0;
	status.androidsMaxRatio = 1000000000;

	write_androids_assignment(fortress->energeticSystem.androidsAssignment, status.energeticSystem);
	write_androids_assignment(fortress->deflectorShields.androidsAssignment, status.deflectorShields);
	write_androids_assignment(fortress->weapons.androidsAssignment, status.weapons);
	write_androids_assignment(fortress->transportBeam.androidsAssignment, status.transportBeam);
	write_androids_assignment(fortress->miningDevices.androidsAssignment, status.miningDevices);
	write_androids_assignment(fortress->probeDevices.androidsAssignment, status.probeDevices);
	write_androids_assignment(fortress->sensors.androidsAssignment, status.sensors);
	write_androids_assignment(fortress->cloaking.androidsAssignment, status.cloaking);
	write_androids_assignment(fortress->mechanics.androidsAssignment, status.mechanics);
	write_androids_assignment(fortress->warehouse.androidsAssignment, status.warehouse);
	write_androids_assignment(fortress->otherEquipment.androidsAssignment, status.otherEquipment);
	write_androids_assignment(fortress->mainframeSystem.androidsAssignment, status.mainframeSystem);
	write_androids_assignment(fortress->structuralIntegrityVoidSection.androidsAssignment, status.structuralIntegrity);
}

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

id request_update_ship_androids_information(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    dtIdentifier fortressid = strtoul(parameters[REQUEST_SHIP_ANDROIDS_INFORMATION_FORTRESSID].c_str(), NULL, 0);
    shipClass * ship = actx->cacheFortressesList.getItem<shipClass>(fortressid);

    /* pokud lod neexistuje, vrat chybu */
    if (ship == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: ship_androids_information_FAIL(fortressid, REQUEST_SHIP_ANDROIDS_INFORMATION_ANSWER_FORTRESSNE));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (ship->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: ship_androids_information_FAIL(fortressid, REQUEST_SHIP_ANDROIDS_INFORMATION_ANSWER_FORTRESSNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!ship->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: ship_androids_information_FAIL(fortressid, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

	if (ship->getFortressType() != FT_SHIP) {
		gctx.sendToClient(cl, answerWriter :: ship_androids_information_FAIL(fortressid, REQUEST_SHIP_ANDROIDS_INFORMATION_ANSWER_FORTRESSNOTSHIP));
		return cl;
	}

	ship_androids_status status;

	write_androids_status(ship, status);	
	write_androids_assignment(ship->impulsDrive.androidsAssignment, status.impulsDrive);
	write_androids_assignment(ship->subspaceDrive.androidsAssignment, status.subspaceDrive);

	gctx.sendToClient(cl, answerWriter :: ship_androids_information(fortressid, status));

    return cl;
}

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

id request_update_base_androids_information(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    dtIdentifier fortressid = strtoul(parameters[REQUEST_BASE_ANDROIDS_INFORMATION_FORTRESSID].c_str(), NULL, 0);
    baseClass * base = actx->cacheFortressesList.getItem<baseClass>(fortressid);

    /* pokud lod neexistuje, vrat chybu */
    if (base == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: base_androids_information_FAIL(fortressid, REQUEST_BASE_ANDROIDS_INFORMATION_ANSWER_FORTRESSNE));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (base->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: base_androids_information_FAIL(fortressid, REQUEST_BASE_ANDROIDS_INFORMATION_ANSWER_FORTRESSNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!base->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: base_androids_information_FAIL(fortressid, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

	if (base->getFortressType() != FT_BASE) {
		gctx.sendToClient(cl, answerWriter :: base_androids_information_FAIL(fortressid, REQUEST_BASE_ANDROIDS_INFORMATION_ANSWER_FORTRESSNOTBASE));
		return cl;
	}

	base_androids_status status;

	write_androids_status(base, status);
	
	write_androids_assignment(base->hangarsPort.androidsAssignment, status.hangars);
	write_androids_assignment(base->factories.androidsAssignment, status.factories);

	gctx.sendToClient(cl, answerWriter :: base_androids_information(fortressid, status));

    return cl;
}

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

void load_androids_assignment_from_parameters(const char* section, std :: map<std :: string, std :: string>& parameters, androids_assignment& assignment)
{
    std :: stringstream ss;

	ss << section << REQUEST_ANDROIDS_ASSSIGNMENT_PRIORITY;
    assignment.priority = (unsigned char)_atoi64(parameters[ss.str()].c_str());
    ss.str(std :: string(""));

    ss << section << REQUEST_ANDROIDS_ASSSIGNMENT_RATIO;
    assignment.ratio = (unsigned int)_atoi64(parameters[ss.str()].c_str());
    ss.str(std :: string(""));
}

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

void update_game_androids_assignment(const androids_assignment & protocolAssignment, androidsAssignmentClass & gameAssignment) {
	gameAssignment.priority = protocolAssignment.priority;
	gameAssignment.ratio = protocolAssignment.ratio;
}

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

void load_androids_status_from_parameters(fortressClass * fortress, std :: map<std :: string, std :: string>& parameters, androids_request_status& status)
{
	status.workingAndroidsSlider = _strtoui64(parameters[REQUEST_CHANGE_BASE_ANDROIDS_STATE_WORKING_ANDROIDS_SLIDER].c_str(), NULL, 10);
	status.repConSlider = _strtoui64(parameters[REQUEST_CHANGE_BASE_ANDROIDS_STATE_REP_CON_SLIDER].c_str(), NULL, 10);

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

void update_game_androids_status(fortressClass * fortress, androids_request_status& status)
{
	update_game_androids_assignment(status.cloaking, fortress->cloaking.androidsAssignment);
	update_game_androids_assignment(status.deflectorShields, fortress->deflectorShields.androidsAssignment);
	update_game_androids_assignment(status.energeticSystem, fortress->energeticSystem.androidsAssignment);
	update_game_androids_assignment(status.mainframeSystem, fortress->mainframeSystem.androidsAssignment);
	update_game_androids_assignment(status.mechanics, fortress->mechanics.androidsAssignment);
	update_game_androids_assignment(status.miningDevices, fortress->miningDevices.androidsAssignment);
	update_game_androids_assignment(status.otherEquipment, fortress->otherEquipment.androidsAssignment);
	update_game_androids_assignment(status.probeDevices, fortress->probeDevices.androidsAssignment);
	update_game_androids_assignment(status.sensors, fortress->sensors.androidsAssignment);
	update_game_androids_assignment(status.transportBeam, fortress->transportBeam.androidsAssignment);
	update_game_androids_assignment(status.warehouse, fortress->warehouse.androidsAssignment);
	update_game_androids_assignment(status.weapons, fortress->weapons.androidsAssignment);
	update_game_androids_assignment(status.structuralIntegrity, fortress->structuralIntegrityVoidSection.androidsAssignment);

	fortress->mechanics.commitWorkingAndroidsSlider(status.workingAndroidsSlider);
	fortress->mechanics.commitRepConSlider(status.repConSlider);
}

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

id request_change_ship_androids_state(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	dtIdentifier fortressid = strtoul(parameters[REQUEST_CHANGE_SHIP_ANDROIDS_STATE_ANSWER_FORTRESSID].c_str(), NULL, 0);
    shipClass* fortress = actx->cacheFortressesList.getItem<shipClass>(fortressid);

    /* pokud lod neexistuje, vrat chybu */
    if (fortress == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: change_ship_androids_state_FAIL(fortressid, REQUEST_CHANGE_SHIP_ANDROIDS_STATE_ANSWER_FORTRESSNE));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (fortress->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: change_ship_androids_state_FAIL(fortressid, REQUEST_CHANGE_SHIP_ANDROIDS_STATE_ANSWER_FORTRESSNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!fortress->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: change_ship_androids_state_FAIL(fortressid, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

	if (fortress->getFortressType() != FT_SHIP) {
		gctx.sendToClient(cl, answerWriter :: change_ship_androids_state_FAIL(fortressid, REQUEST_CHANGE_SHIP_ANDROIDS_STATE_ANSWER_FORTRESSNOTSHIP));
		return cl;
	}

    /* zmenime data podle klienta */
	ship_androids_request_status status;

	load_androids_status_from_parameters(fortress, parameters, status);
	load_androids_assignment_from_parameters(REQUEST_ANDROIDS_ASSIGNMENT_SECTION_IMPULSDRIVE, parameters, status.impulsDrive);	
	load_androids_assignment_from_parameters(REQUEST_ANDROIDS_ASSIGNMENT_SECTION_SUBSPACEDRIVE, parameters, status.subspaceDrive);

	update_game_androids_status(fortress, status);
	update_game_androids_assignment(status.impulsDrive, fortress->impulsDrive.androidsAssignment);
	update_game_androids_assignment(status.subspaceDrive, fortress->subspaceDrive.androidsAssignment);

    /* odpovime clientovi s novym nastavenim */
	ship_androids_status updatedStatus;

	write_androids_status(fortress, updatedStatus);	
	write_androids_assignment(fortress->impulsDrive.androidsAssignment, updatedStatus.impulsDrive);
	write_androids_assignment(fortress->subspaceDrive.androidsAssignment, updatedStatus.subspaceDrive);

	gctx.sendToClient(cl, answerWriter :: ship_androids_information(fortressid, updatedStatus));

    return cl;
}

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

id request_change_base_androids_state(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	dtIdentifier fortressid = strtoul(parameters[REQUEST_CHANGE_BASE_ANDROIDS_STATE_ANSWER_FORTRESSID].c_str(), NULL, 0);
    baseClass* fortress = actx->cacheFortressesList.getItem<baseClass>(fortressid);

    /* pokud lod neexistuje, vrat chybu */
    if (fortress == NULL)
    {
		gctx.sendToClient(cl, answerWriter :: change_base_androids_state_FAIL(fortressid, REQUEST_CHANGE_BASE_ANDROIDS_STATE_ANSWER_FORTRESSNE));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (fortress->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: change_base_androids_state_FAIL(fortressid, REQUEST_CHANGE_BASE_ANDROIDS_STATE_ANSWER_FORTRESSNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!fortress->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: change_base_androids_state_FAIL(fortressid, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

	if (fortress->getFortressType() != FT_BASE) {
		gctx.sendToClient(cl, answerWriter :: change_base_androids_state_FAIL(fortressid, REQUEST_CHANGE_BASE_ANDROIDS_STATE_ANSWER_FORTRESSNOTBASE));
		return cl;
	}

    /* zmenime data podle klienta */
	base_androids_request_status status;

	load_androids_status_from_parameters(fortress, parameters, status);
	load_androids_assignment_from_parameters(REQUEST_ANDROIDS_ASSIGNMENT_SECTION_FACTORIES, parameters, status.factories);	
	load_androids_assignment_from_parameters(REQUEST_ANDROIDS_ASSIGNMENT_SECTION_HANGARS, parameters, status.hangars);

	update_game_androids_status(fortress, status);
	update_game_androids_assignment(status.factories, fortress->factories.androidsAssignment);
	update_game_androids_assignment(status.hangars, fortress->hangarsPort.androidsAssignment);

    /* odpovime clientovi s novym nastavenim */
	base_androids_status updatedStatus;

	write_androids_status(fortress, updatedStatus);	
	write_androids_assignment(fortress->factories.androidsAssignment, updatedStatus.factories);
	write_androids_assignment(fortress->hangarsPort.androidsAssignment, updatedStatus.hangars);

	gctx.sendToClient(cl, answerWriter :: base_androids_information(fortressid, updatedStatus));

    return cl;
}

// --------------------------------
id request_unmount_fortress_device(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	unmount_device_info data;

    data.fortressId = strtoul(parameters[REQUEST_UNMOUNT_FORTRESS_DEVICE_FORTRESSID].c_str(), NULL, 0);
	data.patternName = parameters[REQUEST_UNMOUNT_FORTRESS_DEVICE_PATTERN_NAME];

    fortressClass * fortress = actx->cacheFortressesList.getItem<fortressClass>(data.fortressId);	

    /* pokud lod neexistuje, vrat chybu */
    if (fortress == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: unmount_fortress_device_FAIL(data.fortressId, data.patternName, REQUEST_UNMOUNT_FORTRESS_DEVICE_ANSWER_FORTRESSNE));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (fortress->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: unmount_fortress_device_FAIL(data.fortressId, data.patternName, REQUEST_UNMOUNT_FORTRESS_DEVICE_ANSWER_FORTRESSNO));
        return cl;
	}

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!fortress->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: unmount_fortress_device_FAIL(data.fortressId, data.patternName, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }
	
	dtIdentifier patternId = get_pattern_id_from_pattern_name(data.patternName);

	data.working = _strtoui64(parameters[REQUEST_UNMOUNT_FORTRESS_DEVICE_WORKING].c_str(), NULL, 10);
	data.damaged = _strtoui64(parameters[REQUEST_UNMOUNT_FORTRESS_DEVICE_DAMAGED].c_str(), NULL, 10);
	data.concreteId = strtoul(parameters[REQUEST_UNMOUNT_FORTRESS_DEVICE_CONCRETEID].c_str(), NULL, 0);

	mountingResult result;

	switch (patternId) {
	case PATTERN_ID_ANDROIDS:
		result = fortress->unmountAndroids(data.working, data.damaged);
		break;
	case PATTERN_ID_CLOAKING_DEVICE:
		result = fortress->unmountCloakingDevice();
		break;
	case PATTERN_ID_DEFLECTOR_SHIELDS:
		result = fortress->unmountDeflectorShieldsGenerator();
		break;
	case PATTERN_ID_DRONE_MISSILE_LAUNCHER:
		{
			droneMissileLauncherClass * launcherGun = fortress->weapons.droneMissileLaunchersOnly(data.concreteId);

			if (launcherGun == NULL) {
				gctx.sendToClient(cl, answerWriter :: unmount_fortress_device_FAIL(data.fortressId, data.patternName, REQUEST_UNMOUNT_FORTRESS_DEVICE_ANSWER_DEVICE_NOT_EXISTS));
				return cl;
			}

			result = fortress->unmountDroneMissileLauncher(launcherGun->getID());

			break;
		}
	case PATTERN_ID_DRONE_MISSILES:
		result = fortress->unmountDroneMissiles(data.working, data.damaged);
		break;
	case PATTERN_ID_HIGH_RESOLUTION_SENSORS:
		result = fortress->unmountHighResolutionSensors();
		break;
	case PATTERN_ID_LASER_GUN:
		{
			laserGunClass * laserGun = fortress->weapons.laserGunsOnly(data.concreteId);

			if (laserGun == NULL) {
				gctx.sendToClient(cl, answerWriter :: unmount_fortress_device_FAIL(data.fortressId, data.patternName, REQUEST_UNMOUNT_FORTRESS_DEVICE_ANSWER_DEVICE_NOT_EXISTS));
				return cl;
			}

			result = fortress->unmountLaserGun(laserGun->getID());

			break;
		}		
	case PATTERN_ID_LIFE_SUPPORT:
		result = fortress->unmountLifeSupport();
		break;
	case PATTERN_ID_LONG_RANGE_SENSORS:
		result = fortress->unmountLongRangeSensors();
		break;
	case PATTERN_ID_MAGNETICAL_COLLECTORS_OF_PLASMA:
		result = fortress->unmountMagneticalCollectorsOfPlasma(data.working, data.damaged);
		break;
	case PATTERN_ID_PLASMA_FILTER:
		result = fortress->unmountPlasmaFilter();
		break;
	case PATTERN_ID_PROBE:
		result = fortress->unmountProbe(data.concreteId);
		break;
	case PATTERN_ID_SCIENTIFIC_LAB:
		result = fortress->unmountScientificLab();
		break;
	case PATTERN_ID_SUBMARINE_MINING_MACHINE:
		result = fortress->unmountSubmarineMiningMachines(data.working, data.damaged);
		break;
	case PATTERN_ID_SUBMERSIBLE_FILTRATION_TANK:
		result = fortress->unmountSubmersibleFiltrationTanks(data.working, data.damaged);
		break;
	case PATTERN_ID_SUBSPACE_TRANSMITTER:
		result = fortress->unmountSubspaceTransmitter();
		break;
	case PATTERN_ID_TRANSPORT_BEAM_GENERATOR:
		result = fortress->unmountTransportBeamGenerator();		
		break;
	case PATTERN_ID_UNDERGROUND_DRILLIG_MACHINE:
		result = fortress->unmountUndergroundDrillingMachines(data.working, data.damaged);
		break;
	case PATTERN_ID_WEAPON_ENERGY_CIRCUIT:
		result = fortress->unmountWeaponEnergyCircuit();
		break;

	case PATTERN_ID_IMPULS_JET_ENGINE:
		result = fortress->unmountImpulsJetEngine();
		break;
	case PATTERN_ID_QUARK_GLUON_CORE:
		result = fortress->unmountQuarkGluonCore();
		break;
	case PATTERN_ID_NAVIGATION_COMPUTER:
		result = fortress->unmountNavigationComputer();
		break;
	case PATTERN_ID_SUBSPACE_BEACON:
		result = fortress->unmountSubspaceBeacon();
		break;
	case PATTERN_ID_INERTIAL_DAMPERS:
		result = fortress->unmountInertialDampers();
		break;
	case PATTERN_ID_MECHANICAL_DAMPERS:
		result = fortress->unmountMechanicalDampers();
		break;
	case PATTERN_ID_HANGAR:
		{
			baseClass * base = dynamic_cast<baseClass*>(fortress);

			if (base == NULL) {
				gctx.sendToClient(cl, answerWriter :: unmount_fortress_device_FAIL(data.fortressId, data.patternName, REQUEST_UNMOUNT_FORTRESS_DEVICE_ANSWER_FORTRESS_NOT_BASE));
				return cl;
			}

			hangarClass * hangar = base->hangarsPort.hangarByIdentifier(data.concreteId);

			if (hangar == NULL) {
				gctx.sendToClient(cl, answerWriter :: unmount_fortress_device_FAIL(data.fortressId, data.patternName, REQUEST_UNMOUNT_FORTRESS_DEVICE_ANSWER_DEVICE_NOT_EXISTS));
				return cl;
			}

			result = fortress->unmountHangar(hangar->getID());
			break;
		}
	case PATTERN_ID_MAGNETICAL_FILTER:
		result = fortress->unmountMagneticalFilters(data.working, data.damaged);
		break;
	case PATTERN_ID_DEUTERIUM_DECOMPOSER:
		result = fortress->unmountDeuteriumDecomposers(data.working, data.damaged);
		break;
	case PATTERN_ID_ZIRCONIUM_REACTOR:
		result = fortress->unmountZirconiumReactors(data.working, data.damaged);
		break;
	case PATTERN_ID_ILMENITE_FURNACE:
		result = fortress->unmountIlmeniteFurnaces(data.working, data.damaged);
		break;
	default:
		result = MR_UNKNOWN_FAIL;
	}

	gctx.sendToClient(cl, answerWriter :: unmount_fortress_device(data, mounting_result_to_string(result)));

    return cl;
}

// --------------------------------
id request_mount_fortress_device(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	mount_device_info data;

	data.fortressId = strtoul(parameters[REQUEST_MOUNT_FORTRESS_DEVICE_FORTRESSID].c_str(), NULL, 0);
	data.itemId = strtoul(parameters[REQUEST_MOUNT_FORTRESS_DEVICE_ITEM_ID].c_str(), NULL, 0);

    fortressClass * fortress = actx->cacheFortressesList.getItem<fortressClass>(data.fortressId);	

    /* pokud lod neexistuje, vrat chybu */
    if (fortress == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: mount_fortress_device_FAIL(data.fortressId, data.itemId, REQUEST_MOUNT_FORTRESS_DEVICE_ANSWER_FORTRESSNE));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (fortress->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: mount_fortress_device_FAIL(data.fortressId, data.itemId, REQUEST_MOUNT_FORTRESS_DEVICE_ANSWER_FORTRESSNO));
        return cl;
	}

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!fortress->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: mount_fortress_device_FAIL(data.fortressId, data.itemId, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }
	
	data.count = _strtoui64(parameters[REQUEST_MOUNT_FORTRESS_DEVICE_COUNT].c_str(), NULL, 10);
	
	std::list<dtIdentifier>::iterator warehouseIterator = fortress->warehouse.getIteratorByID(data.itemId);

	if (warehouseIterator == fortress->warehouse.storageEnd()) {
        gctx.sendToClient(cl, answerWriter :: mount_fortress_device_FAIL(data.fortressId, data.itemId, REQUEST_MOUNT_FORTRESS_DEVICE_ANSWER_ITEM_NOT_IN_WAREHOUSE));  
        return cl;
	}

	mountingResult result = fortress->mountStoragedItem(warehouseIterator, data.count);
	gctx.sendToClient(cl, answerWriter :: mount_fortress_device(data.fortressId, data.itemId, mounting_result_to_string(result)));

    return cl;
}

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

id request_update_ship_location_information(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    dtIdentifier shipid = strtoul(parameters[REQUEST_SHIP_LOCATION_INFORMATION_SHIPID].c_str(), NULL, 0);
    shipClass* ship = actx->cacheFortressesList.getItem<shipClass>(shipid);

    /* pokud lod neexistuje, vrat chybu */
    if (ship == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: ship_location_information_FAIL(shipid, REQUEST_SHIP_LOCATION_INFORMATION_ANSWER_SHIPNE));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (ship->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: ship_location_information_FAIL(shipid, REQUEST_SHIP_LOCATION_INFORMATION_ANSWER_SHIPNO));
        return cl;
    }

	location_status status;

    status.nearestStar          = ship->MovementGetNearestStar();
    status.actualSpaceObject    = ship->MovementGetSpaceObjectActuallyIn();
    status.actualStar           = status.actualSpaceObject != 0 ? status.nearestStar : 0;

	gctx.sendToClient(cl, answerWriter :: ship_location_information(shipid, status));

    return cl;
}

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

id request_update_navigation_planets(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    dtIdentifier shipid = strtoul(parameters[REQUEST_NAVIGATION_PLANETS_SHIPID].c_str(), NULL, 0);
    shipClass* ship = actx->cacheFortressesList.getItem<shipClass>(shipid);

    /* pokud lod neexistuje, vrat chybu */
    if (ship == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: navigation_planets_FAIL(shipid, REQUEST_NAVIGATION_PLANETS_ANSWER_SHIPNE));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (ship->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: navigation_planets_FAIL(shipid, REQUEST_NAVIGATION_PLANETS_ANSWER_SHIPNO));
        return cl;
    }

	// Tady neni umyslne kontrola na to, zda je lod kontrolovatelna, protoze nekontrolovatelnost nebrani tomu, aby ziskal seznam planet

    const vector_dist_t shipPos = ship->MovementGetShipPosition();

    dtIdentifier areaid = strtoul(parameters[REQUEST_NAVIGATION_PLANETS_AREAID].c_str(), NULL, 0);
    spaceObject* sp     = actx->cacheSpaceObjectList.getItem<spaceObject>(areaid);
    if (sp != NULL)
    {
        if(sp->getType() == SOT_STAR)
        {
            spaceSunObject* sun = dynamic_cast<spaceSunObject*>(sp);
            if (sun != NULL)
            {
                protocolWriter w;                
                w.beginMessage(MT_ANSWER, REQUEST_NAVIGATION_PLANETS);
                w.writeValue(REQUEST_NAVIGATION_PLANETS_AREAID, areaid);
				w.writeValue(REQUEST_NAVIGATION_PLANETS_SHIPID, shipid);
                w.writeValue(REQUEST_NAVIGATION_PLANETS_ANSWER_COUNT, sun->subObjectCount());
                w.writeValue(REQUEST_NAVIGATION_PLANETS_ANSWER_SUN_OBJ_RADIUS, sun->getObjectRadius());
                w.writeValue(REQUEST_NAVIGATION_PLANETS_ANSWER_SUN_ARE_RADIUS, sun->getAreaRadius());
                w.writeValue(REQUEST_NAVIGATION_PLANETS_ANSWER_SUN_NAME, sun->getName());
                w.writeValue(REQUEST_NAVIGATION_PLANETS_ANSWER_SUN_WEIGHT, sun->getWeight());
                w.writeValue(REQUEST_NAVIGATION_PLANETS_ANSWER_SUN_TYPE, (unsigned long)sun->getSunType());

                /* proiterujeme planety */
                int i = 1;
                for (spaceSunObject :: dtIdentifierConstIterator iter = sun->subObjectsBegin();
                    iter != sun->subObjectsEnd(); iter++)
                {
                    // posleme udaje o planete
                    spacePlanetObject* pl = actx->cacheSpaceObjectList.getItem<spacePlanetObject>(*iter);

                    if (pl != NULL)
                    {
                        w.writeValue(make_request_fmt(REQUEST_NAVIGATION_PLANETS_ANSWER_PLANETID, i),  pl->getID());
                        w.writeValue(make_request_fmt(REQUEST_NAVIGATION_PLANETS_ANSWER_PIVOTX, i),    (signed long long)sun->getPosition().x);
                        w.writeValue(make_request_fmt(REQUEST_NAVIGATION_PLANETS_ANSWER_PIVOTY, i),    (signed long long)sun->getPosition().y);
                        w.writeValue(make_request_fmt(REQUEST_NAVIGATION_PLANETS_ANSWER_SPEED, i),     (signed long long)pl->getAngularVelocity());
                        w.writeValue(make_request_fmt(REQUEST_NAVIGATION_PLANETS_ANSWER_RADIUS, i),    (signed long long)pl->getDistanceFromParentObject());
                        w.writeValue(make_request_fmt(REQUEST_NAVIGATION_PLANETS_ANSWER_SIZE, i),      (signed long long)pl->getObjectRadius());
                        w.writeValue(make_request_fmt(REQUEST_NAVIGATION_PLANETS_ANSWER_ANGLE, i),     (signed long long)pl->getAngle());
                        w.writeValue(make_request_fmt(REQUEST_NAVIGATION_PLANETS_ANSWER_WEIGHT, i),    pl->getWeight());
                        w.writeValue(make_request_fmt(REQUEST_NAVIGATION_PLANETS_ANSWER_YEARP, i),     pl->getYearPeriod());
                        w.writeValue(make_request_fmt(REQUEST_NAVIGATION_PLANETS_ANSWER_DAYP, i),      pl->getDayPeriod());
                        w.writeValue(make_request_fmt(REQUEST_NAVIGATION_PLANETS_ANSWER_TYPE, i),      (unsigned long)pl->getPlanetType());
                        w.writeValue(make_request_fmt(REQUEST_NAVIGATION_PLANETS_ANSWER_DAYTEMP, i),   pl->getDayTemperature());
                        w.writeValue(make_request_fmt(REQUEST_NAVIGATION_PLANETS_ANSWER_NIGHTTEMP, i), pl->getNightTemperature());
                        w.writeValue(make_request_fmt(REQUEST_NAVIGATION_PLANETS_ANSWER_SEA, i),       pl->getSea());
                        w.writeValue(make_request_fmt(REQUEST_NAVIGATION_PLANETS_ANSWER_HWSO, i),      pl->getHeavyWaterSource());
                        w.writeValue(make_request_fmt(REQUEST_NAVIGATION_PLANETS_ANSWER_ZISO, i),      pl->getZirconiumSource());
                        w.writeValue(make_request_fmt(REQUEST_NAVIGATION_PLANETS_ANSWER_ILSO, i),      pl->getIlmeniteSource());
						
						w.writeValue(make_request_fmt(REQUEST_NAVIGATION_PLANETS_ANSWER_HW_MODIFIER, i),    pl->getHeavyWaterModifier());
						w.writeValue(make_request_fmt(REQUEST_NAVIGATION_PLANETS_ANSWER_ZI_MODIFIER, i),    pl->getZirconiumCrystalModifier());
						w.writeValue(make_request_fmt(REQUEST_NAVIGATION_PLANETS_ANSWER_IL_MODIFIER, i),    pl->getIlmeniteModifier());

						w.writeValue(make_request_fmt(REQUEST_NAVIGATION_PLANETS_ANSWER_NAME, i),      pl->getName());
                        w.writeValue(make_request_fmt(REQUEST_NAVIGATION_PLANETS_ANSWER_DISTSHP, i),   (pl->getAbsolutePosition() - shipPos).norm());
                    }
                    else
                    {
                        /* jedna se o spatny typ objektu */
                        errExceptionError("Space object [%u] is not a planet!", (unsigned long long)*iter);
                        gctx.sendToClient(cl, answerWriter :: navigation_planets_ie(areaid));  
                        return cl;
                    }
                    i++;
                }
               
                w.endMessage(true);
                gctx.sendToClient(cl, w.copyMessage());
            }
            else
            {
                /* jedna se o spatny typ objektu */
                errExceptionError("Space object [%u] marked as sun, but it is not a sun!", (unsigned long long)areaid);
                gctx.sendToClient(cl, answerWriter :: navigation_planets_ie(areaid));  
            }
        }
        else
        {
            /* posleme zpravu o chybe, ze dany objekt neni hvezda */
            gctx.sendToClient(cl, answerWriter :: navigation_planets_notstar(areaid));      
        }
    }
    else
    {
        /* posleme zpravu o chybe, ze dany objekt neexistuje */
        gctx.sendToClient(cl, answerWriter :: navigation_planets_nonexisting(areaid));       
    }

    return cl;
}

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

id request_update_discovered_stars(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    /* vyplnime seznam prijemcu - zatim to budou vsichni hraci */
    std :: list<shipClass*> ships;
    realmClass* realm = actx->cacheRealmsList.getItem<realmClass>(cl.first);
    if (realm != NULL)
    {
        discovered_stars ds;

        for (dtIdentifierVector :: const_iterator iter = realm->discoveredStarsBegin(); 
            iter != realm->discoveredStarsEnd(); iter++)
        {
            spaceObject* sObj = actx->cacheSpaceObjectList.getItem<spaceObject>(*iter);
            if (sObj != NULL)
            {
                discovered_star st;
                st.id   = *iter;
                st.name = sObj->getName();
                st.pos  = sObj->getAbsolutePosition();

                ds.dsc_stars.push_back(st);
            }
        }

        /* posleme seznam moznych prijemcu */
        gctx.sendToClient(cl, answerWriter :: player_discovered_stars(ds));
    }
    else
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) cl.first);
        return make_pair(0, 0);
    }

    return cl;
}

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

id request_update_trade_partner_fortresses(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    realmClass* selfRealm = actx->cacheRealmsList.getItem<realmClass>(cl.first);	

    if (selfRealm == NULL)
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) cl.first);
        return make_pair(0, 0);
	}

	dtIdentifier selfFortressId = strtoul(parameters[REQUEST_TRADE_PARTNER_FORTRESSES_FORTRESS_ID].c_str(), NULL, 0);
	fortressClass* selfFortress = actx->cacheFortressesList.getItem<fortressClass>(selfFortressId);	

    if (selfFortress == NULL)
    {
        errExceptionError("Fortress with id %u not found!", (unsigned long long) selfFortressId);
		gctx.sendToClient(cl, answerWriter :: trade_partner_fortresses_FAIL(selfFortressId, REQUEST_TRADE_PARTNER_FORTRESSES_ANSWER_FORTRESSNE));
        return make_pair(0, 0);
	}

    /* pokud pevnost hraci nepatri, vrat chybu */
    if (selfFortress->getFortressRealmID() != cl.first)
    {
		gctx.sendToClient(cl, answerWriter :: trade_partner_fortresses_FAIL(selfFortressId, REQUEST_TRADE_PARTNER_FORTRESSES_ANSWER_FORTRESSNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!selfFortress->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: trade_partner_fortresses_FAIL(selfFortressId, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

	dtIdentifierList shipsIds;
	dtIdentifierList basesIds;

	selfFortress->getFortressesInRangeForTrade(&basesIds, &shipsIds);

	std::list<fortressClass*> notOwnedFortresses;
	std::list<fortressClass*> ownedFortresses;

	for (dtIdentifierList::const_iterator it = shipsIds.begin(); it != shipsIds.end(); ++it)
	{
		fortressClass * fortress = actx->cacheFortressesList.getItem<fortressClass>(*it);

		if (fortress == NULL)
		{
			continue;
		}
		
		if (fortress->getFortressRealmID() == cl.first)
		{
			ownedFortresses.push_back(fortress);
		}
		else 
		{
			notOwnedFortresses.push_back(fortress);
		}
	}	

	for (dtIdentifierList::const_iterator it = basesIds.begin(); it != basesIds.end(); ++it)
	{
		fortressClass * fortress = actx->cacheFortressesList.getItem<fortressClass>(*it);

		if (fortress == NULL)
		{
			continue;
		}
		
		if (fortress->getFortressRealmID() == cl.first)
		{
			ownedFortresses.push_back(fortress);
		}
		else 
		{
			notOwnedFortresses.push_back(fortress);
		}
	}	

	gctx.sendToClient(cl, answerWriter :: trade_partner_fortresses(cl.first, ownedFortresses, notOwnedFortresses));

	return cl;
}

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

void init_trade_invitation(trade_invitation_data & invitation, realmClass* hostRealm, fortressClass* hostFortress, realmClass* invitedRealm, fortressClass* invitedFortress) 
{
	invitation.hostId = hostRealm->getID();
	invitation.hostName = hostRealm->getPlayerName();
	invitation.hostFortressId = hostFortress->getID();
	invitation.hostFortressName = hostFortress->getFortressName();

	invitation.invitedId = invitedRealm->getID();
	invitation.invitedName = invitedRealm->getPlayerName();
	invitation.invitedFortressId = invitedFortress->getID();
	invitation.invitedFortressName = invitedFortress->getFortressName();

	invitation.hostIsShip = hostFortress->getFortressType() == FT_SHIP;
	invitation.invitedIsShip = invitedFortress->getFortressType() == FT_SHIP;
}

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

void init_space_trade_invitation(trade_invitation_data & invitation, realmClass* hostRealm, fortressClass* hostFortress) 
{
	invitation.hostId = hostRealm->getID();
	invitation.hostName = hostRealm->getPlayerName();
	invitation.hostFortressId = hostFortress->getID();
	invitation.hostFortressName = hostFortress->getFortressName();

	invitation.invitedId = 0;
	invitation.invitedName = "";
	invitation.invitedFortressId = 0;
	invitation.invitedFortressName = "";

	invitation.hostIsShip = hostFortress->getFortressType() == FT_SHIP;
	invitation.invitedIsShip = false;
}

void get_trade_items(fortressClass* hostFortress, trade_data & data) 
{
	for (std::list<dtIdentifier>::const_iterator it = hostFortress->warehouse.storageBegin(); it != hostFortress->warehouse.storageEnd(); ++it) 
	{
		commonItemClass* storageItem = actx->cacheItemsList.getItem<commonItemClass>(*it);

		if (storageItem == NULL) 
		{
			continue;
		}

		warehouse_item_status tradeItem;
			
		tradeItem.patternName = get_pattern_name_from_pattern_id(storageItem->getPatternID());
		tradeItem.id = storageItem->getID();
		
		if (storageItem->isStackable()) 
		{
			stackableItemClass* stackableStorageItem = dynamic_cast<stackableItemClass*>(storageItem);
			
			tradeItem.isStackable = true;				
			tradeItem.working = stackableStorageItem->getWorking();
			tradeItem.damaged = stackableStorageItem->getDamaged();
		}
		else 
		{
			tradeItem.isStackable = false;
			tradeItem.working = 1;
			tradeItem.damaged = 0;
		}

		get_pattern_parameters(hostFortress, storageItem, tradeItem.parameters);

		data.tradeItems.push_back(tradeItem);
	}

	if (hostFortress->warehouse.energeticCell()->getCount() > 0) {
		warehouse_item_status energeticCell;
		energeticCell.patternName = get_pattern_name_from_pattern_id(PATTERN_ID_ENERGETIC_CELL);
		energeticCell.working = hostFortress->warehouse.energeticCell()->getWorking();
		energeticCell.damaged = hostFortress->warehouse.energeticCell()->getDamaged();
		energeticCell.id = hostFortress->warehouse.energeticCell()->getID();
		energeticCell.isStackable = true;	
		get_pattern_parameters(hostFortress, hostFortress->warehouse.energeticCell(), energeticCell.parameters);
		data.tradeItems.push_back(energeticCell);
	}

	if (hostFortress->warehouse.magneticalGrid()->getCount() > 0) {
		warehouse_item_status magneticalGrid;
		magneticalGrid.patternName = get_pattern_name_from_pattern_id(PATTERN_ID_MAGNETICAL_GRID);
		magneticalGrid.working = hostFortress->warehouse.magneticalGrid()->getWorking();
		magneticalGrid.damaged = hostFortress->warehouse.magneticalGrid()->getDamaged();
		magneticalGrid.id = hostFortress->warehouse.magneticalGrid()->getID();
		magneticalGrid.isStackable = true;
		get_pattern_parameters(hostFortress, hostFortress->warehouse.magneticalGrid(), magneticalGrid.parameters);
		data.tradeItems.push_back(magneticalGrid);
	}

	if (hostFortress->warehouse.transportContainer()->getCount() > 0) {
		warehouse_item_status transportContainer;
		transportContainer.patternName = get_pattern_name_from_pattern_id(PATTERN_ID_TRANSPORT_CONTAINER);
		transportContainer.working = hostFortress->warehouse.transportContainer()->getWorking();
		transportContainer.damaged = hostFortress->warehouse.transportContainer()->getDamaged();
		transportContainer.id = hostFortress->warehouse.transportContainer()->getID();
		transportContainer.isStackable = true;
		get_pattern_parameters(hostFortress, hostFortress->warehouse.transportContainer(), transportContainer.parameters);
		data.tradeItems.push_back(transportContainer);
	}

	hostFortress->startReadingForClient();

	data.deuterium = hostFortress->actualDeu();
	data.heavyWater = hostFortress->actualHeW();
	data.ilmenite = hostFortress->actualIlm();
	data.quarkGluonPlasma = hostFortress->actualQGP();
	data.titanium = hostFortress->actualTit();
	data.ulrea = hostFortress->actualUlr();
	data.zirconiumCrystal = hostFortress->actualZrC();
	data.energy = hostFortress->actualEng();
}

id request_send_trade_invitation(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    realmClass* selfRealm = actx->cacheRealmsList.getItem<realmClass>(cl.first);	

    if (selfRealm == NULL)
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) cl.first);
        return make_pair(0, 0);
	}

	dtIdentifier ownedFortressId = atoi(parameters[REQUEST_SEND_TRADE_INVITATION_HOST_FORTRESS_ID].c_str());
	fortressClass* selfFortress = actx->cacheFortressesList.getItem<fortressClass>(ownedFortressId);

	if (selfFortress == NULL) 
	{	
		// Self chce pozvat neexistujici partner pevnost, tak mu jen posleme, ze to selhalo
		gctx.sendToClient(cl, answerWriter :: send_trade_invitation_FAIL(
			REQUEST_SEND_TRADE_INVITATION_ANSWER_FAIL_OWNED_FORTRESS_NOT_EXISTS));

		return cl;
	}

    /* pokud pevnost hraci nepatri, vrat chybu */
    if (selfFortress->getFortressRealmID() != cl.first)
    {
		gctx.sendToClient(cl, answerWriter :: send_trade_invitation_FAIL(REQUEST_SEND_TRADE_INVITATION_ANSWER_FAIL_FORTRESSNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!selfFortress->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: send_trade_invitation_FAIL(PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

	dtIdentifier partnerFortressId = atoi(parameters[REQUEST_SEND_TRADE_INVITATION_INVITED_FORTRESS_ID].c_str());

	if (selfRealm->tradeState.isAnyTrader()) 
	{
		// V tomto pripade self hrac poslal pozvanku, server ji poslal partner hraci, ten ji prijal a poslal potvrzeni serveru.
		// Server prijal potvrzeni a zahajil obchod a poslal obema hracum informaci, ze obchod je zahajen.
		
		// To je nekorektni chovani klienta. Zaroven to ale muze znamenat, ze klient obchodoval, pak se odpojil a znovu pripojil
		// a tento puvodni stat mu zustal.
		
		gctx.sendToClient(cl, answerWriter :: send_trade_invitation_FAIL(
			REQUEST_SEND_TRADE_INVITATION_ANSWER_FAIL_YOU_ARE_TRADER_ALREADY));		
	}
	else if (selfRealm->tradeState.isHost())
	{
		// V tomto pripade self hrac poslal pozvanku, server ji poslal partner hraci, ale jeste neobdrzel jeho potvrzeni. Mezitim self
		// hrac poslal dalsi pozvanku. 
		
		// To je nekorektni chovani klienta.

		gctx.sendToClient(cl, answerWriter :: send_trade_invitation_FAIL(
			REQUEST_SEND_TRADE_INVITATION_ANSWER_FAIL_YOU_ARE_HOST_ALREADY));
	}
	else 
	{		
		// Pokud partner ma ID 0, tak hrac chce vyhazovat veci do vesmiru, to se vzdy povoli
		if (partnerFortressId == 0) 
		{
			// Obchodovani s vlastni lodi se hned povoli
			selfRealm->tradeState.becomeSpaceTrader(ownedFortressId);

			trade_invitation_data invitation;
			init_space_trade_invitation(invitation, selfRealm, selfFortress);

			trade_data selfTradeData;
			get_trade_items(selfFortress, selfTradeData);

			gctx.sendToClient(cl, answerWriter :: send_trade_invitation(invitation, selfTradeData, 
				REQUEST_SEND_TRADE_INVITATION_ANSWER_YOU_INVITED_YOURSELF,
				TRADE_ROLE_SPACE_TRADER));

			return cl;
		}
		
		fortressClass* partnerFortress = actx->cacheFortressesList.getItem<fortressClass>(partnerFortressId);

		if (partnerFortress == NULL) 
		{	
			// Self chce pozvat neexistujici partner pevnost, tak mu jen posleme, ze to selhalo
			gctx.sendToClient(cl, answerWriter :: send_trade_invitation_FAIL(
				REQUEST_SEND_TRADE_INVITATION_ANSWER_FAIL_PARTNER_FORTRESS_NOT_EXISTS));

			return cl;
		}

		dtIdentifier partnerId = partnerFortress->getFortressRealmID();
		realmClass* partnerRealm = actx->cacheRealmsList.getItem<realmClass>(partnerId);

		if (partnerRealm == NULL)
		{
			// Self chce pozvat neexistujiciho partner hrace, tak mu jen posleme, ze to selhalo
			gctx.sendToClient(cl, answerWriter :: send_trade_invitation_FAIL(
				REQUEST_SEND_TRADE_INVITATION_ANSWER_FAIL_PARTNER_NOT_EXISTS));

			return cl;
		}	

		if (partnerFortress->isControllable())
		{
			// Pokud spolu maji obchodovat dva ruzni hraci, musime jeste zkontrolovat, zda je dostupny partner hrac
			if (selfRealm->getID() != partnerRealm->getID()) 
			{
				// Hrac muze obchodovat nejvyse s jednou kontrolovatelnou lodi a s kontrolovatelnou lodi muze obchodovat nejvyse jeden hrac

				if (partnerRealm->tradeState.isAnyTrader())
				{
					// Partner hrac uz je obchoduje a vime, ze neobchoduje se self hracem, protoze to by self hrac musel byt
					// ve stavu obchodovani. Proste mu posleme pozvanku, at se rozhodne a self hraci posleme, ze se pozvanka
					// poslala, ale ze hrac prave obchoduje.

					selfRealm->tradeState.becomeHost(partnerId, partnerFortressId, ownedFortressId);

					trade_invitation_data invitation;
					init_trade_invitation(invitation, selfRealm, selfFortress, partnerRealm, partnerFortress);

					gctx.sendToClient(cl, answerWriter :: send_trade_invitation(invitation,
						REQUEST_SEND_TRADE_INVITATION_ANSWER_YOU_INVITED_BUSY_TRADER,
						TRADE_ROLE_HOST));

					gctx.sendToClient(make_pair(partnerId, 0), answerWriter :: receive_trade_invitation(invitation));
				}	
				else if (partnerRealm->tradeState.isHost())
				{				
					if (partnerRealm->tradeState.getEnemyFortressID() == cl.first)
					{
						// V tomto pripade partner hrac pozval self hrace, to znamena, ze oba hraci spolu chteji obchodovat. Partner
						// hrac taky jeste nedostal potvrzeni od self hrace, protoze ten zatim zadnou pozvanku nedostal. Znamena to, ze self hraci dorazi nejprve
						// pozvanka od partner hrace, protoze ta uz byla odeslana, partner hraci momentalne zadna zprava odeslana nebyla a tedy mu neprijde nic. 
						// Pozvanku tedy nebudeme posilat partner hraci, protoze on o obchod zrejme stoji, kdyz pozvanku poslal sam a pouze posleme self hraci
						// upozorneni, ze se tak stalo. Predpokladame, ze klient po obdrzeni pozvanky od stejneho hrace, na jehoz potvrzeni ceka, automaticky 
						// prijme aniz by se ptal uzivatele, protoze uzivatel chce zrejme obchodovat, kdyz poslal pozvanku.
			
						// Self hrac pozval
						selfRealm->tradeState.becomeHost(partnerId, partnerFortressId, ownedFortressId);

						trade_invitation_data invitation;
						init_trade_invitation(invitation, selfRealm, selfFortress, partnerRealm, partnerFortress);

						// Self hraci posleme zpravu o zacatku obchodu
						gctx.sendToClient(cl, answerWriter :: send_trade_invitation(invitation,
							REQUEST_SEND_TRADE_INVITATION_ANSWER_YOU_INVITED_YOUR_HOST,
							TRADE_ROLE_HOST));
					}
					else 
					{
						// Enemy hrac mezitim poslal nekomu pozvanku. To se muze stat, pokud oba hraci poslali pozvanku ve stejny cas v tom smyslu, ze ji jeste
						// nezpracoval server. Pozvanku urcite neposlal self hraci, protoze to by nastal pripad vyse, coz nenastalo. Proste mu posleme pozvanku,
						// at se rozhodne a self hraci posleme, ze se pozvanka poslala, ale ze hrac prave obchoduje.

						selfRealm->tradeState.becomeHost(partnerId, partnerFortressId, ownedFortressId);

						trade_invitation_data invitation;
						init_trade_invitation(invitation, selfRealm, selfFortress, partnerRealm, partnerFortress);

						gctx.sendToClient(cl, answerWriter :: send_trade_invitation(invitation,
							REQUEST_SEND_TRADE_INVITATION_ANSWER_YOU_INVITED_BUSY_HOST,
							TRADE_ROLE_HOST));


						gctx.sendToClient(make_pair(partnerId, 0), answerWriter :: receive_trade_invitation(invitation));
					}
				}	
				else 
				{
					selfRealm->tradeState.becomeHost(partnerId, partnerFortressId, ownedFortressId);

					trade_invitation_data invitation;
					init_trade_invitation(invitation, selfRealm, selfFortress, partnerRealm, partnerFortress);

					gctx.sendToClient(cl, answerWriter :: send_trade_invitation(invitation, 
						REQUEST_SEND_TRADE_INVITATION_ANSWER_YOU_INVITED_FREE_PARTNER,
						TRADE_ROLE_HOST));

					gctx.sendToClient(make_pair(partnerId, 0), answerWriter :: receive_trade_invitation(invitation));
				}
			}
			else 
			{
				// Obchodovani s vlastni lodi se hned povoli
				selfRealm->tradeState.becomeSelfTrader(cl.first, partnerFortressId, ownedFortressId);

				trade_invitation_data invitation;
				init_trade_invitation(invitation, selfRealm, selfFortress, partnerRealm, partnerFortress);

				trade_data selfTradeData;
				get_trade_items(selfFortress, selfTradeData);

				trade_data partnerTradeData;
				get_trade_items(partnerFortress, partnerTradeData);

				gctx.sendToClient(cl, answerWriter :: send_trade_invitation(invitation, selfTradeData, partnerTradeData, 
					REQUEST_SEND_TRADE_INVITATION_ANSWER_YOU_INVITED_YOURSELF,
					TRADE_ROLE_SELF_TRADER));
			}
		}
		else
		{
			// Hrac muze obchodovat nejvyse s jednou kontrolovatelnou lodi a s kontrolovatelnou lodi muze obchodovat libovolne mnoho hracu

			selfRealm->tradeState.becomeLootTrader(partnerId, partnerFortressId, ownedFortressId);

			trade_invitation_data invitation;
			init_trade_invitation(invitation, selfRealm, selfFortress, partnerRealm, partnerFortress);

			trade_data selfTradeData;
			get_trade_items(selfFortress, selfTradeData);

			trade_data partnerTradeData;
			get_trade_items(partnerFortress, partnerTradeData);

			gctx.sendToClient(cl, answerWriter :: send_trade_invitation(invitation, selfTradeData, partnerTradeData, 
				REQUEST_SEND_TRADE_INVITATION_ANSWER_YOU_INVITED_UNCONTROLLABLE,
				TRADE_ROLE_LOOT_TRADER));
		}
	}

	// TODO V metode by mela byt jeste kontrola, ze druha pevnost mezitim nezmizela z dosahu

    return cl;
}

id request_decide_trade_invitation(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    realmClass* invitedRealm = actx->cacheRealmsList.getItem<realmClass>(cl.first);	

    if (invitedRealm == NULL)
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) cl.first);
        return make_pair(0, 0);
	}

	dtIdentifier invitedFortressId = strtoul(parameters[REQUEST_DECIDE_TRADE_INVITATION_INVITED_FORTRESS_ID].c_str(), NULL, 0);
	dtIdentifier partnerFortressId = strtoul(parameters[REQUEST_DECIDE_TRADE_INVITATION_HOST_FORTRESS_ID].c_str(), NULL, 0);

	if (invitedRealm->getID() != cl.first) 
	{
		gctx.sendToClient(cl, answerWriter :: decide_trade_invitation_FAIL(partnerFortressId, invitedFortressId, REQUEST_DECIDE_TRADE_INVITATION_ANSWER_INVITED_FORTRESS_NOT_OWNED));
        return cl;
	}

	bool accepted = atoi(parameters[REQUEST_DECIDE_TRADE_INVITATION_ACCEPTED].c_str()) == 1 ? true : false;

	fortressClass * invitedFortress = actx->cacheFortressesList.getItem<fortressClass>(invitedFortressId);

	if (invitedFortress == NULL) 
	{	
		gctx.sendToClient(cl, answerWriter :: decide_trade_invitation_FAIL(
			partnerFortressId, invitedFortressId, REQUEST_DECIDE_TRADE_INVITATION_ANSWER_INVITED_FORTRESS_NOT_EXISTS));

		return cl;
	}

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!invitedFortress->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: decide_trade_invitation_FAIL(partnerFortressId, invitedFortressId, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

	fortressClass * hostFortress = actx->cacheFortressesList.getItem<fortressClass>(partnerFortressId);

	if (hostFortress == NULL) 
	{	
		// Self chce pozvat neexistujici partner pevnost, tak mu jen posleme, ze to selhalo
		gctx.sendToClient(cl, answerWriter :: decide_trade_invitation_FAIL(
			partnerFortressId, invitedFortressId, REQUEST_DECIDE_TRADE_INVITATION_ANSWER_PARTNER_FORTRESS_NOT_EXISTS));

		return cl;
	}

	realmClass * hostRealm = hostFortress->getFortressRealm();

	if (hostRealm == NULL)
	{
		errExceptionError("Player realm with id %u not found!", (unsigned long long) hostFortress->getFortressRealmID());
        return make_pair(0, 0);
	}

	if (!hostRealm->tradeState.isHost())
	{
		// Self odpovida na neplatnou pozvanku
		gctx.sendToClient(cl, answerWriter :: decide_trade_invitation_FAIL(
			partnerFortressId, invitedFortressId, REQUEST_DECIDE_TRADE_INVITATION_ANSWER_INVITATION_NOT_EXISTS));

		return cl;
	}

	// Pokud partner hrac opravdu pozval pevnost self hrace, tak je odpoved na pozvanku pripustna
	if (hostRealm->tradeState.getEnemyFortressID() != invitedFortressId) 
	{
		// Self odpovida na neplatnou pozvanku
		gctx.sendToClient(cl, answerWriter :: decide_trade_invitation_FAIL(
			partnerFortressId, invitedFortressId, REQUEST_DECIDE_TRADE_INVITATION_ANSWER_INVITATION_NOT_EXISTS));

		return cl;
	}

	if (accepted) 
	{
		// Pokud by self hrac uz obchodoval s partnerem, tak se musi zrusit jeho aktivni obchod a ohlasit to druhemu hraci. 
		if (invitedRealm->tradeState.isPartnerTrader())
		{
			realmClass * partnerRealm = actx->cacheRealmsList.getItem<realmClass>(invitedRealm->tradeState.getEnemyID());

			if (partnerRealm != NULL) {
				partnerRealm->tradeState.cancelTrade();
			}

			// Zrusime selfovu spoluhraci obchod
			gctx.sendToClient(make_pair(invitedRealm->tradeState.getEnemyID(), 0), answerWriter :: receive_cancel_trade(
				invitedRealm->tradeState.getEnemyFortressID(), invitedRealm->tradeState.getOwnedFortressID()));
		}
		// Pokud by self hrac uz nekoho pozval, tak se musi zrusit jeho pozvanka a ohlasit to druhemu hraci. 
		else if (invitedRealm->tradeState.isHost())
		{
			realmClass * partnerRealm = actx->cacheRealmsList.getItem<realmClass>(invitedRealm->tradeState.getEnemyID());

			if (partnerRealm != NULL) {
				partnerRealm->tradeState.cancelTrade();
			}

			// Zrusime selfovu spoluhraci obchod
			gctx.sendToClient(make_pair(invitedRealm->tradeState.getEnemyID(), 0), answerWriter :: receive_cancel_trade(
				invitedRealm->tradeState.getEnemyFortressID(), invitedRealm->tradeState.getOwnedFortressID()));
		}

		// Dusledkem toho, ze self hrac nyni bude trade je to, ze pokud by predtim self hrac byl inviter a nekdo mu
		// kladne odpovedel na pozvanku, tak uz bude mit smulu, protoze self hrac uz bude obchodovat, tedy v predchozi
		// vetvi accepted se odmitne

		invitedRealm->tradeState.becomePartnerTrader(hostRealm->getID(), hostFortress->getID(), invitedFortress->getID());
		hostRealm->tradeState.becomePartnerTrader(invitedRealm->getID(), invitedFortress->getID(), hostFortress->getID());

		trade_invitation_data invitation;
		init_trade_invitation(invitation, hostRealm, hostFortress, invitedRealm, invitedFortress);

		trade_data hostTradeData;
		get_trade_items(hostFortress, hostTradeData);

		trade_data invitedTradeData;
		get_trade_items(invitedFortress, invitedTradeData);

		gctx.sendToClient(cl, answerWriter :: decide_trade_invitation(invitation, invitedTradeData));
		gctx.sendToClient(make_pair(hostRealm->getID(), 0), answerWriter :: receive_trade_invitation_decision(invitation, hostTradeData));
	}
	else
	{
		// Self hraci nemenime stav, protoze muze byt inviter pro jinou pozvanku, coz chceme zachovat
		 
		hostRealm->tradeState.cancelTrade();

		trade_invitation_data invitation;
		init_trade_invitation(invitation, hostRealm, hostFortress, invitedRealm, invitedFortress);

		gctx.sendToClient(cl, answerWriter :: decide_trade_invitation(invitation));
		gctx.sendToClient(make_pair(hostRealm->getID(), 0), answerWriter :: receive_trade_invitation_decision(invitation));
	}

	return cl;
}

void init_trade_movement_data_from_client_data(const trade_client_movement_data & clientData, trade_movement_data & serverData, fortressClass * fortress, commonItemClass * item) 
{
	serverData.selfFortressId = clientData.selfFortressId;
	serverData.partnerFortressId = clientData.partnerFortressId;
	serverData.tradeDirection = clientData.tradeDirection;
	serverData.item.id = clientData.itemId;
	serverData.item.patternName = clientData.patternName;
	serverData.item.working = clientData.working;
	serverData.item.damaged = clientData.damaged;

	get_pattern_parameters(fortress, item, serverData.item.parameters);
}

id request_move_trade_item(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters) 
{
	realmClass* selfRealm = actx->cacheRealmsList.getItem<realmClass>(cl.first);	
	
	trade_client_movement_data tradeData;

	tradeData.selfFortressId = strtoul(parameters[TRADE_CLIENT_MOVEMENT_DATA_SELF_FORTRESS_ID].c_str(), NULL, 0);
	fortressClass* selfFortress = actx->cacheFortressesList.getItem<fortressClass>(tradeData.selfFortressId);

	tradeData.partnerFortressId = strtoul(parameters[TRADE_CLIENT_MOVEMENT_DATA_PARTNER_FORTRESS_ID].c_str(), NULL, 0);
	fortressClass* partnerFortress = actx->cacheFortressesList.getItem<fortressClass>(tradeData.partnerFortressId);

	tradeData.itemId = strtoul(parameters[TRADE_CLIENT_MOVEMENT_DATA_ITEM_ID].c_str(), NULL, 0);

	if (selfFortress == NULL) {
		gctx.sendToClient(cl, answerWriter :: move_trade_item_FAIL(tradeData, REQUEST_MOVE_TRADE_ITEM_ANSWER_FAIL_SOURCE_FORTRESS_NOT_EXISTS));
		return cl;
	}

	if (!selfRealm->tradeState.isAnyTrader()) {
		gctx.sendToClient(cl, answerWriter :: move_trade_item_FAIL(tradeData, REQUEST_MOVE_TRADE_ITEM_ANSWER_FAIL_YOU_ARE_NOT_TRADER));
		return cl;
	}

	if (selfRealm->tradeState.getOwnedFortressID() != selfFortress->getID()) {
		gctx.sendToClient(cl, answerWriter :: move_trade_item_FAIL(tradeData, REQUEST_MOVE_TRADE_ITEM_ANSWER_FAIL_SOURCE_FORTRESS_NOT_PARTNER));
		return cl;
	}

	if (!selfRealm->tradeState.isSpaceTrader()) {
		// Pokud nevyhazujeme do vesmiru, musime zkontrolovat jeste obchodniho partnera 

		if (partnerFortress == NULL) {
			gctx.sendToClient(cl, answerWriter :: move_trade_item_FAIL(tradeData, REQUEST_MOVE_TRADE_ITEM_ANSWER_FAIL_TARGET_FORTRESS_NOT_EXISTS));
			return cl;
		}

		if (selfRealm->tradeState.getEnemyFortressID() != partnerFortress->getID()) {
			gctx.sendToClient(cl, answerWriter :: move_trade_item_FAIL(tradeData, REQUEST_MOVE_TRADE_ITEM_ANSWER_FAIL_TARGET_FORTRESS_NOT_PARTNER));
			return cl;
		}

		if (selfRealm->tradeState.getEnemyID() != partnerFortress->getFortressRealmID()) {
			gctx.sendToClient(cl, answerWriter :: move_trade_item_FAIL(tradeData, REQUEST_MOVE_TRADE_ITEM_ANSWER_FAIL_TARGET_REALM_NOT_PARTNER));
			return cl;
		}
	}

	realmClass * partnerRealm = actx->cacheRealmsList.getItem<realmClass>(selfRealm->tradeState.getEnemyID());

	tradeData.patternName = parameters[TRADE_CLIENT_MOVEMENT_DATA_PATTERN_NAME];
	tradeData.tradeDirection = parameters[TRADE_CLIENT_MOVEMENT_DATA_TRADE_DIRECTION];

	tradeData.working = _strtoui64(parameters[TRADE_CLIENT_MOVEMENT_DATA_WORKING].c_str(), NULL, 10);
	tradeData.damaged = _strtoui64(parameters[TRADE_CLIENT_MOVEMENT_DATA_DAMAGED].c_str(), NULL, 10);	
	
	dtIdentifier patternId = get_pattern_id_from_pattern_name(tradeData.patternName);
	itemsPatternClass* itemPattern = actx->cacheItemsPatternsList.getItem<itemsPatternClass>(patternId);

	if (itemPattern == NULL) {
		gctx.sendToClient(cl, answerWriter :: move_trade_item_FAIL(tradeData, REQUEST_MOVE_TRADE_ITEM_ANSWER_FAIL_UNKNOWN_ITEM));
		return cl;
	}

	commonItemClass * item = actx->cacheItemsList.getItem<commonItemClass>(tradeData.itemId);

	if (item == NULL) {
		gctx.sendToClient(cl, answerWriter :: move_trade_item_FAIL(tradeData, REQUEST_MOVE_TRADE_ITEM_ANSWER_FAIL_UNKNOWN_ITEM));
		return cl;
	}

	if (tradeData.tradeDirection == TRADE_DIRECTION_OWNED_OFFER) 
	{
		trade_movement_data movementData;
		init_trade_movement_data_from_client_data(tradeData, movementData, selfFortress, item);
		selfRealm->tradeState.getTradeBundle()->insertItem(tradeData.itemId, tradeData.working, tradeData.damaged);
		gctx.sendToClient(cl, answerWriter :: move_trade_item(movementData, true));

		if (selfRealm->tradeState.isPartnerTrader()) 
		{
			gctx.sendToClient(make_pair(partnerRealm->getID(), 0), answerWriter :: move_trade_item(movementData, false));
		}
	}
	else if (tradeData.tradeDirection == TRADE_DIRECTION_OWNED_ITEMS) 
	{
		trade_movement_data movementData;
		init_trade_movement_data_from_client_data(tradeData, movementData, selfFortress, item);

		selfRealm->tradeState.getTradeBundle()->deleteItem(tradeData.itemId, tradeData.working, tradeData.damaged);
		gctx.sendToClient(cl, answerWriter :: move_trade_item(movementData, true));

		if (selfRealm->tradeState.isPartnerTrader()) 
		{
			gctx.sendToClient(make_pair(partnerRealm->getID(), 0), answerWriter :: move_trade_item(movementData, false));
		}
	}
	else if (tradeData.tradeDirection == TRADE_DIRECTION_PARTNER_OFFER)  
	{
		// Aby mohl presouvat z partnerske nebo do partnerske pevnosti, tak musi obchodovat sam se sebou
		if (selfRealm->tradeState.isSelfTrader() || selfRealm->tradeState.isLootTrader()) 
		{
			trade_movement_data movementData;
			init_trade_movement_data_from_client_data(tradeData, movementData, selfFortress, item);

			selfRealm->tradeState.getPartnerTradeBundle()->insertItem(tradeData.itemId, tradeData.working, tradeData.damaged);
			gctx.sendToClient(cl, answerWriter :: move_trade_item(movementData, true));
		}
		else 
		{
			gctx.sendToClient(cl, answerWriter :: move_trade_item_FAIL(tradeData, REQUEST_MOVE_TRADE_ITEM_ANSWER_FAIL_FORBIDDEN_DIRECTION));
		}
	}
	else if (tradeData.tradeDirection == TRADE_DIRECTION_PARTNER_ITEMS)  
	{
		// Aby mohl presouvat z partnerske nebo do partnerske pevnosti, tak musi obchodovat sam se sebou
		if (selfRealm->tradeState.isSelfTrader() || selfRealm->tradeState.isLootTrader()) 
		{
			trade_movement_data movementData;
			init_trade_movement_data_from_client_data(tradeData, movementData, selfFortress, item);

			selfRealm->tradeState.getPartnerTradeBundle()->deleteItem(tradeData.itemId, tradeData.working, tradeData.damaged);
			gctx.sendToClient(cl, answerWriter :: move_trade_item(movementData, true));
		}
		else 
		{
			gctx.sendToClient(cl, answerWriter :: move_trade_item_FAIL(tradeData, REQUEST_MOVE_TRADE_ITEM_ANSWER_FAIL_FORBIDDEN_DIRECTION));
		}
	}

	return cl;
}

id request_move_trade_resource(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters) 
{
	realmClass* selfRealm = actx->cacheRealmsList.getItem<realmClass>(cl.first);	
	
	trade_resource_movement_data tradeData;

	tradeData.selfFortressId = strtoul(parameters[TRADE_RESOURCE_MOVEMENT_DATA_SELF_FORTRESS_ID].c_str(), NULL, 0);
	fortressClass* selfFortress = actx->cacheFortressesList.getItem<fortressClass>(tradeData.selfFortressId);

	tradeData.partnerFortressId = strtoul(parameters[TRADE_RESOURCE_MOVEMENT_DATA_PARTNER_FORTRESS_ID].c_str(), NULL, 0);
	fortressClass* partnerFortress = actx->cacheFortressesList.getItem<fortressClass>(tradeData.partnerFortressId);

	tradeData.resourceType = stringToResourceType(parameters[TRADE_RESOURCE_MOVEMENT_DATA_RESOURCE_TYPE]);

	if (selfFortress == NULL) {
		gctx.sendToClient(cl, answerWriter :: move_trade_resource_FAIL(tradeData, REQUEST_MOVE_TRADE_RESOURCE_ANSWER_FAIL_SOURCE_FORTRESS_NOT_EXISTS));
		return cl;
	}

	if (partnerFortress == NULL) {
		gctx.sendToClient(cl, answerWriter :: move_trade_resource_FAIL(tradeData, REQUEST_MOVE_TRADE_RESOURCE_ANSWER_FAIL_TARGET_FORTRESS_NOT_EXISTS));
		return cl;
	}

	if (!selfRealm->tradeState.isAnyTrader()) {
		gctx.sendToClient(cl, answerWriter :: move_trade_resource_FAIL(tradeData, REQUEST_MOVE_TRADE_RESOURCE_ANSWER_FAIL_YOU_ARE_NOT_TRADER));
		return cl;
	}

	if (selfRealm->tradeState.getOwnedFortressID() != selfFortress->getID()) {
		gctx.sendToClient(cl, answerWriter :: move_trade_resource_FAIL(tradeData, REQUEST_MOVE_TRADE_RESOURCE_ANSWER_FAIL_SOURCE_FORTRESS_NOT_PARTNER));
		return cl;
	}

	if (selfRealm->tradeState.getEnemyFortressID() != partnerFortress->getID()) {
		gctx.sendToClient(cl, answerWriter :: move_trade_resource_FAIL(tradeData, REQUEST_MOVE_TRADE_RESOURCE_ANSWER_FAIL_TARGET_FORTRESS_NOT_PARTNER));
		return cl;
	}

	if (selfRealm->tradeState.getEnemyID() != partnerFortress->getFortressRealmID()) {
		gctx.sendToClient(cl, answerWriter :: move_trade_resource_FAIL(tradeData, REQUEST_MOVE_TRADE_RESOURCE_ANSWER_FAIL_TARGET_REALM_NOT_PARTNER));
		return cl;
	}

	realmClass * partnerRealm = actx->cacheRealmsList.getItem<realmClass>(selfRealm->tradeState.getEnemyID());

	tradeData.count = _strtoui64(parameters[TRADE_RESOURCE_MOVEMENT_DATA_COUNT].c_str(), NULL, 10);
	tradeData.tradeDirection = parameters[TRADE_RESOURCE_MOVEMENT_DATA_TRADE_DIRECTION];

	tradeBundleClass * tradeBundle = 0;

	if (tradeData.tradeDirection == TRADE_DIRECTION_OWNED_OFFER) 
	{
		tradeBundle = selfRealm->tradeState.getTradeBundle();
	}
	else if (tradeData.tradeDirection == TRADE_DIRECTION_PARTNER_OFFER) 
	{
		tradeBundle = selfRealm->tradeState.getPartnerTradeBundle();
	}
	else
	{
		gctx.sendToClient(cl, answerWriter :: move_trade_resource_FAIL(tradeData, REQUEST_MOVE_TRADE_RESOURCE_ANSWER_FAIL_FORBIDDEN_DIRECTION));
		return cl;
	}

	switch (tradeData.resourceType) 
	{
	case GAME_RESOURCE_TYPE_DEUTERIUM: 
		if (tradeData.count >= tradeBundle->getUlreaCount()) {
			tradeBundle->insertUlrea(tradeData.count - tradeBundle->getUlreaCount());
		}
		else {
			tradeBundle->deleteUlrea(tradeBundle->getUlreaCount() - tradeData.count);
		}
		break;
	case GAME_RESOURCE_TYPE_ENERGY:
	if (tradeData.count >= tradeBundle->getEnergyInTJ()) {
			tradeBundle->insertEnergy(tradeData.count - tradeBundle->getEnergyInTJ());
		}
		else {
			tradeBundle->insertEnergy(tradeBundle->getEnergyInTJ() - tradeData.count);
		}
		break;
	case GAME_RESOURCE_TYPE_HEAVY_WATER:
		if (tradeData.count >= tradeBundle->getHeavyWaterInKg()) {
			tradeBundle->insertHeavyWater(tradeData.count - tradeBundle->getHeavyWaterInKg());
		}
		else {
			tradeBundle->insertHeavyWater(tradeBundle->getHeavyWaterInKg() - tradeData.count);
		}
		break;
	case GAME_RESOURCE_TYPE_ILMENITE:
		if (tradeData.count >= tradeBundle->getIlmeniteInKg()) {
			tradeBundle->insertIlmenite(tradeData.count - tradeBundle->getIlmeniteInKg());
		}
		else {
			tradeBundle->insertIlmenite(tradeBundle->getIlmeniteInKg() - tradeData.count);
		}
		break;
	case GAME_RESOURCE_TYPE_QUARK_GLUON_PLASMA:
		if (tradeData.count >= tradeBundle->getQuarkGluonPlasmaInMg()) {
			tradeBundle->insertQuarkGluonPlasma(tradeData.count - tradeBundle->getQuarkGluonPlasmaInMg());
		}
		else {
			tradeBundle->insertQuarkGluonPlasma(tradeBundle->getQuarkGluonPlasmaInMg() - tradeData.count);
		}
		break;
	case GAME_RESOURCE_TYPE_TITANIUM:
		if (tradeData.count >= tradeBundle->getTitaniumInKg()) {
			tradeBundle->insertTitanium(tradeData.count - tradeBundle->getTitaniumInKg());
		}
		else {
			tradeBundle->insertTitanium(tradeBundle->getTitaniumInKg() - tradeData.count);
		}
		break;
	case GAME_RESOURCE_TYPE_ULREA:
		if (tradeData.count >= tradeBundle->getUlreaCount()) {
			tradeBundle->insertUlrea(tradeData.count - tradeBundle->getUlreaCount());
		}
		else {
			tradeBundle->insertUlrea(tradeBundle->getUlreaCount() - tradeData.count);
		}
		break;
	case GAME_RESOURCE_TYPE_ZIRCONIUM_CRYSTALS:
		if (tradeData.count >= tradeBundle->getZirconiumCrystalInKg()) {
			tradeBundle->insertZirconiumCrystal(tradeData.count - tradeBundle->getZirconiumCrystalInKg());
		}
		else {
			tradeBundle->insertZirconiumCrystal(tradeBundle->getZirconiumCrystalInKg() - tradeData.count);
		}
		break;
	}

	gctx.sendToClient(cl, answerWriter :: move_trade_resource(tradeData, true));

	if (selfRealm->tradeState.isPartnerTrader()) 
	{
		gctx.sendToClient(make_pair(partnerRealm->getID(), 0), answerWriter :: move_trade_resource(tradeData, false));
	}

	return cl;
}

void read_trade_data(std::map<std::string, std::string>& parameters, const std::string & prefix, tradeBundleClass * tradeBundle)
{
	unsigned long itemCount = strtoul(parameters[create_param_name(prefix, TRADE_ITEM_DATA_ITEM_COUNT)].c_str(), NULL, 0);

	for (unsigned long index = 1; index < itemCount + 1; ++index) {
		client_trade_item_data itemData;

		dtIdentifier id = strtoul((parameters[create_param_name(prefix, TRADE_ITEM_DATA_ID, index)]).c_str(), NULL, 0);
		unsigned long long working = _strtoui64((parameters[create_param_name(prefix, TRADE_ITEM_DATA_WORKING, index)]).c_str(), NULL, 10);
		unsigned long long damaged = _strtoui64((parameters[create_param_name(prefix, TRADE_ITEM_DATA_DAMAGED, index)]).c_str(), NULL, 10);

		tradeBundle->insertItem(id, working, damaged);
	}

	unsigned long long deuterium = _strtoui64((parameters[create_param_name(prefix, TRADE_ITEM_DATA_DEUTERIUM)]).c_str(), NULL, 10);
	unsigned long long heavyWater = _strtoui64((parameters[create_param_name(prefix, TRADE_ITEM_DATA_HEAVY_WATER)]).c_str(), NULL, 10);
	unsigned long long ilmenite = _strtoui64((parameters[create_param_name(prefix, TRADE_ITEM_DATA_ILMENITE)]).c_str(), NULL, 10);
	unsigned long long quarkGluonPlasma = _strtoui64((parameters[create_param_name(prefix, TRADE_ITEM_DATA_QUARK_GLUON_PLASMA)]).c_str(), NULL, 10);
	unsigned long long titanium = _strtoui64((parameters[create_param_name(prefix, TRADE_ITEM_DATA_TITANIUM)]).c_str(), NULL, 10);
	unsigned long long ulrea = _strtoui64((parameters[create_param_name(prefix, TRADE_ITEM_DATA_ULREA)]).c_str(), NULL, 10);
	unsigned long long zirconiumCrystal = _strtoui64((parameters[create_param_name(prefix, TRADE_ITEM_DATA_ZIRCONIUM_CRYSTAL)]).c_str(), NULL, 10);
	unsigned long long energy = _strtoui64((parameters[create_param_name(prefix, TRADE_ITEM_DATA_ENERGY)]).c_str(), NULL, 10);

	tradeBundle->insertDeuterium(deuterium);
	tradeBundle->insertHeavyWater(heavyWater);
	tradeBundle->insertIlmenite(ilmenite);
	tradeBundle->insertQuarkGluonPlasma(quarkGluonPlasma);
	tradeBundle->insertTitanium(titanium);
	tradeBundle->insertUlrea(ulrea);
	tradeBundle->insertZirconiumCrystal(zirconiumCrystal);
	tradeBundle->insertEnergy(energy);
}

void inspect_trade_result(id cl, realmClass * selfRealm, realmClass * partnerRealm, tradingResult tradeResult) 
{	
	// POZOR! Pri posilani duvodu neuspechu druhemu hraci musime obratit stav.
	// Pro druheho hrace posilame, ze prvni pevnost nesplnuje podminku.

	dtIdentifier selfFortressId = selfRealm->tradeState.getOwnedFortressID();
	dtIdentifier partnerFortressId = selfRealm->tradeState.getEnemyFortressID();

	bool isPartnerTrader = selfRealm->tradeState.isPartnerTrader();

	switch (tradeResult) {
	case TR_DONE:
		selfRealm->tradeState.commitTrade();				
		gctx.sendToClient(cl, answerWriter::commit_trade(selfFortressId, partnerFortressId, TR_DONE));

		if (isPartnerTrader) 
		{
			partnerRealm->tradeState.commitTrade();
			gctx.sendToClient(make_pair(partnerRealm->getID(), 0), answerWriter::commit_trade(partnerFortressId, selfFortressId, TR_DONE));
		}

		break;
	case TR_FIRST_FORTRESS_WEIGHT_LIMIT:
		selfRealm->tradeState.cancelCommit();
		gctx.sendToClient(cl, answerWriter::commit_trade(selfFortressId, partnerFortressId, TR_FIRST_FORTRESS_WEIGHT_LIMIT));

		if (isPartnerTrader) 
		{
			partnerRealm->tradeState.cancelCommit();
			gctx.sendToClient(make_pair(partnerRealm->getID(), 0), answerWriter::commit_trade(partnerFortressId, selfFortressId, TR_SECOND_FORTRESS_WEIGHT_LIMIT));
		}

		break;
	case TR_SECOND_FORTRESS_WEIGHT_LIMIT:
		selfRealm->tradeState.cancelCommit();
		gctx.sendToClient(cl, answerWriter::commit_trade(selfFortressId, partnerFortressId, TR_SECOND_FORTRESS_WEIGHT_LIMIT));

		if (isPartnerTrader) 
		{
			partnerRealm->tradeState.cancelCommit();
			gctx.sendToClient(make_pair(partnerRealm->getID(), 0), answerWriter::commit_trade(partnerFortressId, selfFortressId, TR_FIRST_FORTRESS_WEIGHT_LIMIT));
		}

		break;
	case TR_FIRST_FORTRESS_CAPACITY_LIMIT:
		selfRealm->tradeState.cancelCommit();
		gctx.sendToClient(cl, answerWriter::commit_trade(selfFortressId, partnerFortressId, TR_FIRST_FORTRESS_CAPACITY_LIMIT));

		if (isPartnerTrader) 
		{
			partnerRealm->tradeState.cancelCommit();
			gctx.sendToClient(make_pair(partnerRealm->getID(), 0), answerWriter::commit_trade(partnerFortressId, selfFortressId, TR_SECOND_FORTRESS_CAPACITY_LIMIT));
		}

		break;
	case TR_SECOND_FORTRESS_CAPACITY_LIMIT:
		selfRealm->tradeState.cancelCommit();
		gctx.sendToClient(cl, answerWriter::commit_trade(selfFortressId, partnerFortressId, TR_SECOND_FORTRESS_CAPACITY_LIMIT));

		if (isPartnerTrader) 
		{
			partnerRealm->tradeState.cancelCommit();
			gctx.sendToClient(make_pair(partnerRealm->getID(), 0), answerWriter::commit_trade(partnerFortressId, selfFortressId, TR_FIRST_FORTRESS_CAPACITY_LIMIT));
		}

		break;
	case TR_FIRST_FORTRESS_NOT_STORING_ITEMS:
		selfRealm->tradeState.cancelTrade();
		partnerRealm->tradeState.cancelTrade();

		gctx.sendToClient(cl, answerWriter::commit_trade(selfFortressId, partnerFortressId, TR_FIRST_FORTRESS_NOT_STORING_ITEMS));

		if (isPartnerTrader) 
		{
			partnerRealm->tradeState.cancelCommit();
			gctx.sendToClient(make_pair(partnerRealm->getID(), 0), answerWriter::commit_trade(partnerFortressId, selfFortressId, TR_SECOND_FORTRESS_NOT_STORING_ITEMS));
		}

		break;
	case TR_SECOND_FORTRESS_NOT_STORING_ITEMS:
		selfRealm->tradeState.cancelTrade();
		partnerRealm->tradeState.cancelTrade();

		gctx.sendToClient(cl, answerWriter::commit_trade(selfFortressId, partnerFortressId, TR_SECOND_FORTRESS_NOT_STORING_ITEMS));
				
		if (isPartnerTrader) 
		{
			partnerRealm->tradeState.cancelCommit();
			gctx.sendToClient(make_pair(partnerRealm->getID(), 0), answerWriter::commit_trade(partnerFortressId, selfFortressId, TR_FIRST_FORTRESS_NOT_STORING_ITEMS));
		}

		break;
	case TR_FIRST_FORTRESS_MAGNETICAL_GRIDS_LACK:
		selfRealm->tradeState.cancelCommit();
		gctx.sendToClient(cl, answerWriter::commit_trade(selfFortressId, partnerFortressId, TR_FIRST_FORTRESS_MAGNETICAL_GRIDS_LACK));

		if (isPartnerTrader) 
		{
			partnerRealm->tradeState.cancelCommit();
			gctx.sendToClient(make_pair(partnerRealm->getID(), 0), answerWriter::commit_trade(partnerFortressId, selfFortressId, TR_SECOND_FORTRESS_MAGNETICAL_GRIDS_LACK));
		}

		break;
	case TR_SECOND_FORTRESS_MAGNETICAL_GRIDS_LACK:
		selfRealm->tradeState.cancelCommit();
		gctx.sendToClient(cl, answerWriter::commit_trade(selfFortressId, partnerFortressId, TR_SECOND_FORTRESS_MAGNETICAL_GRIDS_LACK));

		if (isPartnerTrader) 
		{
			partnerRealm->tradeState.cancelCommit();
			gctx.sendToClient(make_pair(partnerRealm->getID(), 0), answerWriter::commit_trade(partnerFortressId, selfFortressId, TR_FIRST_FORTRESS_MAGNETICAL_GRIDS_LACK));
		}

		break;
	case TR_FIRST_FORTRESS_TRANSPORT_CONTAINERS_LACK:
		selfRealm->tradeState.cancelCommit();
		gctx.sendToClient(cl, answerWriter::commit_trade(selfFortressId, partnerFortressId, TR_FIRST_FORTRESS_TRANSPORT_CONTAINERS_LACK));

		if (isPartnerTrader) 
		{
			partnerRealm->tradeState.cancelCommit();
			gctx.sendToClient(make_pair(partnerRealm->getID(), 0), answerWriter::commit_trade(partnerFortressId, selfFortressId, TR_SECOND_FORTRESS_TRANSPORT_CONTAINERS_LACK));
		}

		break;
	case TR_SECOND_FORTRESS_TRANSPORT_CONTAINERS_LACK:
		selfRealm->tradeState.cancelCommit();
		gctx.sendToClient(cl, answerWriter::commit_trade(selfFortressId, partnerFortressId, TR_SECOND_FORTRESS_TRANSPORT_CONTAINERS_LACK));

		if (isPartnerTrader) 
		{
			partnerRealm->tradeState.cancelCommit();
			gctx.sendToClient(make_pair(partnerRealm->getID(), 0), answerWriter::commit_trade(partnerFortressId, selfFortressId, TR_FIRST_FORTRESS_TRANSPORT_CONTAINERS_LACK));
		}

		break;
	case TR_FIRST_FORTRESS_ENERGETIC_CELLS_LACK:
		selfRealm->tradeState.cancelCommit();
		gctx.sendToClient(cl, answerWriter::commit_trade(selfFortressId, partnerFortressId, TR_FIRST_FORTRESS_ENERGETIC_CELLS_LACK));

		if (isPartnerTrader) 
		{
			partnerRealm->tradeState.cancelCommit();
			gctx.sendToClient(make_pair(partnerRealm->getID(), 0), answerWriter::commit_trade(partnerFortressId, selfFortressId, TR_SECOND_FORTRESS_ENERGETIC_CELLS_LACK));
		}

		break;
	case TR_SECOND_FORTRESS_ENERGETIC_CELLS_LACK:
		selfRealm->tradeState.cancelCommit();
		gctx.sendToClient(cl, answerWriter::commit_trade(selfFortressId, partnerFortressId, TR_SECOND_FORTRESS_ENERGETIC_CELLS_LACK));

		if (isPartnerTrader) 
		{
			partnerRealm->tradeState.cancelCommit();
			gctx.sendToClient(make_pair(partnerRealm->getID(), 0), answerWriter::commit_trade(partnerFortressId, selfFortressId, TR_FIRST_FORTRESS_ENERGETIC_CELLS_LACK));
		}

		break;
	case TR_NOT_IN_RANGE:
		selfRealm->tradeState.cancelTrade();
		gctx.sendToClient(cl, answerWriter::commit_trade(selfFortressId, partnerFortressId, TR_NOT_IN_RANGE));

		if (isPartnerTrader) 
		{
			partnerRealm->tradeState.cancelTrade();
			gctx.sendToClient(make_pair(partnerRealm->getID(), 0), answerWriter::commit_trade(partnerFortressId, selfFortressId, TR_NOT_IN_RANGE));
		}

		break;
	case TR_UNKNOWN_FAIL:
		selfRealm->tradeState.cancelTrade();				
		gctx.sendToClient(cl, answerWriter :: receive_cancel_trade(selfFortressId, partnerFortressId));

		if (isPartnerTrader) 
		{
			partnerRealm->tradeState.cancelTrade();
			gctx.sendToClient(make_pair(partnerRealm->getID(), 0), answerWriter :: receive_cancel_trade(selfFortressId, partnerFortressId));
		}

		break;
	}
}

id request_commit_trade(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters) 
{
	realmClass* selfRealm = actx->cacheRealmsList.getItem<realmClass>(cl.first);	

    if (selfRealm == NULL)
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) cl.first);
        return make_pair(0, 0);
	}

	realmClass * partnerRealm = actx->cacheRealmsList.getItem<realmClass>(selfRealm->tradeState.getEnemyID());

	dtIdentifier selfFortressId = strtoul(parameters[REQUEST_COMMIT_TRADE_SELF_FORTRESS_ID].c_str(), NULL, 0);
	fortressClass* selfFortress = actx->cacheFortressesList.getItem<fortressClass>(selfFortressId);

	dtIdentifier partnerFortressId = strtoul(parameters[REQUEST_COMMIT_TRADE_PARTNER_FORTRESS_ID].c_str(), NULL, 0);
	fortressClass* partnerFortress = actx->cacheFortressesList.getItem<fortressClass>(partnerFortressId);

	if (selfFortress == NULL) {
		gctx.sendToClient(cl, answerWriter :: commit_trade_FAIL(selfFortressId, partnerFortressId, REQUEST_COMMIT_TRADE_ANSWER_FAIL_SOURCE_FORTRESS_NOT_EXISTS));
		return cl;
	}

	if (selfRealm->tradeState.isCommiterHost()) {
		gctx.sendToClient(cl, answerWriter :: commit_trade_FAIL(selfFortressId, partnerFortressId, REQUEST_COMMIT_TRADE_ANSWER_FAIL_YOU_ARE_COMMITER_HOST_ALREADY));
		return cl;
	}	

	if (!(selfRealm->tradeState.isAnyTrader() || selfRealm->tradeState.isCommiterInvited())) {
		// Aby mohl hrac zadat o commit, tak musi byt bude obchodnik, nebo byt ke commitu pozvany protihracem
		gctx.sendToClient(cl, answerWriter :: commit_trade_FAIL(selfFortressId, partnerFortressId, REQUEST_COMMIT_TRADE_ANSWER_FAIL_YOU_ARE_NOT_TRADER));
		return cl;
	}

	if (selfRealm->tradeState.getOwnedFortressID() != selfFortress->getID()) {
		gctx.sendToClient(cl, answerWriter :: commit_trade_FAIL(selfFortressId, partnerFortressId, REQUEST_COMMIT_TRADE_ANSWER_FAIL_SOURCE_FORTRESS_NOT_PARTNER));
		return cl;
	}

	if (selfRealm->tradeState.isSpaceTrader()) {
		// V dusledku toho, ze prohlasime self hrace za commitujiciho, mu znovu vytvorime bundle. 
		// Nepouzivame puvodni bundle, co se prubezne vytvarel na serveru, protoze neni potreba s nicim porovnavat, hlavni je,
		// aby se uzavrel obchod tak, jak ho vidi klient.
		selfRealm->tradeState.becomeCommiterAcknowledged();

		read_trade_data(parameters, REQUEST_COMMIT_TRADE_SELF_DATA_PREFIX, selfRealm->tradeState.getTradeBundle());
		tradingResult tradeResult = selfFortress->throwSomeStuffIntoTheSpace(selfRealm->tradeState.getTradeBundle());
		inspect_trade_result(cl, selfRealm, NULL, tradeResult);		
	}
	else {
		if (partnerFortress == NULL) {
			gctx.sendToClient(cl, answerWriter :: commit_trade_FAIL(selfFortressId, partnerFortressId, REQUEST_COMMIT_TRADE_ANSWER_FAIL_TARGET_FORTRESS_NOT_EXISTS));
			return cl;
		}	

		if (partnerRealm == NULL) 
		{
			gctx.sendToClient(cl, answerWriter :: commit_trade_FAIL(selfFortressId, partnerFortressId, REQUEST_COMMIT_TRADE_ANSWER_FAIL_TARGET_REALM_NOT_EXISTS));
			return cl;
		}

		if (selfRealm->tradeState.getEnemyFortressID() != partnerFortress->getID()) {
			gctx.sendToClient(cl, answerWriter :: commit_trade_FAIL(selfFortressId, partnerFortressId, REQUEST_COMMIT_TRADE_ANSWER_FAIL_TARGET_FORTRESS_NOT_PARTNER));
			return cl;
		}

		if (selfRealm->tradeState.getEnemyID() != partnerFortress->getFortressRealmID()) {
			gctx.sendToClient(cl, answerWriter :: commit_trade_FAIL(selfFortressId, partnerFortressId, REQUEST_COMMIT_TRADE_ANSWER_FAIL_TARGET_REALM_NOT_PARTNER));
			return cl;
		}

		if (selfRealm->tradeState.isPartnerTrader()) 		
		{
			if (partnerRealm->tradeState.isCommiterHost()) {
				selfRealm->tradeState.becomeCommiterAcknowledged();

				read_trade_data(parameters, REQUEST_COMMIT_TRADE_SELF_DATA_PREFIX, selfRealm->tradeState.getTradeBundle());			
				read_trade_data(parameters, REQUEST_COMMIT_TRADE_PARTNER_DATA_PREFIX, selfRealm->tradeState.getPartnerTradeBundle());

				tradeBundleClass * selfSelfOffer = selfRealm->tradeState.getTradeBundle();
				tradeBundleClass * selfPartnerOffer = selfRealm->tradeState.getPartnerTradeBundle();

				// Partnersky hrac uz ma predmety v bundle, protoze je commiter host
				tradeBundleClass * partnerSelfOffer = partnerRealm->tradeState.getTradeBundle();
				tradeBundleClass * partnerPartnerOffer = partnerRealm->tradeState.getPartnerTradeBundle();
			
				if (!(*selfSelfOffer == *partnerPartnerOffer && *selfPartnerOffer == *partnerSelfOffer)) 
				{
					// Pokud pohledy nesedi, zrusit commit a poslat obema hracum zruseni
					selfRealm->tradeState.cancelTrade();
					partnerRealm->tradeState.cancelTrade();

					gctx.sendToClient(cl, answerWriter :: receive_cancel_trade(selfFortress->getID(), partnerFortress->getID()));
					gctx.sendToClient(make_pair(partnerRealm->getID(), 0), answerWriter :: receive_cancel_trade(partnerFortress->getID(), selfFortress->getID()));
					return cl;
				}

				tradingResult tradeResult = fortressClass::commitTrade(selfFortress, selfRealm->tradeState.getTradeBundle(), partnerFortress, selfRealm->tradeState.getPartnerTradeBundle());		
				inspect_trade_result(cl, selfRealm, partnerRealm, tradeResult);	
			}
			else 
			{
				// Pokud partnersky hrac jeste nezadal o commit, tak je self hrac hostujici commiter a partnersky hrac pozvany commiter

				// Zmenime hracum stav, takze uz nebude mozne pridavat nove polozky
				selfRealm->tradeState.becomeCommiterHost();		
				partnerRealm->tradeState.becomeCommiterInvited();

				tradeBundleClass * selfTradeBundle = selfRealm->tradeState.getTradeBundle();
				read_trade_data(parameters, REQUEST_COMMIT_TRADE_SELF_DATA_PREFIX, selfTradeBundle);

				tradeBundleClass * selfPartnerTradeBundle = selfRealm->tradeState.getPartnerTradeBundle();
				read_trade_data(parameters, REQUEST_COMMIT_TRADE_PARTNER_DATA_PREFIX, selfPartnerTradeBundle);

				gctx.sendToClient(cl, answerWriter :: prepare_commit_trade(selfFortressId, partnerFortressId, TRADE_COMMIT_ROLE_HOST));
				gctx.sendToClient(make_pair(partnerRealm->getID(), 0), answerWriter :: prepare_commit_trade(partnerFortressId, selfFortressId, TRADE_COMMIT_ROLE_INVITED));
			}
		}
		else {
			// Self hrac obchoduje sam se sebou nebo nekontrolovatelnou lodi. Nemusime pouzivat docasny server bundle, 
			// protoze hlavni je klientuv pohled na nabidku.

			selfRealm->tradeState.becomeCommiterAcknowledged();

			read_trade_data(parameters, REQUEST_COMMIT_TRADE_SELF_DATA_PREFIX, selfRealm->tradeState.getTradeBundle());
			read_trade_data(parameters, REQUEST_COMMIT_TRADE_PARTNER_DATA_PREFIX, selfRealm->tradeState.getPartnerTradeBundle());

			tradingResult tradeResult = fortressClass::commitTrade(selfFortress, selfRealm->tradeState.getTradeBundle(), partnerFortress, selfRealm->tradeState.getPartnerTradeBundle());		
			inspect_trade_result(cl, selfRealm, partnerRealm, tradeResult);
		}

	}

	return cl;
}

id request_cancel_trade_commit(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	realmClass* selfRealm = actx->cacheRealmsList.getItem<realmClass>(cl.first);	

    if (selfRealm == NULL)
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) cl.first);
        return make_pair(0, 0);
	}

	realmClass * partnerRealm = actx->cacheRealmsList.getItem<realmClass>(selfRealm->tradeState.getEnemyID());

	dtIdentifier selfFortressId = strtoul(parameters[REQUEST_CANCEL_TRADE_COMMIT_SELF_FORTRESS_ID].c_str(), NULL, 0);
	fortressClass* selfFortress = actx->cacheFortressesList.getItem<fortressClass>(selfFortressId);

	dtIdentifier partnerFortressId = strtoul(parameters[REQUEST_CANCEL_TRADE_COMMIT_PARTNER_FORTRESS_ID].c_str(), NULL, 0);
	fortressClass* partnerFortress = actx->cacheFortressesList.getItem<fortressClass>(partnerFortressId);

	if (selfFortress == NULL) {
		gctx.sendToClient(cl, answerWriter :: cancel_trade_commit_FAIL(selfFortressId, partnerFortressId, REQUEST_CANCEL_TRADE_COMMIT_ANSWER_FAIL_SOURCE_FORTRESS_NOT_EXISTS));
		return cl;
	}

	if (partnerFortress == NULL) {
		gctx.sendToClient(cl, answerWriter :: cancel_trade_commit_FAIL(selfFortressId, partnerFortressId, REQUEST_CANCEL_TRADE_COMMIT_ANSWER_FAIL_TARGET_FORTRESS_NOT_EXISTS));
		return cl;
	}	

	if (partnerRealm == NULL) 
	{
		gctx.sendToClient(cl, answerWriter :: cancel_trade_commit_FAIL(selfFortressId, partnerFortressId, REQUEST_CANCEL_TRADE_COMMIT_ANSWER_FAIL_TARGET_REALM_NOT_EXISTS));
		return cl;
	}

	if (selfRealm->tradeState.getOwnedFortressID() != selfFortress->getID()) {
		gctx.sendToClient(cl, answerWriter :: cancel_trade_commit_FAIL(selfFortressId, partnerFortressId, REQUEST_CANCEL_TRADE_COMMIT_ANSWER_FAIL_SOURCE_FORTRESS_NOT_PARTNER));
		return cl;
	}

	if (selfRealm->tradeState.getEnemyFortressID() != partnerFortress->getID()) {
		gctx.sendToClient(cl, answerWriter :: cancel_trade_commit_FAIL(selfFortressId, partnerFortressId, REQUEST_CANCEL_TRADE_COMMIT_ANSWER_FAIL_TARGET_FORTRESS_NOT_PARTNER));
		return cl;
	}

	if (selfRealm->tradeState.getEnemyID() != partnerFortress->getFortressRealmID()) {
		gctx.sendToClient(cl, answerWriter :: cancel_trade_commit_FAIL(selfFortressId, partnerFortressId, REQUEST_CANCEL_TRADE_COMMIT_ANSWER_FAIL_TARGET_REALM_NOT_PARTNER));
		return cl;
	}

	if (!(selfRealm->tradeState.isCommiterHost() || selfRealm->tradeState.isCommiterInvited())) {
		gctx.sendToClient(cl, answerWriter :: cancel_trade_commit_FAIL(selfFortressId, partnerFortressId, REQUEST_CANCEL_TRADE_COMMIT_ANSWER_FAIL_NO_COMMIT_TO_REJECT));
		return cl;
	}	

	selfRealm->tradeState.cancelCommit();
	partnerRealm->tradeState.cancelCommit();

	gctx.sendToClient(cl, answerWriter :: cancel_trade_commit(selfFortressId, partnerFortressId, REQUEST_CANCEL_TRADE_COMMIT_ANSWER_REASON_SELF_CANCELLED_COMMIT));
	gctx.sendToClient(make_pair(partnerRealm->getID(), 0), answerWriter :: cancel_trade_commit(partnerFortressId, selfFortressId, REQUEST_CANCEL_TRADE_COMMIT_ANSWER_REASON_PARTNER_CANCELLED_COMMIT));

	return cl;
}

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

id request_cancel_trade(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    realmClass* selfRealm = actx->cacheRealmsList.getItem<realmClass>(cl.first);	

	dtIdentifier selfFortressId = strtoul(parameters[REQUEST_CANCEL_TRADE_OWNED_FORTRESS_ID].c_str(), NULL, 0);
	dtIdentifier partnerFortressId = strtoul(parameters[REQUEST_CANCEL_TRADE_PARTNER_FORTRESS_ID].c_str(), NULL, 0);

    if (selfRealm == NULL)
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) cl.first);
        return make_pair(0, 0);
	}

	if (selfRealm->tradeState.isParticipant()) 
	{
		if (selfRealm->tradeState.isPartnerTrader() || selfRealm->tradeState.isHost())
		{
			// V tomto pripade se self hrac ucastni obchodu, takze ho muze zrusit. Partner hrac ho jeste nezrusil, takze se mu zasle
			// zprava o zruseni. Mohlo by se stat, ze partner hrac chtel taky zrusit, ale jeste jeho zprava neprisla na server. To znamena,
			// ze az jeho zprava dorazi na server, tak obchod bude ve stavu zrusen, coz je v poradku, server mu pak jen potvrdi, ze obchod
			// je zrusen a bude to brat jako jeho potvrzeni, ze o tom vi, protoze ho sam chtel zrusit.

			dtIdentifier selfFortressId = selfRealm->tradeState.getOwnedFortressID();
			dtIdentifier partnerFortressId = selfRealm->tradeState.getEnemyFortressID();

			dtIdentifier partnerId = selfRealm->tradeState.getEnemyID();

			selfRealm->tradeState.cancelTrade();

			realmClass* partnerRealm = actx->cacheRealmsList.getItem<realmClass>(partnerId);

			if (partnerRealm != NULL) {
				partnerRealm->tradeState.becomeCanceled();
			}
			else {
				// Partner realm neexistuje, coz je velmi divne, ale nevadi to, proste mu nic nezrusime
			}

			gctx.sendToClient(cl, answerWriter :: cancel_trade(selfFortressId, partnerFortressId, 
				REQUEST_CANCEL_TRADE_ANSWER_REASON_YOU_ARE_PARTICIPANT, TRADE_ROLE_NONE));

			gctx.sendToClient(make_pair(partnerId, 0), answerWriter :: receive_cancel_trade(partnerFortressId, selfFortressId));
		}
		else 
		{
			dtIdentifier selfFortressId = selfRealm->tradeState.getOwnedFortressID();
			dtIdentifier partnerFortressId = selfRealm->tradeState.getEnemyFortressID();

			// V tomto pripade je self hrac bud lootTrader nebo selfTrader, coz lze oboji zrusit okamzite
			selfRealm->tradeState.cancelTrade();

			gctx.sendToClient(cl, answerWriter :: cancel_trade(selfFortressId, partnerFortressId, 
				REQUEST_CANCEL_TRADE_ANSWER_REASON_YOU_ARE_PARTICIPANT, TRADE_ROLE_NONE));
		}
	}
	else if (selfRealm->tradeState.isCanceled()) {
		// V tomto pripade se self hrac ucastni obchodu, ktery uz vsak partner hrac zrusil. Server poslal self hraci upozorneni,
		// ze obchod skoncil, ale self hrac to jeste nepotvrdil, coz nevadi.

		dtIdentifier selfFortressId = selfRealm->tradeState.getOwnedFortressID();
		dtIdentifier partnerFortressId = selfRealm->tradeState.getEnemyFortressID();

		selfRealm->tradeState.cancelTrade();

		gctx.sendToClient(cl, answerWriter :: cancel_trade(selfFortressId, partnerFortressId, 
			REQUEST_CANCEL_TRADE_ANSWER_REASON_PARTNER_CANCELED_TRADE, TRADE_ROLE_NONE));
	}
	else {
		// V tomto pripade se self hrac neucastni obchodu, ani se ho neucastnil tak, ze by byl mezitim zrusen, takze nema co rusit

		// To je nekorektni chovani klienta

		gctx.sendToClient(cl, answerWriter :: cancel_trade_FAIL(
			selfFortressId, partnerFortressId, REQUEST_CANCEL_TRADE_ANSWER_FAIL_YOU_ARE_NOT_PARTICIPANT));
	}

	return cl;
}

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

id request_update_fortresses_in_weapons_range(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    realmClass* selfRealm = actx->cacheRealmsList.getItem<realmClass>(cl.first);	

    if (selfRealm == NULL)
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) cl.first);
        return make_pair(0, 0);
	}

	dtIdentifier fortressId = strtoul(parameters[REQUEST_FORTRESSES_IN_WEAPONS_RANGE_FORTRESS_ID].c_str(), NULL, 0);
	fortressClass* fortress = actx->cacheFortressesList.getItem<fortressClass>(fortressId);	

    if (fortress == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: fortresses_in_weapons_range_FAIL(fortressId, REQUEST_FORTRESSES_IN_WEAPONS_RANGE_ANSWER_FAIL_FORTRESSNE));
		return cl;
	}

	dtIdentifierList shipsInRangeIds;
	dtIdentifierList basesInRangeIds;
	fortress->getFortressesInRangeForAttack(&basesInRangeIds, &shipsInRangeIds);

	fortresses_in_range_data data;

	data.fortressId = fortressId;

	std::list<shipClass*> ships;

	for (dtIdentifierList::const_iterator it = shipsInRangeIds.begin(); it != shipsInRangeIds.end(); ++it)
	{
		shipClass * _fortress = actx->cacheFortressesList.getItem<shipClass>(*it);

		if (_fortress != NULL) {	
			ships.push_back(_fortress);
		}
	}

	std::list<baseClass*> bases;

	for (dtIdentifierList::const_iterator it = basesInRangeIds.begin(); it != basesInRangeIds.end(); ++it)
	{
		baseClass * _fortress = actx->cacheFortressesList.getItem<baseClass>(*it);

		if (_fortress != NULL) {	
			bases.push_back(_fortress);
		}
	}

	gctx.sendToClient(cl, answerWriter :: fortresses_in_weapons_range(fortress, ships, bases));

	return cl;
}

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

id request_attack_fortress(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    realmClass* selfRealm = actx->cacheRealmsList.getItem<realmClass>(cl.first);	

    if (selfRealm == NULL)
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) cl.first);
        return make_pair(0, 0);
	}

	dtIdentifier selfFortressId = strtoul(parameters[REQUEST_ATTACK_FORTRESS_SELF_FORTRESS_ID].c_str(), NULL, 0);
	dtIdentifier enemyFortressId = strtoul(parameters[REQUEST_ATTACK_FORTRESS_ENEMY_FORTRESS_ID].c_str(), NULL, 0);

	fortressClass* selfFortress = actx->cacheFortressesList.getItem<fortressClass>(selfFortressId);	

    if (selfFortress == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: attack_fortress_FAIL(selfFortressId, enemyFortressId, REQUEST_ATTACK_FORTRESS_ANSWER_FAIL_SELF_FORTRESSNE));
		return cl;
	}
	
    /* pokud pevnost hraci nepatri, vrat chybu */
    if (selfFortress->getFortressRealmID() != cl.first)
    {
		gctx.sendToClient(cl, answerWriter :: attack_fortress_FAIL(selfFortressId, enemyFortressId, REQUEST_ATTACK_FORTRESS_ANSWER_FAIL_SELF_FORTRESSNE));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!selfFortress->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: attack_fortress_FAIL(selfFortressId, enemyFortressId, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

	fortressClass* enemyFortress = actx->cacheFortressesList.getItem<fortressClass>(enemyFortressId);	

    if (enemyFortress == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: attack_fortress_FAIL(selfFortressId, enemyFortressId, REQUEST_ATTACK_FORTRESS_ANSWER_FAIL_ENEMY_FORTRESSNE));
		return cl;
	}

	selfFortress->aimNewTarget(enemyFortress, 0);

	gctx.sendToClient(cl, answerWriter :: attack_fortress(selfFortressId, enemyFortressId));

	return cl;
}

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

id request_stop_attack_fortress(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    realmClass* selfRealm = actx->cacheRealmsList.getItem<realmClass>(cl.first);	

    if (selfRealm == NULL)
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) cl.first);
        return make_pair(0, 0);
	}

	dtIdentifier selfFortressId = strtoul(parameters[REQUEST_STOP_ATTACK_FORTRESS_SELF_FORTRESS_ID].c_str(), NULL, 0);
	fortressClass* selfFortress = actx->cacheFortressesList.getItem<fortressClass>(selfFortressId);	

    if (selfFortress == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: stop_attack_fortress_FAIL(selfFortressId, REQUEST_STOP_ATTACK_FORTRESS_ANSWER_FAIL_SELF_FORTRESSNE));
		return cl;
	}

    /* pokud pevnost hraci nepatri, vrat chybu */
    if (selfFortress->getFortressRealmID() != cl.first)
    {
		gctx.sendToClient(cl, answerWriter :: stop_attack_fortress_FAIL(selfFortressId, REQUEST_STOP_ATTACK_FORTRESS_ANSWER_FAIL_SELF_FORTRESSNO));
        return cl;
    }

    /* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!selfFortress->isControllable())
    {
		gctx.sendToClient(cl, answerWriter :: stop_attack_fortress_FAIL(selfFortressId, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
        return cl;
    }

	selfFortress->unlockWeapons();

	gctx.sendToClient(cl, answerWriter :: stop_attack_fortress(selfFortressId));

	return cl;
}

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

id request_update_fortresses_in_conquer_range(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    realmClass* selfRealm = actx->cacheRealmsList.getItem<realmClass>(cl.first);	

    if (selfRealm == NULL)
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) cl.first);
        return make_pair(0, 0);
	}

	dtIdentifier selfFortressId = strtoul(parameters[REQUEST_FORTRESSES_IN_CONQUER_RANGE_SELF_FORTRESS_ID].c_str(), NULL, 0);
	fortressClass* selfFortress = actx->cacheFortressesList.getItem<fortressClass>(selfFortressId);	

    if (selfFortress == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: fortresses_in_conquer_range_FAIL(selfFortressId, REQUEST_FORTRESSES_IN_CONQUER_RANGE_ANSWER_FORTRESSNE));
		return cl;
	}

	dtIdentifierList shipsForConquerIds;
	dtIdentifierList basesForConquerIds;
	selfFortress->getFortressesInRangeForConquer(&basesForConquerIds, &shipsForConquerIds);

	std::list<fortressClass*> shipsForConquer;
	std::list<fortressClass*> basesForConquer;

	for (dtIdentifierList::const_iterator it = shipsForConquerIds.begin(); it != shipsForConquerIds.end(); ++it)
	{
		shipClass * fortress = actx->cacheFortressesList.getItem<shipClass>(*it);

		if (fortress == NULL)
		{
			continue;			
		}

		if (fortress->isControllable()) {
			continue;
		}

		shipsForConquer.push_back(fortress);
	}
	 
	for (dtIdentifierList::const_iterator it = basesForConquerIds.begin(); it != basesForConquerIds.end(); ++it)
	{
		baseClass * fortress = actx->cacheFortressesList.getItem<baseClass>(*it);

		if (fortress == NULL) 
		{
			continue;			
		}

		if (fortress->isControllable()) {
			continue;
		}

		basesForConquer.push_back(fortress);
	}

	gctx.sendToClient(cl, answerWriter :: fortresses_in_conquer_range(selfFortress, shipsForConquer, basesForConquer));

	return cl;
}

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

id request_update_available_fortress_classes(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    realmClass* selfRealm = actx->cacheRealmsList.getItem<realmClass>(cl.first);	

    if (selfRealm == NULL)
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) cl.first);
        return make_pair(0, 0);
	}

	dtIdentifier selfFortressId = strtoul(parameters[REQUEST_AVAILABLE_FORTRESS_CLASSES_SELF_FORTRESS_ID].c_str(), NULL, 0);
	fortressClass* selfFortress = actx->cacheFortressesList.getItem<fortressClass>(selfFortressId);	

    if (selfFortress == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: available_fortress_classes_FAIL(selfFortressId, REQUEST_AVAILABLE_FORTRESS_CLASSES_ANSWER_FORTRESSNE));
		return cl;
	}

	dtIdentifierList availableShipClassesIds;
	dtIdentifierList availableBaseClassesIds;

	selfFortress->getAvailableFortressClasses(&availableBaseClassesIds, &availableShipClassesIds);

	std::list<fortressClassClass*> availableShipClasses;
	std::list<fortressClassClass*> availableBaseClasses;

	for (dtIdentifierList::const_iterator it = availableShipClassesIds.begin(); it != availableShipClassesIds.end(); ++it)
	{
		fortressClassClass * fortressClazz = actx->cacheFortressClassesList.getItem<fortressClassClass>(*it);

		if (fortressClazz == NULL)
		{
			continue;			
		}

		availableShipClasses.push_back(fortressClazz);
	}

	for (dtIdentifierList::const_iterator it = availableBaseClassesIds.begin(); it != availableBaseClassesIds.end(); ++it)
	{
		fortressClassClass * fortressClazz = actx->cacheFortressClassesList.getItem<fortressClassClass>(*it);

		if (fortressClazz == NULL)
		{
			continue;			
		}

		availableBaseClasses.push_back(fortressClazz);
	}

	gctx.sendToClient(cl, answerWriter :: available_fortress_classes(selfFortress, availableShipClasses, availableBaseClasses));

	return cl;
}

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

id request_update_fortress_class_data(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    realmClass* selfRealm = actx->cacheRealmsList.getItem<realmClass>(cl.first);	

    if (selfRealm == NULL)
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) cl.first);
        return make_pair(0, 0);
	}

	dtIdentifier fortressClassId = strtoul(parameters[REQUEST_FORTRESS_CLASS_DATA_FORTRESS_CLASS_ID].c_str(), NULL, 0);
	fortressClassClass* fortressClazz = actx->cacheFortressClassesList.getItem<fortressClassClass>(fortressClassId);	

    if (fortressClazz == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: fortress_class_data_FAIL(fortressClassId, REQUEST_FORTRESS_CLASS_DATA_FORTRESS_CLASS_ANSWER_FORTRESSNE));
		return cl;
	}

	gctx.sendToClient(cl, answerWriter :: fortress_class_data(fortressClazz));

	return cl;
}

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

id request_build_new_base_shell(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    realmClass* selfRealm = actx->cacheRealmsList.getItem<realmClass>(cl.first);	

    if (selfRealm == NULL)
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) cl.first);
        return make_pair(0, 0);
	}

	dtIdentifier selfFortressId = strtoul(parameters[REQUEST_BUILD_NEW_BASE_SHELL_SELF_FORTRESS_ID].c_str(), NULL, 0);
	fortressClass* selfFortress = actx->cacheFortressesList.getItem<fortressClass>(selfFortressId);	

    if (selfFortress == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: build_new_base_shell_FAIL(selfFortressId, REQUEST_BUILD_NEW_BASE_SHELL_ANSWER_FORTRESSNE));
		return cl;
	}

    /* pokud pevnost hraci nepatri, vrat chybu */
    if (selfFortress->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: build_new_base_shell_FAIL(selfFortressId, REQUEST_BUILD_NEW_BASE_SHELL_ANSWER_FORTRESSNO));
        return cl;
    }

	/* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!selfFortress->isControllable()) 
	{
		gctx.sendToClient(cl, answerWriter :: build_new_base_shell_FAIL(selfFortressId, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
	}

	dtIdentifier fortressClassId = strtoul(parameters[REQUEST_BUILD_NEW_BASE_SHELL_FORTRESS_CLASS_ID].c_str(), NULL, 0);
	unsigned long long buildingTitanium = _strtoui64(parameters[REQUEST_BUILD_NEW_BASE_SHELL_TITANIUM].c_str(), NULL, 10);

	baseBuildingResult result = selfFortress->buildNewBaseShell(fortressClassId, buildingTitanium);

	selfFortress->startReadingForClient();
	gctx.sendToClient(cl, answerWriter :: build_new_base_shell(selfFortressId, result, selfFortress->actualTit()));

	return cl;
}

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

id request_update_player_fortresses_build_information(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    /* vyplnime seznam prijemcu - zatim to budou vsichni hraci */
    std :: list<shipClass*> ships;
	std :: list<baseClass*> bases;
    realmClass* realm = actx->cacheRealmsList.getItem<realmClass>(cl.first);
    if (realm != NULL)
    {
		if (!get_realm_ships(realm, ships))
		{
			return make_pair(0, 0);
		}
        

        if (!get_realm_bases(realm, bases))
		{
			return make_pair(0, 0);
		}

        /* posleme seznam moznych prijemcu */
        gctx.sendToClient(cl, answerWriter :: player_fortresses_build_information(ships, bases));
    }
    else
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) cl.first);
        return make_pair(0, 0);
    }

    return cl;
}

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

id request_update_player_fortresses_attack_information(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    /* vyplnime seznam prijemcu - zatim to budou vsichni hraci */
    std :: list<shipClass*> ships;
	std :: list<baseClass*> bases;
    realmClass* realm = actx->cacheRealmsList.getItem<realmClass>(cl.first);
    if (realm != NULL)
    {
		if (!get_realm_ships(realm, ships))
		{
			return make_pair(0, 0);
		}

		if (!get_realm_bases(realm, bases))
		{
			return make_pair(0, 0);
		}

        /* posleme seznam moznych prijemcu */
        gctx.sendToClient(cl, answerWriter :: player_fortresses_attack_information(ships, bases));
    }
    else
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) cl.first);
        return make_pair(0, 0);
    }

    return cl;
}

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

id request_update_player_fortresses(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	startReadOnlyRequest();

    /* vyplnime seznam prijemcu - zatim to budou vsichni hraci */
    std :: list<shipClass*> ships;
	std :: list<baseClass*> bases;
    realmClass* realm = actx->cacheRealmsList.getItem<realmClass>(cl.first);
    if (realm != NULL)
    {
        const dtIdentifierVector& vships = realm->getShipList();
        for (dtIdentifierVector :: const_iterator iter = vships.begin(); iter != vships.end(); iter++)
        {
            fortressClass* f = actx->cacheFortressesList.getItem<fortressClass>(*iter);
            if (f!= NULL)
            {
				if (!f->isControllable()) 
				{
					continue;
				}

                if (f->getFortressType() == FT_SHIP) 
                {
                    ships.push_back(dynamic_cast<shipClass*>(f));
                }
                else
                {
                    errExceptionError("Base [%u] in ships list!", (unsigned long long) f->getID());
                    return make_pair(0, 0);
                }
            }
            else
            {
                errExceptionError("Ship with id %u not found!", (unsigned long long) *iter);
                return make_pair(0, 0);
            }
        }

		const dtIdentifierVector& vbases = realm->getBaseList();
        for (dtIdentifierVector :: const_iterator iter = vbases.begin(); iter != vbases.end(); iter++)
        {
            fortressClass* f = actx->cacheFortressesList.getItem<fortressClass>(*iter);
            if (f!= NULL)
            {
				if (!f->isControllable()) 
				{
					continue;
				}

                if (f->getFortressType() == FT_BASE) 
                {
                    bases.push_back(dynamic_cast<baseClass*>(f));
                }
                else
                {
                    errExceptionError("Ship [%u] in bases list!", (unsigned long long) f->getID());
                    return make_pair(0, 0);
                }
            }
            else
            {
                errExceptionError("Base with id %u not found!", (unsigned long long) *iter);
                return make_pair(0, 0);
            }
        }

        /* posleme seznam moznych prijemcu */
        gctx.sendToClient(cl, answerWriter :: player_fortresses(ships, bases));
    }
    else
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) cl.first);
        return make_pair(0, 0);
    }

    return cl;
}

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

id request_conquer_fortress(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    realmClass* selfRealm = actx->cacheRealmsList.getItem<realmClass>(cl.first);	

    if (selfRealm == NULL)
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) cl.first);
        return make_pair(0, 0);
	}

	dtIdentifier selfFortressId = strtoul(parameters[REQUEST_CONQUER_FORTRESS_SELF_FORTRESS_ID].c_str(), NULL, 0);
	fortressClass* selfFortress = actx->cacheFortressesList.getItem<fortressClass>(selfFortressId);	

    if (selfFortress == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: conquer_fortress_FAIL(selfFortressId, REQUEST_CONQUER_FORTRESS_ANSWER_FORTRESSNE));
        return cl;
	}

    /* pokud pevnost hraci nepatri, vrat chybu */
    if (selfFortress->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: conquer_fortress_FAIL(selfFortressId, REQUEST_CONQUER_FORTRESS_ANSWER_FORTRESSNO));
        return cl;
    }

	/* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!selfFortress->isControllable()) 
	{
		gctx.sendToClient(cl, answerWriter :: conquer_fortress_FAIL(selfFortressId, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
	}

	dtIdentifier targetFortressId = strtoul(parameters[REQUEST_CONQUER_FORTRESS_ENEMY_FORTRESS_ID].c_str(), NULL, 0);
	fortressClass* targetFortress = actx->cacheFortressesList.getItem<fortressClass>(targetFortressId);	

	if (targetFortress == NULL) 
	{
        gctx.sendToClient(cl, answerWriter :: conquer_fortress_FAIL(selfFortressId, REQUEST_CONQUER_FORTRESS_ANSWER_TARGET_FORTRESSNE));
        return cl;
	}

	conquerResultClass conquerResult;
	fortressAddingResult addingResult = selfFortress->conquerTarget(targetFortress, &conquerResult);

	gctx.sendToClient(cl, answerWriter :: conquer_fortress(selfFortressId, targetFortressId, addingResult, conquerResult));

	return cl;
}

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

id request_update_fortress_sensors_information(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    realmClass* selfRealm = actx->cacheRealmsList.getItem<realmClass>(cl.first);	

    if (selfRealm == NULL)
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) cl.first);
        return make_pair(0, 0);
	}

	dtIdentifier selfFortressId = strtoul(parameters[REQUEST_FORTRESS_SENSORS_INFORMATION_SELF_FORTRESS_ID].c_str(), NULL, 0);
	fortressClass* selfFortress = actx->cacheFortressesList.getItem<fortressClass>(selfFortressId);	

    if (selfFortress == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: fortress_sensors_information_FAIL(selfFortressId, REQUEST_FORTRESS_SENSORS_INFORMATION_ANSWER_FORTRESSNE));
        return cl;
	}

    /* pokud pevnost hraci nepatri, vrat chybu */
    if (selfFortress->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: fortress_sensors_information_FAIL(selfFortressId, REQUEST_FORTRESS_SENSORS_INFORMATION_ANSWER_FORTRESSNO));
        return cl;
    }

	/* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!selfFortress->isControllable()) 
	{
		gctx.sendToClient(cl, answerWriter :: fortress_sensors_information_FAIL(selfFortressId, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
	}


	sensors_data hrData;

	hrData.range = selfFortress->sensors.highResolutionSensors()->actualRange();
	hrData.level = selfFortress->sensors.highResolutionSensors()->actualLevel();	
	hrData.weight = selfFortress->sensors.highResolutionSensors()->getWeight();
	hrData.status = selfFortress->sensors.highResolutionSensors()->getStatus();
	hrData.available = selfFortress->sensors.highResolutionSensors()->getCount() > 0;
	hrData.consumption = selfFortress->sensors.getActualEnergyConsumptionHR();
	
	sensors_data lrData;

	lrData.range = selfFortress->sensors.longRangeSensors()->actualRange();
	lrData.level = selfFortress->sensors.longRangeSensors()->actualLevel();	
	lrData.weight = selfFortress->sensors.longRangeSensors()->getWeight();
	lrData.status = selfFortress->sensors.longRangeSensors()->getStatus();
	lrData.available = selfFortress->sensors.longRangeSensors()->getCount() > 0;
	lrData.consumption = selfFortress->sensors.getActualEnergyConsumptionLR();

	gctx.sendToClient(cl, answerWriter :: fortress_sensors_information(selfFortressId, hrData, lrData));

	return cl;
}

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

id request_update_fortress_cloaking_information(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    realmClass* selfRealm = actx->cacheRealmsList.getItem<realmClass>(cl.first);	

    if (selfRealm == NULL)
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) cl.first);
        return make_pair(0, 0);
	}

	dtIdentifier selfFortressId = strtoul(parameters[REQUEST_FORTRESS_CLOAKING_INFORMATION_SELF_FORTRESS_ID].c_str(), NULL, 0);
	fortressClass* selfFortress = actx->cacheFortressesList.getItem<fortressClass>(selfFortressId);	

    if (selfFortress == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: fortress_cloaking_information_FAIL(selfFortressId, REQUEST_FORTRESS_CLOAKING_INFORMATION_ANSWER_FORTRESSNE));
        return cl;
	}

    /* pokud pevnost hraci nepatri, vrat chybu */
    if (selfFortress->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: fortress_cloaking_information_FAIL(selfFortressId, REQUEST_FORTRESS_CLOAKING_INFORMATION_ANSWER_FORTRESSNO));
        return cl;
    }

	/* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!selfFortress->isControllable()) 
	{
		gctx.sendToClient(cl, answerWriter :: fortress_cloaking_information_FAIL(selfFortressId, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
	}


	cloaking_data data;

	data.level = selfFortress->cloaking.cloakingDevice()->actualLevel();
	data.consumption = selfFortress->cloaking.getActualEnergyConsumption();	
	data.status = selfFortress->cloaking.cloakingDevice()->getStatus();
	data.available = selfFortress->cloaking.cloakingDevice()->getCount() > 0;
	data.weight = selfFortress->cloaking.getCloakingWeight();
	
	gctx.sendToClient(cl, answerWriter :: fortress_cloaking_information(selfFortressId, data));

	return cl;
}

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

id request_game_seconds_per_actual_second(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
	gctx.sendToClient(cl, answerWriter :: game_seconds_per_actual_second(GAME_TIME_TO_WALL_TIME_SPEED_RATIO));
	return cl;
}

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

id request_rename_fortress(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    realmClass* selfRealm = actx->cacheRealmsList.getItem<realmClass>(cl.first);	

    if (selfRealm == NULL)
    {
        errExceptionError("Player realm with id %u not found!", (unsigned long long) cl.first);
        return make_pair(0, 0);
	}

	dtIdentifier fortressId = strtoul(parameters[REQUEST_RENAME_FORTRESS_FORTRESS_ID].c_str(), NULL, 0);
	std::string newName = parameters[REQUEST_RENAME_FORTRESS_NEW_NAME];

	fortressClass * fortress = actx->cacheFortressesList.getItem<fortressClass>(fortressId);

	if (fortress == NULL) {
		gctx.sendToClient(cl, answerWriter :: rename_fortress_FAIL(fortressId, REQUEST_RENAME_FORTRESS_ANSWER_FAIL_FORTRESSNE));
		return cl;
	}

	if (fortress->getFortressRealmID() != cl.first) {
		gctx.sendToClient(cl, answerWriter :: rename_fortress_FAIL(fortressId, REQUEST_RENAME_FORTRESS_ANSWER_FAIL_FORTRESSNO));
		return cl;
	}

	if (newName == "") {
		gctx.sendToClient(cl, answerWriter :: rename_fortress_FAIL(fortressId, REQUEST_RENAME_FORTRESS_ANSWER_FAIL_EMPTY_NAME));
		return cl;
	}

	fortress->setFortressName(newName);

	gctx.sendToClient(cl, answerWriter :: rename_fortress(fortressId, newName));

	return cl;
}

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

id request_hangar_build_ship(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    realmClass* selfRealm = actx->cacheRealmsList.getItem<realmClass>(cl.first);	

    if (selfRealm == NULL)
    {
        errExceptionError("player realm with id %u not found!", (unsigned long long) cl.first);
        return make_pair(0, 0);
	}

	dtIdentifier selfFortressId = strtoul(parameters[REQUEST_HANGAR_BUILD_SHIP_SELF_FORTRESS_ID].c_str(), NULL, 0);
	fortressClass* selfFortress = actx->cacheFortressesList.getItem<fortressClass>(selfFortressId);	

	dtIdentifier hangarId = strtoul(parameters[REQUEST_HANGAR_BUILD_SHIP_HANGAR_ID].c_str(), NULL, 0);

    if (selfFortress == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: base_hangar_build_new_ship_FAIL(selfFortressId, hangarId, REQUEST_HANGAR_BUILD_SHIP_ANSWER_FORTRESSNE));
		return cl;
	}

	baseClass * base = dynamic_cast<baseClass*>(selfFortress);

    if (base == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: base_hangar_build_new_ship_FAIL(selfFortressId, hangarId, REQUEST_HANGAR_BUILD_SHIP_ANSWER_FORTRESS_NOT_BASE));
		return cl;
	}

    /* pokud pevnost hraci nepatri, vrat chybu */
    if (base->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: base_hangar_build_new_ship_FAIL(selfFortressId, hangarId, REQUEST_HANGAR_BUILD_SHIP_ANSWER_FORTRESSNO));
        return cl;
    }

	/* pokud pevnost neni kontrolovatelna, vrat chybu */
	if (!base->isControllable()) 
	{
		gctx.sendToClient(cl, answerWriter :: base_hangar_build_new_ship_FAIL(selfFortressId, hangarId, PROTOCOL_ERROR_MESSAGE_FORTRESS_NOT_CONTROLLABLE));
	}
	
	hangarClass * hangar = base->hangarsPort.hangarByIdentifier(hangarId);

	if (hangar == NULL) {
		gctx.sendToClient(cl, answerWriter :: base_hangar_build_new_ship_FAIL(selfFortressId, hangarId, REQUEST_HANGAR_BUILD_SHIP_HANGARNE));
		return cl;
	}

	dtIdentifier fortressclassid = strtoul(parameters[REQUEST_HANGAR_BUILD_SHIP_FORTRESS_CLASS_ID].c_str(), NULL, 0);
	unsigned long long buildingtitanium = _strtoui64(parameters[REQUEST_HANGAR_BUILD_SHIP_TITANIUM].c_str(), NULL, 10);

	itemsCreationResult result = hangar->createNewShip(base, fortressclassid, buildingtitanium);

	gctx.sendToClient(cl, answerWriter :: base_hangar_build_new_ship(selfFortressId, hangarId, result));

	return cl;
}

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

id request_ship_warp_info(id cl, const std :: string& requestName, std :: map<std :: string, std :: string>& parameters)
{
    startReadOnlyRequest();

    dtIdentifier shipid = strtoul(parameters[REQUEST_NAVIGATION_SHIPID].c_str(), NULL, 0);
    shipClass* ship = actx->cacheFortressesList.getItem<shipClass>(shipid);

    /* pokud lod neexistuje, vrat chybu */
    if (ship == NULL)
    {
        gctx.sendToClient(cl, answerWriter :: ship_warp_information_FAIL(shipid, REQUEST_SHIPWARPINFO_ANSWER_NOT_EXISTS));  
        return cl;
    }

    /* pokud lod hraci nepatri, vrat chybu */
    if (ship->getFortressRealmID() != cl.first)
    {
        gctx.sendToClient(cl, answerWriter :: ship_warp_information_FAIL(shipid, REQUEST_SHIPWARPINFO_ANSWER_NOT_OWNED));
        return cl;
    }

	/* pokud lod neni kontrolovatelna, vrat chybu */
	if (!ship->isControllable()) 
	{
		 gctx.sendToClient(cl, answerWriter :: ship_warp_information_FAIL(shipid, REQUEST_SHIPWARPINFO_ANSWER_NOT_CONTROLLABLE));
	}

    WarpInfo w;
    w.shipName              = ship->getFortressName();
    w.shipType              = ship->getFortressClassID();
    w.shipId                = ship->getID();
    w.stateChange           = false;

    if (ship->MovementIsInWarp())
    {
        // vyplnime klientska data

        vector_dist_t tposT     = ship->MovementGetWarpTarget();
        vector_dist_t cposEst   = ship->MovementEstimateWarpPosition();
        vector_dist_t sposT     = ship->MovementGetShipPosition(false);
        w.dstPosX               = tposT.x;
        w.dstPosY               = tposT.y;
        w.posX                  = cposEst.x;
        w.posY                  = cposEst.y;
        w.sposX                 = sposT.x;
        w.sposY                 = sposT.y;
        w.inWarp                = true;
        w.speed                 = ship->MovementGetWarpSpeed();
    }
    else
    {
        // vyplnime klientska data

        vector_dist_t tposT     = vector_dist_t(0, 0);
        vector_dist_t cposEst   = vector_dist_t(0, 0);
        vector_dist_t sposT     = vector_dist_t(0, 0);
        w.dstPosX               = tposT.x;
        w.dstPosY               = tposT.y;
        w.posX                  = cposEst.x;
        w.posY                  = cposEst.y;
        w.sposX                 = sposT.x;
        w.sposY                 = sposT.y;
        w.inWarp                = false;
        w.speed                 = 0;
    }

	gctx.sendToClient(cl, answerWriter :: ship_warp_information(w));

	return cl;
}

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

void init_request_table(void)
{
    request_processors[REQUEST_PING]                                    = request_ping;
    request_processors[REQUEST_LOGIN]                                   = request_login;
    request_processors[REQUEST_CHAT]                                    = request_chat;
    request_processors[REQUEST_BUDDY]                                   = request_buddy;
    request_processors[REQUEST_SHIPS]                                   = request_update_ships;
    request_processors[REQUEST_BASES]                                   = request_update_bases;
    request_processors[REQUEST_PLANETS]                                 = request_update_planets;
    request_processors[REQUEST_SHIPSINAREA]                             = request_update_shipsinarea;
    request_processors[REQUEST_NAVIGATION_STATUS]                       = request_update_navigation_status;
    request_processors[REQUEST_NAVIGATION_STOP]                         = request_navigation_stop;
    request_processors[REQUEST_NAVIGATION_WARP]                         = request_navigation_warp;
    request_processors[REQUEST_NAVIGATION_MOVE_TO]                      = request_navigation_move_to;
    request_processors[REQUEST_NAVIGATION_ORBIT]                        = request_navigation_orbit;
    request_processors[REQUEST_NAVIGATION_PURSUIT]                      = request_navigation_pursuit;
    request_processors[REQUEST_NAVIGATION_MOVE_TO_SPOBJ]                = request_navigation_move_to_spobj;
    request_processors[REQUEST_NAVIGATION_BREAK_WARP]                   = request_navigation_break_warp;
    request_processors[REQUEST_SHIP_JOURNEY_DETAILS]                    = request_update_ship_journey_details;
    request_processors[REQUEST_DEVICE_ENERGY_STATE]                     = request_update_device_energy_state;
    request_processors[REQUEST_CHANGE_DEVICE_ENERGY_STATE]              = request_change_device_energy_state;
    request_processors[REQUEST_SCIENCE]                                 = request_update_science;
    request_processors[REQUEST_SCIENCE_CHANGE]                          = request_science_change;
    request_processors[REQUEST_SHIP_CENTRAL_INFORMATION]                = request_update_ship_central_information;
    request_processors[REQUEST_FORTRESS_SHIELDS_INFORMATION]            = request_update_fortress_shields_information;
    request_processors[REQUEST_SHIP_SUBSPACE_DRIVE_INFORMATION]         = request_update_ship_subspace_drive_information;
    request_processors[REQUEST_SHIP_IMPULSE_DRIVE_INFORMATION]          = request_update_ship_impulse_drive_information;
    request_processors[REQUEST_FORTRESS_WEAPONS_INFORMATION]            = request_update_fortress_weapons_information;
    request_processors[REQUEST_FORTRESS_WEAPONS_SET]                    = request_update_fortress_weapons_set;
    request_processors[REQUEST_FORTRESS_MAINFRAME_INFORMATION]          = request_update_fortress_mainframe_information;
    request_processors[REQUEST_FORTRESS_CREW_INFORMATION]               = request_update_fortress_crew_information;
    request_processors[REQUEST_FORTRESS_QUARRY_INFORMATION]             = request_update_fortress_quarry_information;
    request_processors[REQUEST_FORTRESS_QUARRY_CHANGE_STATE]            = request_fortress_quarry_change_state;
	request_processors[REQUEST_FORTRESS_ACCOMMODATIONS_INFORMATION]     = request_update_fortress_accommodations_information;
	request_processors[REQUEST_FORTRESS_OTHER_EQUIPMENT_INFORMATION]    = request_update_fortress_other_equipment_information;
	request_processors[REQUEST_BASE_FACTORIES_INFORMATION]			    = request_update_base_factories_information;
	request_processors[REQUEST_FORTRESS_WAREHOUSES_INFORMATION]		    = request_update_fortress_warehouses_information;
	request_processors[REQUEST_SHIP_ANDROIDS_INFORMATION]			    = request_update_ship_androids_information;
	request_processors[REQUEST_BASE_ANDROIDS_INFORMATION]			    = request_update_base_androids_information;
    request_processors[REQUEST_SHIP_LOCATION_INFORMATION]               = request_update_ship_location_information;
	request_processors[REQUEST_CHANGE_SHIP_ANDROIDS_STATE]              = request_change_ship_androids_state;
	request_processors[REQUEST_CHANGE_BASE_ANDROIDS_STATE]              = request_change_base_androids_state;
	request_processors[REQUEST_BASE_HANGARS_INFORMATION]				= request_update_base_hangars_information;
	request_processors[REQUEST_BASE_HANGAR_ITEM_INFORMATION]			= request_update_base_hangars_item_information;
	request_processors[REQUEST_HANGAR_BUILD_ITEM]						= request_base_hangar_build_item;
	request_processors[REQUEST_HANGAR_CANCEL_ITEM]						= request_base_hangar_cancel_item;
    request_processors[REQUEST_NAVIGATION_PLANETS]                      = request_update_navigation_planets;
    request_processors[REQUEST_DISCOVERED_STARS]                        = request_update_discovered_stars;
	request_processors[REQUEST_UNMOUNT_FORTRESS_DEVICE]					= request_unmount_fortress_device;
	request_processors[REQUEST_MOUNT_FORTRESS_DEVICE]					= request_mount_fortress_device;
	request_processors[REQUEST_SEND_TRADE_INVITATION]					= request_send_trade_invitation;
	request_processors[REQUEST_CANCEL_TRADE]							= request_cancel_trade;
	request_processors[REQUEST_TRADE_PARTNER_FORTRESSES]				= request_update_trade_partner_fortresses;
	request_processors[REQUEST_DECIDE_TRADE_INVITATION]					= request_decide_trade_invitation;
	request_processors[REQUEST_MOVE_TRADE_ITEM]							= request_move_trade_item;
	request_processors[REQUEST_MOVE_TRADE_RESOURCE]						= request_move_trade_resource;
	request_processors[REQUEST_COMMIT_TRADE]							= request_commit_trade;
	request_processors[REQUEST_CANCEL_TRADE_COMMIT]						= request_cancel_trade_commit;
	request_processors[REQUEST_FORTRESSES_IN_WEAPONS_RANGE]				= request_update_fortresses_in_weapons_range;
	request_processors[REQUEST_ATTACK_FORTRESS]							= request_attack_fortress;
	request_processors[REQUEST_STOP_ATTACK_FORTRESS]					= request_stop_attack_fortress;
	request_processors[REQUEST_FORTRESSES_IN_CONQUER_RANGE]				= request_update_fortresses_in_conquer_range;
	request_processors[REQUEST_BUILD_NEW_BASE_SHELL]					= request_build_new_base_shell;	
	request_processors[REQUEST_AVAILABLE_FORTRESS_CLASSES]				= request_update_available_fortress_classes;		
	request_processors[REQUEST_FORTRESS_CLASS_DATA]						= request_update_fortress_class_data;	
	request_processors[REQUEST_PLAYER_FORTRESSES_BUILD_INFORMATION]		= request_update_player_fortresses_build_information;		
	request_processors[REQUEST_CONQUER_FORTRESS]						= request_conquer_fortress;	
    request_processors[REQUEST_NAVIGATION_MOVE_TO_SPOBJ_BY_WARP]        = request_navigation_move_to_spobj_by_warp;
	request_processors[REQUEST_FORTRESS_ADD_ACCOMMODATIONS]				= request_fortress_add_accommodations;
	request_processors[REQUEST_FORTRESS_ADD_CREW]						= request_fortress_add_crew;
	request_processors[REQUEST_FORTRESS_REMOVE_CREW]					= request_fortress_remove_crew;
	request_processors[REQUEST_NAVIGATION_DOCK_DOWN]					= request_navigation_dock_down;
	request_processors[REQUEST_NAVIGATION_UNBOUND]						= request_navigation_unbound;
	request_processors[REQUEST_PLAYER_FORTRESSES]						= request_update_player_fortresses;
	request_processors[REQUEST_REGISTER_PLAYER]							= request_register_player;
	request_processors[REQUEST_GAME_SECONDS_PER_ACTUAL_SECOND]			= request_game_seconds_per_actual_second;
	request_processors[REQUEST_RENAME_FORTRESS]							= request_rename_fortress;
	request_processors[REQUEST_PLAYER_FORTRESSES_ATTACK_INFORMATION]	= request_update_player_fortresses_attack_information;
	request_processors[REQUEST_HANGAR_BUILD_SHIP]						= request_hangar_build_ship;
	request_processors[REQUEST_FORTRESS_SENSORS_INFORMATION]			= request_update_fortress_sensors_information;
	request_processors[REQUEST_FORTRESS_CLOAKING_INFORMATION]			= request_update_fortress_cloaking_information;
    request_processors[REQUEST_SHIPWARPINFO]                            = request_ship_warp_info;
	

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

	request_processors[REQUEST_ADMIN_PLAYERS]							= request_admin_players;
	request_processors[REQUEST_ADMIN_PLAYER_INFORMATION]				= request_admin_player_information;
	request_processors[REQUEST_ADMIN_SHIP_INFORMATION]					= request_admin_ship_information;	
	request_processors[REQUEST_ADMIN_BASE_INFORMATION]					= request_admin_base_information;	
	request_processors[REQUEST_ADMIN_BAN_PLAYER]						= request_admin_ban_player;	
	request_processors[REQUEST_ADMIN_PLAYER_BAN_INFORMATION]			= request_admin_player_ban_information;	
	request_processors[REQUEST_ADMIN_ADD_REALM]							= request_admin_add_realm;
}

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

engine :: engine() 
{
	suppressClientUpdates_ = 0;
    tAxis_.setEngine(this);
} 

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

engineMainThread :: engineMainThread() : sem_(0, EMT_QUEUE_MAX_ITEMS)
{
    stopping_ = false;
}

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

void engineMainThread :: start(void)
{
    stopping_ = false;
}

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

void engineMainThread :: stop(void)
{
    stopping_ = true;
    sem_.up();
}

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

void engineMainThread :: beginWork(void)
{
    workLock_.lock();
}

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

void engineMainThread :: endWork(void)
{
    workLock_.unlock();
}
    
// --------------------------------

void engineMainThread :: addRequest(id cl, message* ms)
{
    queueLock_.lock();

    if (!stopping_)
    {
        requests_.push_back(make_pair(cl, ms));
    }
    else delete ms;

    queueLock_.unlock();
    sem_.up();
}

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

void engineMainThread :: addEvent(triggerEventClass* ev)
{
    queueLock_.lock();

    if (!stopping_)
    {
        events_.push_back(ev);
    }
    else delete ev;

    queueLock_.unlock();
    sem_.up();
}

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

void engineMainThread :: operator ()(threads::thread *thd)
{
    while (!stopping_)
    {
        std :: list<triggerEventClass *> eventTriggersToProcess;

        beginWork();
        actx->synchronize(false);
        endWork();
        
        // napred nacti vsechny eventy
        queueLock_.lock();

        eventTriggersToProcess = events_;
        events_.clear();

        queueLock_.unlock();

        // tyto eventy zpracuj
        for (std :: list<triggerEventClass *> :: iterator iter = eventTriggersToProcess.begin(); 
            iter != eventTriggersToProcess.end(); iter++)
        {
            if (!stopping_)
            {
                beginWork();
                setContextById((*iter)->getServerID());
                (*iter)->checkEvent();
                (*iter)->DBDelete();
                endWork();
            }

            delete *iter;
        }

        // nacti jeden request a pripadne ho zpracuj      
        queueLock_.lock();

        if (requests_.size() > 0) {
            std :: pair<id, message*> r = requests_.front();
            requests_.pop_front();
            queueLock_.unlock();

            // zpracuj request
            beginWork();
            setContextById(r.first.second); // <- reimplementovat, v pripade zmeny             
            id idUser = eng_->processRequest(r.first, r.second->getRequestName(), r.second->getValues());
            endWork();

            // jestlize je ID clienta nulove, znamena to, ze mame koncit
            if (idUser.first == 0) {
                gctx.closeClient(idUser);
            }
            else
            {
#if defined(_DEBUG) && defined(DV_SERVER_VERBOSE) && defined(DV_SERVER_VERBOSE_REQUEST)
                std :: stringstream ss;
                ss << "Client [" << idUser.first << "] request \"" << r.second->getRequestName() << "\" processed!";
                log(ss.str());
#endif
            }

            delete r.second;
        } 
        else queueLock_.unlock();

        
        sem_.down();
    }

    // uvolni vsechny eventy a requesty
    queueLock_.lock();

    for (std :: list<triggerEventClass *> :: iterator iter = events_.begin(); 
        iter != events_.end(); iter++)
    {
        delete *iter;
    }
    events_.clear();

    for (std :: list<pair<id, message*>> :: iterator iter = requests_.begin(); iter != requests_.end(); iter++)
    {
        delete iter->second;
    }
    requests_.clear();

    queueLock_.unlock();

    actx->synchronize(true);
}

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

void engine :: start(void)
{
    LOG("Starting engine: time axis and message queue...");
    active_ = true;
    tAxis_.start();  
    emt_.start();
    thread_ = new threads :: thread(&emt_, false);
    LOG("Engine initialized and running...");
}

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

void engine :: stop(void)
{
    LOG("Stopping engine: time axis and message queue...");
    active_ = false;
    emt_.stop();
    tAxis_.stop();  
    thread_->join();
    delete thread_;
    thread_ = NULL;
    LOG("Engine stopped...");
}

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

void engine :: beginWork(void)
{
    emt_.beginWork();
}

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

void engine :: endWork(void)
{
    //actx->db.commit();
    emt_.endWork();
}

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

id engine :: processRequest(id cl, const std :: string& requestName, 
							std :: map<std :: string, std :: string>& parameters)
{
    map<std :: string, request_fn> :: iterator iter = request_processors.find(requestName);
    if (iter != request_processors.end())
    {
        /* provedeme akci */
#if defined(_DEBUG) && defined(DV_SERVER_VERBOSE) && defined(DV_SERVER_VERBOSE_REQUEST)
        std :: stringstream ss;
        ss << "Client [" << cl.first << "] Processing request: " << requestName;
        log(ss.str());
#endif
        id returnedCl = (iter->second)(cl, requestName, parameters);
		// Pridano zastaveni priznaku cteni
		stopReadOnlyRequest();
		return returnedCl;
    } else
    {
#if defined(_DEBUG) && defined(DV_SERVER_VERBOSE) && defined(DV_SERVER_VERBOSE_REQUEST)
        std :: stringstream ss;
        ss << "Client [" << cl.first << "] Unknown request: " << requestName;
        log(ss.str());
#endif
        /* provedeme defaultni akci - odpoved ze je spatny request*/
        protocolWriter w;
        w.beginMessage(MT_ANSWER, BAD_REQUEST_MESSAGE);
        w.writeValue(BAD_REQUEST_MESSAGE_NAME, requestName);
        w.endMessage(false);
        gctx.sendToClient(cl, w.copyMessage());

        return make_pair(0, 0);
    }
}

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

void engine :: addRequest(id cl, message* ms)
{
    if (active_)
    {
        emt_.addRequest(cl, ms);
    }
    else
        delete ms;
}

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

void engine :: addEvent(triggerEventClass* ev)
{
    if (active_)
    {
        emt_.addEvent(ev);
    }
    else
        delete ev;
}

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

void engine :: registerEvent(dv_time:: datetime gameTime, triggerEventClass* ev, unsigned long long& lastEventID)
{
    if (active_)
    {
        tAxis_.pushEventTrigger(gameTime, ev, lastEventID);
    }
    else
        delete ev;
}

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

