void StandardLocationService::addLocalObject(const UUID& uuid, const TimedMotionVector3f& loc, const TimedMotionQuaternion& orient, const BoundingSphere3f& bnds, const String& msh, const String& phy) {
    LocationMap::iterator it = mLocations.find(uuid);

    // Add or update the information to the cache
    if (it == mLocations.end()) {
        mLocations[uuid] = LocationInfo();
        it = mLocations.find(uuid);
    } else {
        // It was already in there as a replica, notify its removal
        assert(it->second.local == false);
        CONTEXT_SPACETRACE(serverObjectEvent, 0, mContext->id(), uuid, false, TimedMotionVector3f()); // FIXME remote server ID
        notifyReplicaObjectRemoved(uuid);
    }

    LocationInfo& locinfo = it->second;
    locinfo.location = loc;
    locinfo.orientation = orient;
    locinfo.bounds = bnds;
    locinfo.mesh = msh;
    locinfo.physics = phy;
    locinfo.local = true;
    locinfo.aggregate = false;

    // FIXME: we might want to verify that location(uuid) and bounds(uuid) are
    // reasonable compared to the loc and bounds passed in

    // Add to the list of local objects
    CONTEXT_SPACETRACE(serverObjectEvent, mContext->id(), mContext->id(), uuid, true, loc);
    notifyLocalObjectAdded(uuid, false, location(uuid), orientation(uuid), bounds(uuid), mesh(uuid), physics(uuid));
}
/*
  Destructor
*/
CraqObjectSegmentation::~CraqObjectSegmentation()
{
    //    should delete not found queue;
    while (mNfData.size() != 0)
    {
        NotFoundData* nfd = mNfData.front();
        mNfData.pop();
        delete nfd;
    }


    for (TrackedMessageMapAdded::iterator tmessmapit  = trackedAddMessages.begin(); tmessmapit != trackedAddMessages.end(); ++tmessmapit)
        delete tmessmapit->second.msgAdded;

    trackedAddMessages.clear();



    CONTEXT_SPACETRACE(processOSegShutdownEvents,
                       mContext->id(),
                       numLookups,
                       numOnThisServer,
                       numCacheHits,
                       numCraqLookups,
                       numTimeElapsedCacheEviction,
                       numMigrationNotCompleteYet);

}
void StandardLocationService::locationUpdate(UUID source, void* buffer, uint32 length) {
    Sirikata::Protocol::Loc::Container loc_container;
    bool parse_success = loc_container.ParseFromString( String((char*) buffer, length) );
    if (!parse_success) {
        LOG_INVALID_MESSAGE_BUFFER(standardloc, error, ((char*)buffer), length);
        return;
    }

    if (loc_container.has_update_request()) {
        Sirikata::Protocol::Loc::LocationUpdateRequest request = loc_container.update_request();

        TrackingType obj_type = type(source);
        if (obj_type == Local) {
            LocationMap::iterator loc_it = mLocations.find( source );
            assert(loc_it != mLocations.end());

            if (request.has_location()) {
                TimedMotionVector3f newloc(
                    request.location().t(),
                    MotionVector3f( request.location().position(), request.location().velocity() )
                );
                loc_it->second.location = newloc;
                notifyLocalLocationUpdated( source, loc_it->second.aggregate, newloc );

                CONTEXT_SPACETRACE(serverLoc, mContext->id(), mContext->id(), source, newloc );
            }

            if (request.has_bounds()) {
                BoundingSphere3f newbounds = request.bounds();
                loc_it->second.bounds = newbounds;
                notifyLocalBoundsUpdated( source, loc_it->second.aggregate, newbounds );
            }

            if (request.has_mesh()) {
                String newmesh = request.mesh();
                loc_it->second.mesh = newmesh;
                notifyLocalMeshUpdated( source, loc_it->second.aggregate, newmesh );
            }

            if (request.has_orientation()) {
                TimedMotionQuaternion neworient(
                    request.orientation().t(),
                    MotionQuaternion( request.orientation().position(), request.orientation().velocity() )
                );
                loc_it->second.orientation = neworient;
                notifyLocalOrientationUpdated( source, loc_it->second.aggregate, neworient );
            }

            if (request.has_physics()) {
                String newphy = request.physics();
                loc_it->second.physics = newphy;
                notifyLocalPhysicsUpdated( source, loc_it->second.aggregate, newphy );
            }

        }
        else {
            // Warn about update to non-local object
        }
    }
}
void StandardLocationService::addReplicaObject(const Time& t, const UUID& uuid, const TimedMotionVector3f& loc, const TimedMotionQuaternion& orient, const BoundingSphere3f& bnds, const String& msh, const String& phy) {
    // FIXME we should do checks on timestamps to decide which setting is "more" sane
    LocationMap::iterator it = mLocations.find(uuid);

    if (it != mLocations.end()) {
        // It already exists. If its local, ignore the update. If its another replica, somethings out of sync, but perform the update anyway
        LocationInfo& locinfo = it->second;
        if (!locinfo.local) {
            locinfo.location = loc;
            locinfo.orientation = orient;
            locinfo.bounds = bnds;
            locinfo.mesh = msh;
            locinfo.physics = phy;
            //local = false
            // FIXME should we notify location and bounds updated info?
        }
        // else ignore
    }
    else {
        // Its a new replica, just insert it
        LocationInfo locinfo;
        locinfo.location = loc;
        locinfo.orientation = orient;
        locinfo.bounds = bnds;
        locinfo.mesh = msh;
        locinfo.physics = phy;
        locinfo.local = false;
        locinfo.aggregate = false;
        mLocations[uuid] = locinfo;

        // We only run this notification when the object actually is new
        CONTEXT_SPACETRACE(serverObjectEvent, 0, mContext->id(), uuid, true, loc); // FIXME add remote server ID
        notifyReplicaObjectAdded(uuid, location(uuid), orientation(uuid), bounds(uuid), mesh(uuid), physics(uuid));
    }
}
void FairServerMessageReceiver::service() {
#define MAX_MESSAGES_PER_ROUND 100

    boost::mutex::scoped_try_lock lock(mServiceMutex);
    if (!lock.owns_lock()) return;

    mProfiler->started();

    mServiceScheduled = false;

    Time tcur = mContext->simTime();

    // Receive
    ServerID sid;
    Message* next_recv_msg = NULL;
    uint32 num_recv = 0;
    uint32 cum_recv_size = 0;
    uint32 went_empty = false;
    while( num_recv < MAX_MESSAGES_PER_ROUND && !mContext->stopped() ) {
        {
            boost::lock_guard<boost::mutex> lck(mMutex);

            next_recv_msg = mReceiveQueues.pop(&sid);
        }

        if (next_recv_msg == NULL) {
            went_empty = true;
            break;
        }

        cum_recv_size += next_recv_msg->size();

        CONTEXT_SPACETRACE(serverDatagramReceived, mContext->simTime(), next_recv_msg->source_server(), next_recv_msg->id(), next_recv_msg->serializedSize());
        mListener->serverMessageReceived(next_recv_msg);

        num_recv++;
    }

    mBytesUsed += cum_recv_size;
    mCapacityEstimator.estimate_rate(tcur, cum_recv_size);

    if (!went_empty) {
        // Since the queues are not empty that means we must have stopped due to
        // insufficient budget of bytes.  Setup a timer to let us check again
        // soon.
        // FIXME we should calculate an exact duration instead of making it up
        mBlocked=true;
        mStoppedMaxMessages++;
        mServiceTimer->wait( Duration::microseconds(1) );
    } else {
        mStoppedUnderflow++;
        mBlocked=false;
    }
    mProfiler->finished();

    return;
}
void StandardLocationService::removeLocalObject(const UUID& uuid) {
    // Remove from mLocations, but save the cached state
    assert( mLocations.find(uuid) != mLocations.end() );
    assert( mLocations[uuid].local == true );
    assert( mLocations[uuid].aggregate == false );
    mLocations.erase(uuid);

    // Remove from the list of local objects
    CONTEXT_SPACETRACE(serverObjectEvent, mContext->id(), mContext->id(), uuid, false, TimedMotionVector3f());
    notifyLocalObjectRemoved(uuid, false);

    // FIXME we might want to give a grace period where we generate a replica if one isn't already there,
    // instead of immediately removing all traces of the object.
    // However, this needs to be handled carefully, prefer updates from another server, and expire
    // automatically.
}
//should be called from inside of o_strand and posts to postingStrand mainStrand->post.
void CraqObjectSegmentation::callOsegLookupCompleted(const UUID& obj_id, const CraqEntry& sID, OSegLookupTraceToken* traceToken)
{
    if (mStopping)
    {
        if (traceToken != NULL)
            delete traceToken;
        return;
    }

    mLookupListener->osegLookupCompleted(obj_id,sID);

    if (traceToken != NULL) {
        traceToken->stamp(OSegLookupTraceToken::OSEG_TRACE_LOOKUP_RETURN_END);
        CONTEXT_SPACETRACE(osegCumulativeResponse, traceToken);
        delete traceToken;
    }
}
void StandardLocationService::removeReplicaObject(const Time& t, const UUID& uuid) {
    // FIXME we should maintain some time information and check t against it to make sure this is sane

    LocationMap::iterator it = mLocations.find(uuid);
    if (it == mLocations.end())
        return;

    // If the object is marked as local, this is out of date information.  Just ignore it.
    LocationInfo& locinfo = it->second;
    if (locinfo.local)
        return;

    // Otherwise, remove and notify
    mLocations.erase(uuid);
    CONTEXT_SPACETRACE(serverObjectEvent, 0, mContext->id(), uuid, false, TimedMotionVector3f()); // FIXME add remote server ID
    notifyReplicaObjectRemoved(uuid);
}
//called from within o_strand
void CraqObjectSegmentation::processMigrateMessageAcknowledge(const Sirikata::Protocol::OSeg::MigrateMessageAcknowledge& msg)
{
    if (mStopping)
        return;

    CraqEntry serv_from(msg.m_servid_from(),msg.m_objradius());
    UUID obj_id;

    obj_id    = msg.m_objid();


    InTransitMap::iterator inTransIt;

    mCraqCache->insert(obj_id, serv_from);

    inTransOrLookup_m.lock();
    inTransIt = mInTransitOrLookup.find(obj_id);
    if (inTransIt != mInTransitOrLookup.end())
    {
        //means that we now remove the obj_id from mInTransit
        mInTransitOrLookup.erase(inTransIt);
        //add it to mFinishedMove.  serv_from

        //put the value in the cache!
        mCraqCache->insert(obj_id, serv_from);
        callOsegLookupCompleted(obj_id,serv_from, NULL);


        //log reception of acknowled message
        CONTEXT_SPACETRACE(objectAcknowledgeMigrate,
                           obj_id,serv_from.server(),
                           mContext->id());
    }
    inTransOrLookup_m.unlock();

    //send a message to the server that object should now disconnect
    mWriteListener->osegMigrationAcknowledged(obj_id);
}
/*
  If we get a message to move an object that our server holds, then we add the object's id to mInTransit.
  Whatever calls this must verify that the object is on this server.
  I can do the check in the function by querrying bambooDht as well
*/
void CraqObjectSegmentation::migrateObject(const UUID& obj_id, const OSegEntry& new_server_id)
{
    if (mStopping)
        return;

    //log the message.
    CONTEXT_SPACETRACE(objectBeginMigrate,
                       obj_id,mContext->id(),
                       new_server_id.server());

    InTransitMap::const_iterator transIter = mInTransitOrLookup.find(obj_id);

    TransLookup tmpTransLookup;
    tmpTransLookup.sID = CraqEntry(new_server_id);

    Duration tmpDurer = Time::local() - Time::epoch();

    tmpTransLookup.timeAdmitted = (int)tmpDurer.toMilliseconds();

    mInTransitOrLookup[obj_id] = tmpTransLookup;

    //erases the local copy of obj_id
    UUID tmp_id = obj_id; //note: can probably delete this line

    //erase the local copy of the object.
    size_t num_erased = mObjects.erase(obj_id);
#ifdef CRAQ_DEBUG
    if (num_erased == 0)
    {
        std::cout<<"\n\nThe object clearly wasn't registered on this server.  This is obj id:  " <<  obj_id.toString() <<  ".  This is time:   " <<mContext->simTime().raw() << " Oh no.   ";

        if (clearToMigrate(obj_id))
            std::cout<<"  Likely a problem with clear to migrate\n\n";
        else
            std::cout<<"\n\n clear to migrate is fine migration is being called from somewhere besides server.cpp\n\n";
    }
#endif
}
void CraqObjectSegmentation::beginCraqLookup(const UUID& obj_id, OSegLookupTraceToken* traceToken)
{
    --mOSegQueueLen;
    if (mStopping)
    {
        delete traceToken;
        return;
    }

    traceToken->stamp(OSegLookupTraceToken::OSEG_TRACE_CRAQ_LOOKUP_BEGIN);

    UUID tmper = obj_id;
    InTransitMap::const_iterator iter = mInTransitOrLookup.find(tmper);

    if (iter == mInTransitOrLookup.end()) //means that the object isn't already being looked up and the object isn't already in transit
    {
        //Duration beginCraqLookupNotAlreadyLookingUpDur = Time::local() - Time::epoch();
        //traceToken->craqLookupNotAlreadyLookingUpBegin  = beginCraqLookupNotAlreadyLookingUpDur.toMicroseconds();
        traceToken->stamp(OSegLookupTraceToken::OSEG_TRACE_CRAQ_LOOKUP_NOT_ALREADY_LOOKING_UP_BEGIN);

        //if object is not in transit, lookup its location in the dht.  returns -1 if object doesn't exist.
        //add the mapping of a craqData Key to a uuid.

        ++numCraqLookups;

        std::string indexer = "";
        indexer.append(1,myUniquePrefixKey);
        indexer.append(tmper.rawHexData());

        CraqDataSetGet cdSetGet (indexer,CraqEntry::null(),false,CraqDataSetGet::GET); //bftm modified

        mapDataKeyToUUID[indexer] = tmper; //changed here.


        CONTEXT_SPACETRACE(objectSegmentationCraqLookupRequest,
                           obj_id,
                           mContext->id());

        ++numLookingUpDebug;

        //puts object in transit or lookup.
        //Duration timerDur =  Time::local() - Time::epoch();

        TransLookup tmpTransLookup;
        tmpTransLookup.sID = CraqEntry::null();  //means that we're performing a lookup, rather than a migrate.
        //tmpTransLookup.timeAdmitted = (int)timerDur.toMilliseconds();
        tmpTransLookup.timeAdmitted = 0;

        mInTransitOrLookup[tmper] = tmpTransLookup; //just says that we are performing a lookup on the object

        traceToken->stamp(OSegLookupTraceToken::OSEG_TRACE_CRAQ_LOOKUP_END);
        traceToken->stamp(OSegLookupTraceToken::OSEG_TRACE_CRAQ_LOOKUP_NOT_ALREADY_LOOKING_UP_END);

        if ((numCraqLookups %2) == 0)
            craqDhtGet1.get(cdSetGet,traceToken); //calling the craqDht to do a get
        else
            craqDhtGet2.get(cdSetGet,traceToken); //calling the craqDht to do a get.
    }
    else
    {
        ++numAlreadyLookingUp;
        traceToken->stamp(OSegLookupTraceToken::OSEG_TRACE_CRAQ_LOOKUP_END);
        CONTEXT_SPACETRACE(osegCumulativeResponse, traceToken);
        delete traceToken;
    }
}
/*
  After insuring that the object isn't in transit, the lookup should querry the dht.
  Only called from postingStrand
*/
OSegEntry CraqObjectSegmentation::lookup(const UUID& obj_id)
{

    if (mStopping)
        return CraqEntry::null();


    OSegLookupTraceToken* traceToken = new OSegLookupTraceToken(obj_id,shouldLog());
    traceToken->stamp(OSegLookupTraceToken::OSEG_TRACE_INITIAL_LOOKUP_TIME);


    ++numLookups;
    float radius=0;
    if (checkOwn(obj_id,&radius))  //this call just checks through to see whether the object is on this space server.
    {
        ++numOnThisServer;
        delete traceToken;
        return CraqEntry(mContext->id(),radius);
    }

    //log the request.
    CONTEXT_SPACETRACE(objectSegmentationLookupNotOnServerRequest,
                       obj_id,
                       mContext->id());


    if (checkMigratingFromNotCompleteYet(obj_id,&radius))//this call just checks to see whether the object is migrating from this server to another server.  If it is, but hasn't yet received an ack message to disconnect the object connection.
    {
        ++numMigrationNotCompleteYet;
        delete traceToken;
        return CraqEntry(mContext->id(),radius);
    }


    traceToken->stamp(OSegLookupTraceToken::OSEG_TRACE_CHECK_CACHE_LOCAL_BEGIN);

    CraqEntry cacheReturn = satisfiesCache(obj_id);
    if ((cacheReturn.notNull()) && (cacheReturn.server() != mContext->id())) //have to perform second check to prevent accidentally infinitely re-routing to this server when the object doesn't reside here: if the object resided here, then one of the first two conditions would have triggered.
    {
        CONTEXT_SPACETRACE(osegCacheResponse,
                           cacheReturn.server(),
                           obj_id);

        ++numCacheHits;


        traceToken->stamp(OSegLookupTraceToken::OSEG_TRACE_CHECK_CACHE_LOCAL_END);

        delete traceToken;
        return cacheReturn;
    }


    traceToken->stamp(OSegLookupTraceToken::OSEG_TRACE_CHECK_CACHE_LOCAL_END);

    ++mOSegQueueLen;
    traceToken->osegQLenPostQuery = mOSegQueueLen;
    oStrand->post(boost::bind(&CraqObjectSegmentation::beginCraqLookup,this,obj_id, traceToken));

    return CraqEntry::null();
}
void StandardLocationService::receiveMessage(Message* msg) {
    assert(msg->dest_port() == SERVER_PORT_LOCATION);
    Sirikata::Protocol::Loc::BulkLocationUpdate contents;
    bool parsed = parsePBJMessage(&contents, msg->payload());

    if (parsed) {
        for(int32 idx = 0; idx < contents.update_size(); idx++) {
            Sirikata::Protocol::Loc::LocationUpdate update = contents.update(idx);

            // Its possible we'll get an out of date update. We only use this update
            // if (a) we have this object marked as a replica object and (b) we don't
            // have this object marked as a local object
            if (type(update.object()) != Replica)
                continue;

            LocationMap::iterator loc_it = mLocations.find( update.object() );
            // We can safely make this assertion right now because space server
            // to space server loc and prox are on the same reliable channel. If
            // this goes away then a) we can't make this assertion and b) we
            // need an OrphanLocUpdateManager to save updates where this
            // condition is false so they can be applied once the prox update
            // arrives.
            assert(loc_it != mLocations.end());

            if (update.has_location()) {
                TimedMotionVector3f newloc(
                    update.location().t(),
                    MotionVector3f( update.location().position(), update.location().velocity() )
                );
                loc_it->second.location = newloc;
                notifyReplicaLocationUpdated( update.object(), newloc );

                CONTEXT_SPACETRACE(serverLoc, msg->source_server(), mContext->id(), update.object(), newloc );
            }

            if (update.has_orientation()) {
                TimedMotionQuaternion neworient(
                    update.orientation().t(),
                    MotionQuaternion( update.orientation().position(), update.orientation().velocity() )
                );
                loc_it->second.orientation = neworient;
                notifyReplicaOrientationUpdated( update.object(), neworient );
            }

            if (update.has_bounds()) {
                BoundingSphere3f newbounds = update.bounds();
                loc_it->second.bounds = newbounds;
                notifyReplicaBoundsUpdated( update.object(), newbounds );
            }

            if (update.has_mesh()) {
                String newmesh = update.mesh();
                loc_it->second.mesh = newmesh;
                notifyReplicaMeshUpdated( update.object(), newmesh );
            }

            if (update.has_physics()) {
                String newphy = update.physics();
                loc_it->second.physics = newphy;
                notifyReplicaPhysicsUpdated( update.object(), newphy );
            }
        }
    }

    delete msg;
}