void EntityImporterBase::sightArrived(const Operation & op, OpVector & res)
{
    if (op->isDefaultArgs() || op->getArgs().empty()) {
        S_LOG_FAILURE("No arg");
        return;
    }
    const Root & arg = op->getArgs().front();
    switch (m_state) {
    case ENTITY_WALKSTART:
        if (op->isDefaultRefno()) {
            break;
        }
        if (arg->isDefaultId()) {
            S_LOG_WARNING("Corrupted top level entity: no id");
            cancel();
            return;
        } else {
            getEntity(arg->getId(), res);
        }


        // Expecting sight of world root
        break;
    case ENTITY_UPDATING:
    {
        const Operation& sub_op = smart_dynamic_cast<Operation>(arg);
        if (!sub_op.isValid()) {
            break;
        }
        if (sub_op->getClassNo() != Atlas::Objects::Operation::SET_NO || sub_op->getArgs().empty() || sub_op->isDefaultSerialno()) {
            S_LOG_FAILURE("This is not our entity update response.");
            break;
        }
        walkEntities(res);
    }
        break;
    case ENTITY_CREATING:
    case ENTITY_WALKING:
        //Just ignore sights when creating; these are sights of the actual creation ops.
        break;
    default:
        S_LOG_WARNING("Unexpected state in state machine: " << m_state);
        break;
    };
}
void EntityImporterBase::infoArrived(const Operation & op, OpVector & res)
{
    if (op->isDefaultRefno()) {
        return;
    }
    if (op->isDefaultArgs() || op->getArgs().empty()) {
        S_LOG_FAILURE("Info with no arg.");
        return;
    }
    const Root & arg = op->getArgs().front();

    if (m_state == RULE_WALKING) {
        auto& current = mRuleStack.back();
        if (arg->getId() != current.definition->getId()) {
            S_LOG_WARNING("Got info on rule " << arg->getId() << " when expecting " << current.definition->getId() << ".");
            return;
        }

        updateRule(arg, current.definition, res);

    } else if (m_state == RULE_CREATING) {
        mStats.rulesProcessedCount++;
        mStats.rulesCreateCount++;
        EventProgress.emit();
        walkRules(res);
    } else if (m_state == RULE_UPDATING) {
        mStats.rulesProcessedCount++;
        mStats.rulesUpdateCount++;
        EventProgress.emit();
        walkRules(res);
    } else if (m_state == ENTITY_CREATING) {
        if (!op.isValid()) {
            return;
        }
        mNewIds.insert(arg->getId());
        StackEntry & current = mTreeStack.back();
        current.restored_id = arg->getId();
        S_LOG_VERBOSE("Created: " << arg->getParent() << "(" << arg->getId() << ")");

        auto I = mCreateEntityMapping.find(op->getRefno());
        if (I != mCreateEntityMapping.end()) {
            //Check if there's a mind that we should send further on
            auto mindI = mPersistedMinds.find(I->second);
            if (mindI != mPersistedMinds.end()) {
                mResolvedMindMapping.emplace_back(arg->getId(), mindI->second);
            }
            mEntityIdMap.insert(std::make_pair(I->second, arg->getId()));
            mCreateEntityMapping.erase(op->getRefno());
        } else {
            S_LOG_WARNING("Got info about create for an entity which we didn't seem to have sent.");
        }

        walkEntities(res);
    } else if (m_state == ENTITY_WALKING) {
        const RootEntity& ent = smart_dynamic_cast<RootEntity>(arg);
        if (!ent.isValid()) {
            S_LOG_FAILURE("Info response is not entity.");
            return;
        }
        if (arg->isDefaultId()) {
            S_LOG_FAILURE("Corrupted info response: no id.");
        }
        const std::string & id = arg->getId();

        StackEntry & current = mTreeStack.back();
        const RootEntity& obj = current.obj;

        assert(id == obj->getId());

        if (mNewIds.find(id) != mNewIds.end() || (mTreeStack.size() != 1 && ent->isDefaultLoc()) || ent->getParent() != obj->getParent()) {
            createEntity(obj, res);
        } else {

            Root update = obj.copy();

            current.restored_id = id;

            S_LOG_VERBOSE("Updating: " << obj->getId() << " ," << obj->getParent());

            update->removeAttrFlag(Atlas::Objects::Entity::CONTAINS_FLAG);
            update->removeAttrFlag(Atlas::Objects::STAMP_FLAG);

            Set set;
            set->setArgs1(update);
            set->setFrom(mAvatarId);
            set->setTo(id);
            set->setSerialno(newSerialNumber());

            res.push_back(set);

            //Check if there's a mind, and if so put it in our map of resolved entity-to-mind mappings (since we know the entity id)
            auto mindI = mPersistedMinds.find(obj->getId());
            if (mindI != mPersistedMinds.end()) {
                mResolvedMindMapping.emplace_back(obj->getId(), mindI->second);
            }

            ++mStats.entitiesProcessedCount;
            ++mStats.entitiesUpdateCount;
            EventProgress.emit();

            m_state = ENTITY_UPDATING;
        }
    }
}