<commit_before>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////

#include "CollectionNameResolver.h"

#include "Basics/Common.h"
#include "Basics/NumberUtils.h"
#include "Basics/ReadLocker.h"
#include "Basics/StringUtils.h"
#include "Cluster/ClusterInfo.h"
#include "VocBase/LogicalCollection.h"
#include "VocBase/LogicalView.h"
#include "VocBase/vocbase.h"

namespace arangodb {

std::shared_ptr<LogicalCollection> CollectionNameResolver::getCollection(
  TRI_voc_cid_t id
) const noexcept {
  #ifdef ARANGODB_ENABLE_MAINTAINER_MODE
    return std::dynamic_pointer_cast<LogicalCollection>(getDataSource(id));
  #else
  auto dataSource = getDataSource(id);

  return dataSource && dataSource->category() == LogicalCollection::category()
    ? std::static_pointer_cast<LogicalCollection>(dataSource) : nullptr;
  #endif
}

std::shared_ptr<LogicalCollection> CollectionNameResolver::getCollection(
  std::string const& nameOrId
) const noexcept {
  #ifdef ARANGODB_ENABLE_MAINTAINER_MODE
    return std::dynamic_pointer_cast<LogicalCollection>(getDataSource(nameOrId));
  #else
  auto dataSource = getDataSource(nameOrId);

  return dataSource && dataSource->category() == LogicalCollection::category()
    ? std::static_pointer_cast<LogicalCollection>(dataSource) : nullptr;
  #endif
}

//////////////////////////////////////////////////////////////////////////////
/// @brief look up a collection id for a collection name (local case),
/// use this if you know you are on a single server or on a DBserver
/// and need to look up a local collection name (or shard name).
//////////////////////////////////////////////////////////////////////////////

TRI_voc_cid_t CollectionNameResolver::getCollectionIdLocal(
    std::string const& name) const {
  if (name[0] >= '0' && name[0] <= '9') {
    // name is a numeric id
    return NumberUtils::atoi_zero<TRI_voc_cid_t>(name.data(), name.data() + name.size());
  }

  arangodb::LogicalCollection const* collection = getCollectionStruct(name);

  if (collection != nullptr) {
    return collection->id();
  }

  auto view = _vocbase->lookupView(name);

  if (view) {
    return view->id();
  }

  return 0;
}

//////////////////////////////////////////////////////////////////////////////
/// @brief look up a cluster collection id for a cluster collection name,
/// only use this is in cluster mode on a coordinator or DBserver, in both
/// cases the name is resolved as a cluster wide collection name and the
/// cluster wide collection id is returned.
//////////////////////////////////////////////////////////////////////////////

TRI_voc_cid_t CollectionNameResolver::getCollectionIdCluster(
    std::string const& name) const {
  if (!ServerState::isRunningInCluster(_serverRole)) {
    return getCollectionIdLocal(name);
  }
  if (name[0] >= '0' && name[0] <= '9') {
    // name is a numeric id
    TRI_voc_cid_t cid = NumberUtils::atoi_zero<TRI_voc_cid_t>(name.data(), name.data() + name.size());
    auto collection = getCollection(cid);
    // Now validate the cid
    auto type = collection ? collection->type() : TRI_COL_TYPE_UNKNOWN;

    if (type == TRI_COL_TYPE_UNKNOWN) {
      return 0;
    }
    return cid;
  }

  try {
    // We have to look up the collection info:
    ClusterInfo* ci = ClusterInfo::instance();
    auto cinfo = ci->getCollection(_vocbase->name(), name);

    if (cinfo) {
      return cinfo->id();
    }

    auto vinfo = ci->getView(_vocbase->name(), name);

    if (vinfo) {
      return vinfo->id();
    }
  } catch (...) {
  }

  return 0;
}

//////////////////////////////////////////////////////////////////////////////
/// @brief look up a collection id for a collection name, this is the
/// default one to use, which will usually do the right thing. On a
/// single server or DBserver it will use the local lookup and on a
/// coordinator it will use the cluster wide lookup.
//////////////////////////////////////////////////////////////////////////////

TRI_voc_cid_t CollectionNameResolver::getCollectionId(
    std::string const& name) const {
  if (!ServerState::isRunningInCluster(_serverRole) ||
      ServerState::isDBServer(_serverRole)) {
    return getCollectionIdLocal(name);
  }
  return getCollectionIdCluster(name);
}

//////////////////////////////////////////////////////////////////////////////
/// @brief look up a collection struct for a collection name
//////////////////////////////////////////////////////////////////////////////

arangodb::LogicalCollection const* CollectionNameResolver::getCollectionStruct(
    std::string const& name) const {
  auto it = _resolvedNames.find(name);

  if (it != _resolvedNames.end()) {
    return (*it).second;
  }

  auto* collection = _vocbase->lookupCollection(name).get();

  if (collection != nullptr) {
    _resolvedNames.emplace(name, collection);
  }

  return collection;
}

//////////////////////////////////////////////////////////////////////////////
/// @brief look up a collection name for a collection id, this implements
/// some magic in the cluster case: a DBserver in a cluster will automatically
/// translate the local collection ID into a cluster wide collection name.
//////////////////////////////////////////////////////////////////////////////

std::string CollectionNameResolver::getCollectionName(TRI_voc_cid_t cid) const {
  auto it = _resolvedIds.find(cid);

  if (it != _resolvedIds.end()) {
    return (*it).second;
  }

  std::string name = localNameLookup(cid);
  _resolvedIds.emplace(cid, name);

  return name;
}

//////////////////////////////////////////////////////////////////////////////
/// @brief look up a cluster-wide collection name for a cluster-wide
/// collection id
//////////////////////////////////////////////////////////////////////////////

std::string CollectionNameResolver::getCollectionNameCluster(
    TRI_voc_cid_t cid) const {
  // First check the cache:
  auto it = _resolvedIds.find(cid);

  if (it != _resolvedIds.end()) {
    return (*it).second;
  }

  if (!ServerState::isClusterRole(_serverRole)) {
    // This handles the case of a standalone server
    return getCollectionName(cid);
  }

  std::string name;

  if (ServerState::isDBServer(_serverRole)) {
    // This might be a local system collection:
    name = localNameLookup(cid);
    if (name != "_unknown") {
      _resolvedIds.emplace(cid, name);
      return name;
    }
  }

  int tries = 0;

  while (tries++ < 2) {
    try {
      auto ci = ClusterInfo::instance()->getCollection(
          _vocbase->name(), arangodb::basics::StringUtils::itoa(cid));

      name = ci->name();
      _resolvedIds.emplace(cid, name);
      return name;
    } catch (...) {
      // most likely collection not found. now try again
      ClusterInfo::instance()->flush();
    }
  }

  LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "CollectionNameResolver: was not able to resolve id " << cid;
  return "_unknown";
}

//////////////////////////////////////////////////////////////////////////////
/// @brief return collection name if given string is either the name or
/// a string with the (numerical) collection id, this returns the cluster
/// wide collection name in the DBserver case
//////////////////////////////////////////////////////////////////////////////

std::string CollectionNameResolver::getCollectionName(
    std::string const& nameOrId) const {
  if (!nameOrId.empty() &&
      (nameOrId[0] < '0' || nameOrId[0] > '9')) {
    return nameOrId;
  }
  return getCollectionName(NumberUtils::atoi_zero<TRI_voc_cid_t>(nameOrId.data(), nameOrId.data() + nameOrId.size()));
}

std::string CollectionNameResolver::localNameLookup(TRI_voc_cid_t cid) const {
  std::string name;

  if (ServerState::isDBServer(_serverRole)) {
    READ_LOCKER(readLocker, _vocbase->_dataSourceLock);
    auto it = _vocbase->_dataSourceById.find(cid);

    if (it != _vocbase->_dataSourceById.end()
        && LogicalCollection::category() == it->second->category()) {
      if (it->second->planId() == it->second->id()) {
        // DBserver local case
        name = (*it).second->name();
      } else {
        // DBserver case of a shard:
        name = arangodb::basics::StringUtils::itoa((*it).second->planId());
        std::shared_ptr<LogicalCollection> ci;

        try {
          TRI_ASSERT(it->second->vocbase());
          ci = ClusterInfo::instance()->getCollection(
            it->second->vocbase()->name(), name
          );
        }
        catch (...) {
        }

        if (ci == nullptr) {
          name = ""; // collection unknown
        } else {
          name = ci->name();  // can be empty, if collection unknown
        }
      }
    }
  } else {
    // exactly as in the non-cluster case
    name = _vocbase->collectionName(cid);
  }

  if (name.empty()) {
    name = "_unknown";
  }
  return name;
}

std::shared_ptr<LogicalDataSource> CollectionNameResolver::getDataSource(
    TRI_voc_cid_t id
) const noexcept {
  auto itr = _dataSourceById.find(id);

  if (itr != _dataSourceById.end()) {
    return itr->second;
  }

  std::shared_ptr<LogicalDataSource> ptr;

  // db server / standalone
  if (!ServerState::isCoordinator(_serverRole)) {
    ptr = _vocbase ? _vocbase->lookupDataSource(id) : nullptr;
  } else {
    ptr = getDataSource(std::to_string(id));
  }

  if (ptr) {
    _dataSourceById.emplace(id, ptr);
  }

  return ptr;
}

std::shared_ptr<LogicalDataSource> CollectionNameResolver::getDataSource(
  std::string const& nameOrId
) const noexcept {
  auto itr = _dataSourceByName.find(nameOrId);

  if (itr != _dataSourceByName.end()) {
    return itr->second;
  }

  std::shared_ptr<LogicalDataSource> ptr;

  // db server / standalone
  if (!ServerState::isCoordinator(_serverRole)) {
    ptr = _vocbase ? _vocbase->lookupDataSource(nameOrId) : nullptr;
  } else {
    // cluster coordinator
    auto* ci = ClusterInfo::instance();

    if (!ci) {
      return nullptr;
    }

    try {
      ptr = std::static_pointer_cast<LogicalDataSource>(
        ci->getCollection(_vocbase->name(), nameOrId)
      );

      if (!ptr) {
        ptr = std::static_pointer_cast<LogicalDataSource>(
          ci->getView(_vocbase->name(), nameOrId)
        );
      }
    } catch (...) {
      LOG_TOPIC(ERR, arangodb::Logger::FIXME)
        << "caught exception while resolving cluster data-source: " << nameOrId;
    }

  return nullptr;
}

std::shared_ptr<LogicalDataSource> CollectionNameResolver::getDataSource(
    std::string const& name
) const noexcept {
  // db server / standalone
  if (!ServerState::isRunningInCluster(_serverRole)
      || ServerState::isDBServer(_serverRole)) {
    return _vocbase ? _vocbase->lookupDataSource(name) : nullptr;
  }

  // cluster coordinator
  auto* ci = ClusterInfo::instance();

  if (!ci) {
    return nullptr;
  }

  try {
    auto cinfo = ci->getCollection(_vocbase->name(), name);

    if (cinfo) {
      return cinfo;
    }

    return ci->getView(_vocbase->name(), name);
  } catch (...) {
    LOG_TOPIC(ERR, arangodb::Logger::FIXME)
      << "caught exception while resolving cluster data-source name: " << name;
  }

  if (ptr) {
    _dataSourceByName.emplace(nameOrId, ptr);
  }

  return ptr;
}

std::shared_ptr<LogicalView> CollectionNameResolver::getView(
  TRI_voc_cid_t id
) const noexcept {
  #ifdef ARANGODB_ENABLE_MAINTAINER_MODE
    return std::dynamic_pointer_cast<LogicalView>(getDataSource(id));
  #else
  auto dataSource = getDataSource(id);

  return dataSource && dataSource->category() == LogicalView::category()
    ? std::static_pointer_cast<LogicalView>(dataSource) : nullptr;
  #endif
}

std::shared_ptr<LogicalView> CollectionNameResolver::getView(
  std::string const& nameOrId
) const noexcept {
  #ifdef ARANGODB_ENABLE_MAINTAINER_MODE
    return std::dynamic_pointer_cast<LogicalView>(getDataSource(nameOrId));
  #else
  auto dataSource = getDataSource(nameOrId);

  return dataSource && dataSource->category() == LogicalView::category()
    ? std::static_pointer_cast<LogicalView>(dataSource) : nullptr;
  #endif
}

std::string CollectionNameResolver::getViewNameCluster(
    TRI_voc_cid_t cid
) const {
  if (!ServerState::isClusterRole(_serverRole)) {
    // This handles the case of a standalone server
    return _vocbase->viewName(cid);
  }

  // FIXME not supported
  return StaticStrings::Empty;
}

bool CollectionNameResolver::visitCollections(
    std::function<bool(LogicalCollection&)> const& visitor,
    TRI_voc_cid_t id
) const {
  auto dataSource = getDataSource(id);

  if (!dataSource) {
    return false; // no way to determine what to visit
  }

  if (LogicalCollection::category() == dataSource->category()) {
    #ifdef ARANGODB_ENABLE_MAINTAINER_MODE
      auto collection = std::dynamic_pointer_cast<LogicalCollection>(dataSource);
      TRI_ASSERT(collection);
    #else
      auto collection = std::static_pointer_cast<LogicalCollection>(dataSource);
    #endif

    // TODO resolve smart edge collection CIDs here
    return visitor(*collection);
  }

  if (LogicalView::category() == dataSource->category()) {
    #ifdef ARANGODB_ENABLE_MAINTAINER_MODE
      auto view = std::dynamic_pointer_cast<LogicalView>(dataSource);
    #else
      auto view = std::static_pointer_cast<LogicalView>(dataSource);
    #endif

    // each CID in a view might need further resolution
    return view->visitCollections([this, &visitor, id](TRI_voc_cid_t cid)->bool {
      return cid == id ? false : visitCollections(visitor, cid); // avoid infinite recursion
    });
  }

  return false; // no way to determine what to visit
}

} // namespace arangodb
<commit_msg>fixes after merge<commit_after>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////

#include "CollectionNameResolver.h"

#include "Basics/Common.h"
#include "Basics/NumberUtils.h"
#include "Basics/ReadLocker.h"
#include "Basics/StringUtils.h"
#include "Cluster/ClusterInfo.h"
#include "VocBase/LogicalCollection.h"
#include "VocBase/LogicalView.h"
#include "VocBase/vocbase.h"

namespace arangodb {

std::shared_ptr<LogicalCollection> CollectionNameResolver::getCollection(
  TRI_voc_cid_t id
) const noexcept {
  #ifdef ARANGODB_ENABLE_MAINTAINER_MODE
    return std::dynamic_pointer_cast<LogicalCollection>(getDataSource(id));
  #else
  auto dataSource = getDataSource(id);

  return dataSource && dataSource->category() == LogicalCollection::category()
    ? std::static_pointer_cast<LogicalCollection>(dataSource) : nullptr;
  #endif
}

std::shared_ptr<LogicalCollection> CollectionNameResolver::getCollection(
  std::string const& nameOrId
) const noexcept {
  #ifdef ARANGODB_ENABLE_MAINTAINER_MODE
    return std::dynamic_pointer_cast<LogicalCollection>(getDataSource(nameOrId));
  #else
  auto dataSource = getDataSource(nameOrId);

  return dataSource && dataSource->category() == LogicalCollection::category()
    ? std::static_pointer_cast<LogicalCollection>(dataSource) : nullptr;
  #endif
}

//////////////////////////////////////////////////////////////////////////////
/// @brief look up a collection id for a collection name (local case),
/// use this if you know you are on a single server or on a DBserver
/// and need to look up a local collection name (or shard name).
//////////////////////////////////////////////////////////////////////////////

TRI_voc_cid_t CollectionNameResolver::getCollectionIdLocal(
    std::string const& name) const {
  if (name[0] >= '0' && name[0] <= '9') {
    // name is a numeric id
    return NumberUtils::atoi_zero<TRI_voc_cid_t>(name.data(), name.data() + name.size());
  }

  arangodb::LogicalCollection const* collection = getCollectionStruct(name);

  if (collection != nullptr) {
    return collection->id();
  }

  auto view = _vocbase->lookupView(name);

  if (view) {
    return view->id();
  }

  return 0;
}

//////////////////////////////////////////////////////////////////////////////
/// @brief look up a cluster collection id for a cluster collection name,
/// only use this is in cluster mode on a coordinator or DBserver, in both
/// cases the name is resolved as a cluster wide collection name and the
/// cluster wide collection id is returned.
//////////////////////////////////////////////////////////////////////////////

TRI_voc_cid_t CollectionNameResolver::getCollectionIdCluster(
    std::string const& name) const {
  if (!ServerState::isRunningInCluster(_serverRole)) {
    return getCollectionIdLocal(name);
  }
  if (name[0] >= '0' && name[0] <= '9') {
    // name is a numeric id
    TRI_voc_cid_t cid = NumberUtils::atoi_zero<TRI_voc_cid_t>(name.data(), name.data() + name.size());
    auto collection = getCollection(cid);
    // Now validate the cid
    auto type = collection ? collection->type() : TRI_COL_TYPE_UNKNOWN;

    if (type == TRI_COL_TYPE_UNKNOWN) {
      return 0;
    }
    return cid;
  }

  try {
    // We have to look up the collection info:
    ClusterInfo* ci = ClusterInfo::instance();
    auto cinfo = ci->getCollection(_vocbase->name(), name);

    if (cinfo) {
      return cinfo->id();
    }

    auto vinfo = ci->getView(_vocbase->name(), name);

    if (vinfo) {
      return vinfo->id();
    }
  } catch (...) {
  }

  return 0;
}

//////////////////////////////////////////////////////////////////////////////
/// @brief look up a collection id for a collection name, this is the
/// default one to use, which will usually do the right thing. On a
/// single server or DBserver it will use the local lookup and on a
/// coordinator it will use the cluster wide lookup.
//////////////////////////////////////////////////////////////////////////////

TRI_voc_cid_t CollectionNameResolver::getCollectionId(
    std::string const& name) const {
  if (!ServerState::isRunningInCluster(_serverRole) ||
      ServerState::isDBServer(_serverRole)) {
    return getCollectionIdLocal(name);
  }
  return getCollectionIdCluster(name);
}

//////////////////////////////////////////////////////////////////////////////
/// @brief look up a collection struct for a collection name
//////////////////////////////////////////////////////////////////////////////

arangodb::LogicalCollection const* CollectionNameResolver::getCollectionStruct(
    std::string const& name) const {
  auto it = _resolvedNames.find(name);

  if (it != _resolvedNames.end()) {
    return (*it).second;
  }

  auto* collection = _vocbase->lookupCollection(name).get();

  if (collection != nullptr) {
    _resolvedNames.emplace(name, collection);
  }

  return collection;
}

//////////////////////////////////////////////////////////////////////////////
/// @brief look up a collection name for a collection id, this implements
/// some magic in the cluster case: a DBserver in a cluster will automatically
/// translate the local collection ID into a cluster wide collection name.
//////////////////////////////////////////////////////////////////////////////

std::string CollectionNameResolver::getCollectionName(TRI_voc_cid_t cid) const {
  auto it = _resolvedIds.find(cid);

  if (it != _resolvedIds.end()) {
    return (*it).second;
  }

  std::string name = localNameLookup(cid);
  _resolvedIds.emplace(cid, name);

  return name;
}

//////////////////////////////////////////////////////////////////////////////
/// @brief look up a cluster-wide collection name for a cluster-wide
/// collection id
//////////////////////////////////////////////////////////////////////////////

std::string CollectionNameResolver::getCollectionNameCluster(
    TRI_voc_cid_t cid) const {
  // First check the cache:
  auto it = _resolvedIds.find(cid);

  if (it != _resolvedIds.end()) {
    return (*it).second;
  }

  if (!ServerState::isClusterRole(_serverRole)) {
    // This handles the case of a standalone server
    return getCollectionName(cid);
  }

  std::string name;

  if (ServerState::isDBServer(_serverRole)) {
    // This might be a local system collection:
    name = localNameLookup(cid);
    if (name != "_unknown") {
      _resolvedIds.emplace(cid, name);
      return name;
    }
  }

  int tries = 0;

  while (tries++ < 2) {
    try {
      auto ci = ClusterInfo::instance()->getCollection(
          _vocbase->name(), arangodb::basics::StringUtils::itoa(cid));

      name = ci->name();
      _resolvedIds.emplace(cid, name);
      return name;
    } catch (...) {
      // most likely collection not found. now try again
      ClusterInfo::instance()->flush();
    }
  }

  LOG_TOPIC(ERR, arangodb::Logger::FIXME) << "CollectionNameResolver: was not able to resolve id " << cid;
  return "_unknown";
}

//////////////////////////////////////////////////////////////////////////////
/// @brief return collection name if given string is either the name or
/// a string with the (numerical) collection id, this returns the cluster
/// wide collection name in the DBserver case
//////////////////////////////////////////////////////////////////////////////

std::string CollectionNameResolver::getCollectionName(
    std::string const& nameOrId) const {
  if (!nameOrId.empty() &&
      (nameOrId[0] < '0' || nameOrId[0] > '9')) {
    return nameOrId;
  }
  return getCollectionName(NumberUtils::atoi_zero<TRI_voc_cid_t>(nameOrId.data(), nameOrId.data() + nameOrId.size()));
}

std::string CollectionNameResolver::localNameLookup(TRI_voc_cid_t cid) const {
  std::string name;

  if (ServerState::isDBServer(_serverRole)) {
    READ_LOCKER(readLocker, _vocbase->_dataSourceLock);
    auto it = _vocbase->_dataSourceById.find(cid);

    if (it != _vocbase->_dataSourceById.end()
        && LogicalCollection::category() == it->second->category()) {
      if (it->second->planId() == it->second->id()) {
        // DBserver local case
        name = (*it).second->name();
      } else {
        // DBserver case of a shard:
        name = arangodb::basics::StringUtils::itoa((*it).second->planId());
        std::shared_ptr<LogicalCollection> ci;

        try {
          TRI_ASSERT(it->second->vocbase());
          ci = ClusterInfo::instance()->getCollection(
            it->second->vocbase()->name(), name
          );
        }
        catch (...) {
        }

        if (ci == nullptr) {
          name = ""; // collection unknown
        } else {
          name = ci->name();  // can be empty, if collection unknown
        }
      }
    }
  } else {
    // exactly as in the non-cluster case
    name = _vocbase->collectionName(cid);
  }

  if (name.empty()) {
    name = "_unknown";
  }
  return name;
}

std::shared_ptr<LogicalDataSource> CollectionNameResolver::getDataSource(
    TRI_voc_cid_t id
) const noexcept {
  auto itr = _dataSourceById.find(id);

  if (itr != _dataSourceById.end()) {
    return itr->second;
  }

  std::shared_ptr<LogicalDataSource> ptr;

  // db server / standalone
  if (!ServerState::isCoordinator(_serverRole)) {
    ptr = _vocbase ? _vocbase->lookupDataSource(id) : nullptr;
  } else {
    ptr = getDataSource(std::to_string(id));
  }

  if (ptr) {
    _dataSourceById.emplace(id, ptr);
  }

  return ptr;
}

std::shared_ptr<LogicalDataSource> CollectionNameResolver::getDataSource(
  std::string const& nameOrId
) const noexcept {
  auto itr = _dataSourceByName.find(nameOrId);

  if (itr != _dataSourceByName.end()) {
    return itr->second;
  }

  std::shared_ptr<LogicalDataSource> ptr;

  // db server / standalone
  if (!ServerState::isCoordinator(_serverRole)) {
    ptr = _vocbase ? _vocbase->lookupDataSource(nameOrId) : nullptr;
  } else {
    // cluster coordinator
    auto* ci = ClusterInfo::instance();

    if (!ci) {
      return nullptr;
    }

    try {
      ptr = std::static_pointer_cast<LogicalDataSource>(
        ci->getCollection(_vocbase->name(), nameOrId)
      );

      if (!ptr) {
        ptr = std::static_pointer_cast<LogicalDataSource>(
          ci->getView(_vocbase->name(), nameOrId)
        );
      }
    } catch (...) {
      LOG_TOPIC(ERR, arangodb::Logger::FIXME)
        << "caught exception while resolving cluster data-source: " << nameOrId;
    }
  }

  return nullptr;
}

std::shared_ptr<LogicalView> CollectionNameResolver::getView(
  TRI_voc_cid_t id
) const noexcept {
  #ifdef ARANGODB_ENABLE_MAINTAINER_MODE
    return std::dynamic_pointer_cast<LogicalView>(getDataSource(id));
  #else
  auto dataSource = getDataSource(id);

  return dataSource && dataSource->category() == LogicalView::category()
    ? std::static_pointer_cast<LogicalView>(dataSource) : nullptr;
  #endif
}

std::shared_ptr<LogicalView> CollectionNameResolver::getView(
  std::string const& nameOrId
) const noexcept {
  #ifdef ARANGODB_ENABLE_MAINTAINER_MODE
    return std::dynamic_pointer_cast<LogicalView>(getDataSource(nameOrId));
  #else
  auto dataSource = getDataSource(nameOrId);

  return dataSource && dataSource->category() == LogicalView::category()
    ? std::static_pointer_cast<LogicalView>(dataSource) : nullptr;
  #endif
}

std::string CollectionNameResolver::getViewNameCluster(
    TRI_voc_cid_t cid
) const {
  if (!ServerState::isClusterRole(_serverRole)) {
    // This handles the case of a standalone server
    return _vocbase->viewName(cid);
  }

  // FIXME not supported
  return StaticStrings::Empty;
}

bool CollectionNameResolver::visitCollections(
    std::function<bool(LogicalCollection&)> const& visitor,
    TRI_voc_cid_t id
) const {
  auto dataSource = getDataSource(id);

  if (!dataSource) {
    return false; // no way to determine what to visit
  }

  if (LogicalCollection::category() == dataSource->category()) {
    #ifdef ARANGODB_ENABLE_MAINTAINER_MODE
      auto collection = std::dynamic_pointer_cast<LogicalCollection>(dataSource);
      TRI_ASSERT(collection);
    #else
      auto collection = std::static_pointer_cast<LogicalCollection>(dataSource);
    #endif

    // TODO resolve smart edge collection CIDs here
    return visitor(*collection);
  }

  if (LogicalView::category() == dataSource->category()) {
    #ifdef ARANGODB_ENABLE_MAINTAINER_MODE
      auto view = std::dynamic_pointer_cast<LogicalView>(dataSource);
    #else
      auto view = std::static_pointer_cast<LogicalView>(dataSource);
    #endif

    // each CID in a view might need further resolution
    return view->visitCollections([this, &visitor, id](TRI_voc_cid_t cid)->bool {
      return cid == id ? false : visitCollections(visitor, cid); // avoid infinite recursion
    });
  }

  return false; // no way to determine what to visit
}

} // namespace arangodb
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: cachewritescheduler.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 04:24:23 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef CONFIGMGR_CACHEWRITESCHEDULER_HXX
#define CONFIGMGR_CACHEWRITESCHEDULER_HXX

#ifndef CONFIGMGR_MISC_REQUESTOPTIONS_HXX_
#include "requestoptions.hxx"
#endif
#ifndef CONFIGMGR_TIMESTAMP_HXX
#include "timestamp.hxx"
#endif
#ifndef CONFIGMGR_UTILITY_HXX_
#include "utility.hxx"
#endif

#ifndef INCLUDED_SET
#include <set>
#define INCLUDED_SET
#endif

#ifndef _VOS_TIMER_HXX_
#include <vos/timer.hxx>
#endif
#ifndef _VOS_REF_HXX_
#include <vos/ref.hxx>

#endif
#ifndef _OSL_MUTEX_HXX_
#include <osl/mutex.hxx>
#endif

// -----------------------------------------------------------------------------
namespace configmgr
{
    class RequestOptions;
    namespace backend { class ComponentRequest; class CacheController; }

    // Write down the Cache, much less complex than caching Nodes
    // (better control)
    class OCacheWriteScheduler
    {
        typedef std::set< RequestOptions, lessRequestOptions > CacheWriteList; // fire and forget!
        typedef backend::CacheController CacheManager;

        class Timer : public vos::OTimer
        {
            osl::Mutex  m_aMutex;
        public:
            OCacheWriteScheduler* pParent;

            Timer(OCacheWriteScheduler& _rParent) : pParent(&_rParent) {};

            // vos::OTimer
            virtual void SAL_CALL onShot();

            //
            osl::Mutex&     getShotMutex() {return m_aMutex;}

            // stop the scheduling
            void dispose() {
                stop();
                pParent = NULL;
            }

        };
        friend void Timer::onShot();
    private:
        mutable osl::Mutex  m_aMutex;
        vos::ORef<Timer>    m_xTimer;
        CacheManager&       m_rTreeManager;

        CacheWriteList      m_aWriteList;

        TimeInterval m_aWriteInterval;

    public:
    //-------- Construction and destruction -----------------------------------
        explicit
        OCacheWriteScheduler(CacheManager& _rTreeManager, TimeInterval const& _aWriteInterval)
            : m_rTreeManager(_rTreeManager)
            , m_aWriteInterval(_aWriteInterval)
        {
            m_xTimer = new Timer(*this);
        }
        ~OCacheWriteScheduler();

    //-------- Delay and Interval ---------------------------------------------
        /// retrieves the recurrance interval used for cleanup
        TimeInterval const& getWriteInterval() const
        {
            osl::MutexGuard aGuard(m_aMutex);
            return m_aWriteInterval;
        }

        static TimeStamp implGetScheduleTime(TimeStamp const& aBaseTime, TimeInterval const& aDelay)
        {
            return aBaseTime + aDelay;
        }
    //-------- Control of execution  ------------------------------------------
        void scheduleWrite(backend::ComponentRequest _aComponent) CFG_UNO_THROW_ALL(  );

        /// stop pending activities for one set of options (do not discard them)
        bool clearTasks(RequestOptions const& _xOptions);

        /// stop and discard pending activities
        void stopAndWriteCache();

        /// mutex for synchronisation
        osl::Mutex&     getShotMutex() {return m_xTimer->getShotMutex();}

    private:
        // vos::OTimer
        void onTimerShot();

        void runWriter();
        void implStartBefore(TimeStamp const& _aTime);
        void writeOneTreeFoundByOption(RequestOptions const& _aOption) CFG_UNO_THROW_ALL(  );
    };
} // namespace configmgr

#endif // CONFIGMGR_DISPOSETIMER_HXX

<commit_msg>INTEGRATION: CWS configrefactor01 (1.5.84); FILE MERGED 2007/01/11 20:16:04 mmeeks 1.5.84.2: Submitted by: mmeeks More re-factoring, lots of locking rationalized, drastically reduced the mutex count, also removed ~300k interlocked increments with a non-interlocking SimpleReferencedObject base 2007/01/08 20:49:02 mmeeks 1.5.84.1: Issue number: Submitted by: mmeeks Substantial configmgr re-factoring #1 ... 	+ remove endless typedef chains 	+ remove custom allocator & associated complexity 	+ remove Pointer, and 'Address' classes<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: cachewritescheduler.hxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: ihi $ $Date: 2007-11-23 14:37:40 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef CONFIGMGR_CACHEWRITESCHEDULER_HXX
#define CONFIGMGR_CACHEWRITESCHEDULER_HXX

#ifndef CONFIGMGR_MISC_REQUESTOPTIONS_HXX_
#include "requestoptions.hxx"
#endif
#ifndef CONFIGMGR_TIMESTAMP_HXX
#include "timestamp.hxx"
#endif
#ifndef CONFIGMGR_UTILITY_HXX_
#include "utility.hxx"
#endif

#ifndef INCLUDED_SET
#include <set>
#define INCLUDED_SET
#endif

#ifndef _VOS_TIMER_HXX_
#include <vos/timer.hxx>
#endif
#ifndef _VOS_REF_HXX_
#include <vos/ref.hxx>

#endif
#ifndef _OSL_MUTEX_HXX_
#include <osl/mutex.hxx>
#endif

// -----------------------------------------------------------------------------
namespace configmgr
{
    class RequestOptions;
    namespace backend { class ComponentRequest; class CacheController; }

    // Write down the Cache, much less complex than caching Nodes
    // (better control)
    class OCacheWriteScheduler
    {
        typedef std::set< RequestOptions, lessRequestOptions > CacheWriteList; // fire and forget!

        class Timer : public vos::OTimer
        {
        public:
            OCacheWriteScheduler* pParent;

            Timer(OCacheWriteScheduler& _rParent) : pParent(&_rParent) {};

            // vos::OTimer
            virtual void SAL_CALL onShot();

            // stop the scheduling
            void dispose() {
                stop();
                pParent = NULL;
            }

        };
        friend void Timer::onShot();
    private:
        vos::ORef<Timer>          m_xTimer;
        backend::CacheController &m_rTreeManager;
        CacheWriteList        m_aWriteList;
        TimeInterval          m_aWriteInterval;

    public:
    //-------- Construction and destruction -----------------------------------
        explicit
        OCacheWriteScheduler(backend::CacheController& _rTreeManager, TimeInterval const& _aWriteInterval)
            : m_rTreeManager(_rTreeManager)
            , m_aWriteInterval(_aWriteInterval)
        {
            m_xTimer = new Timer(*this);
        }
        ~OCacheWriteScheduler();

    //-------- Delay and Interval ---------------------------------------------
        /// retrieves the recurrance interval used for cleanup
        TimeInterval const& getWriteInterval() const
        {
            UnoApiLock aLock;
            return m_aWriteInterval;
        }

        static TimeStamp implGetScheduleTime(TimeStamp const& aBaseTime, TimeInterval const& aDelay)
        {
            return aBaseTime + aDelay;
        }
    //-------- Control of execution  ------------------------------------------
        void scheduleWrite(backend::ComponentRequest _aComponent) CFG_UNO_THROW_ALL(  );

        /// stop pending activities for one set of options (do not discard them)
        bool clearTasks(RequestOptions const& _xOptions);

        /// stop and discard pending activities
        void stopAndWriteCache();
    private:
        // vos::OTimer
        void onTimerShot();

        void runWriter();
        void implStartBefore(TimeStamp const& _aTime);
        void writeOneTreeFoundByOption(RequestOptions const& _aOption) CFG_UNO_THROW_ALL(  );
    };
} // namespace configmgr

#endif // CONFIGMGR_DISPOSETIMER_HXX

<|endoftext|>


<commit_before>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

#include "condor_common.h"
#include "condor_debug.h"
#include "condor_config.h"
#include "condor_string.h"
#include "daemon_list.h"
#include "dc_collector.h"
#include "internet.h"
#include "ipv6_hostname.h"

DaemonList::DaemonList()
{
}

DaemonList::~DaemonList( void )
{
	Daemon* tmp;
	list.Rewind();
	while( list.Next(tmp) ) {
		delete tmp;
	}
}

void
DaemonList::init( daemon_t type, const char* host_list, const char* pool_list )
{
	Daemon* tmp;
	char* host;
	char const *pool = NULL;
	StringList foo;
	StringList pools;
	if( host_list ) {
		foo.initializeFromString( host_list );
		foo.rewind();
	}
	if( pool_list ) {
		pools.initializeFromString( pool_list );
		pools.rewind();
	}
	while( true ) {
		host = foo.next();
		pool = pools.next();
		if( !host && !pool ) {
			break;
		}
		tmp = buildDaemon( type, host, pool );
		append( tmp );
	}
}

Daemon*
DaemonList::buildDaemon( daemon_t type, const char* host, char const *pool )
{
	Daemon* tmp;
	switch( type ) {
	case DT_COLLECTOR:
		tmp = new DCCollector( host );
		break;
	default:
		tmp = new Daemon( type, host, pool );
		break;
	}
	return tmp;
}

/*************************************************************
 ** SimpleList API
 ************************************************************/

bool
DaemonList::append( Daemon* d) { return list.Append(d); }

bool
DaemonList::Append( Daemon* d) { return list.Append(d); }

bool
DaemonList::isEmpty( void ) { return list.IsEmpty(); }

bool
DaemonList::IsEmpty( void ) { return list.IsEmpty(); }

int
DaemonList::number( void ) { return list.Number(); }

int
DaemonList::Number( void ) { return list.Number(); }

void
DaemonList::rewind( void ) { list.Rewind(); }

void
DaemonList::Rewind( void ) { list.Rewind(); }

bool
DaemonList::current( Daemon* & d ) { return list.Current(d); }

bool
DaemonList::Current( Daemon* & d ) { return list.Current(d); }

bool
DaemonList::next( Daemon* & d ) { return list.Next(d); }

bool
DaemonList::Next( Daemon* & d ) { return list.Next(d); }

bool
DaemonList::atEnd() { return list.AtEnd(); }

bool
DaemonList::AtEnd() { return list.AtEnd(); }

void
DaemonList::deleteCurrent() { this->DeleteCurrent(); }

/*
  NOTE: SimpleList does NOT delete the Daemon objects themselves,
  DeleteCurrent() is only going to delete the pointer itself.  Since
  we're responsible for all this memory (we create the Daemon objects
  in DaemonList::init() and DaemonList::buildDaemon()), we have to be
  responsbile to deallocate it when we're done.  We're already doing
  this correctly in the DaemonList destructor, and we have to do it
  here in the DeleteCurrent() interface, too.
*/
void
DaemonList::DeleteCurrent() {
	Daemon* cur = NULL;
	if( list.Current(cur) && cur ) {
		delete cur;
	}
	list.DeleteCurrent();
}

CollectorList::CollectorList() {
}

CollectorList::~CollectorList() {
}

CollectorList *
CollectorList::create( const char * pool )
{
	CollectorList * result = new CollectorList();
	DCCollector * collector = NULL;

	if (pool) {
			// Eventually we might want to query this collector
			// for all the other collectors in the pool....
		result->append (new DCCollector (pool));
		return result;
	}

		// Read the new names from config file
	StringList collector_name_list;
	char * collector_name_param = NULL;
	collector_name_param = getCmHostFromConfig( "COLLECTOR" );
	if( collector_name_param ) {
		collector_name_list.initializeFromString(collector_name_param);

			// Create collector objects
		collector_name_list.rewind();
		char * collector_name = NULL;
		while ((collector_name = collector_name_list.next()) != NULL) {
			collector = new DCCollector (collector_name);
			result->append (collector);
		}
	} else {
			// Otherwise, just return an empty list
		dprintf( D_ALWAYS, "Warning: Collector information was not found in the configuration file. ClassAds will not be sent to the collector and this daemon will not join a larger Condor pool.\n");
	}
	if( collector_name_param ) {
		free( collector_name_param );
	}
	return result;
}

/***
 *
 * Resort a collector list for locality;
 * prioritize the collector that is best suited for the negotiator
 * running on this machine. This minimizes the delay for fetching
 * ads from the Collector by the Negotiator, which some people
 * consider more critical.
 *
 ***/

int
CollectorList::resortLocal( const char *preferred_collector )
{
		// Find the collector in the list that is best suited for
		// this host. This is determined either by
		// a) preferred_collector passed in
        // b) the collector that has the same hostname as this negotiator
	char * tmp_preferred_collector = NULL;

	if ( !preferred_collector ) {
        // figure out our hostname for plan b) above
		const char * _hostname = get_local_fqdn().Value();
		if ((!_hostname) || !(*_hostname)) {
				// Can't get our hostname??? fuck off
			return -1;
		}

		tmp_preferred_collector = strdup(_hostname);
		preferred_collector = preferred_collector; // So we know to free later
	}

		// First, pick out collector(s) that is on this host
	Daemon *daemon;
	SimpleList<Daemon*> prefer_list;
	this->list.Rewind();
	while ( this->list.Next(daemon) ) {
		if ( same_host (preferred_collector, daemon->fullHostname()) ) {
			this->list.DeleteCurrent();
			prefer_list.Prepend( daemon );
		}
	}

		// Walk through the list of preferred collectors,
		// stuff 'em in the main "list"
	this->list.Rewind();
	prefer_list.Rewind();
	while ( prefer_list.Next(daemon) ) {
		this->list.Prepend( daemon );
	}

	free(tmp_preferred_collector); // Warning, preferred_collector (may have) just became invalid, so do this just before returning.
	return 0;
}

int
CollectorList::sendUpdates (int cmd, ClassAd * ad1, ClassAd* ad2, bool nonblocking) {
	int success_count = 0;

	this->rewind();
	DCCollector * daemon;
	while (this->next(daemon)) {
		dprintf( D_FULLDEBUG,
				 "Trying to update collector %s\n",
				 daemon->addr() );
		if( daemon->sendUpdate(cmd, ad1, ad2, nonblocking) ) {
			success_count++;
		}
	}

	return success_count;
}

QueryResult
CollectorList::query(CondorQuery & cQuery, ClassAdList & adList, CondorError *errstack) {

	int num_collectors = this->number();
	if (num_collectors < 1) {
		return Q_NO_COLLECTOR_HOST;
	}

	SimpleList<DCCollector *> sorted_collectors;
	DCCollector * daemon;
	QueryResult result;
	int pass = 0;

	bool problems_resolving = false;

	for( pass = 1; pass <= 2; pass++ ) {
		this->rewind();
		while (this->next(daemon)) {
				// Only try blacklisted collectors on the second pass
			if( daemon->isBlacklisted() ) {
				if( pass == 1 ) {
					if( num_collectors > 1 ) {
						dprintf( D_ALWAYS,
								 "Collector %s %s is still being avoided if "
								 "an alternative succeeds.\n",
								 daemon->name() ? daemon->name() : "unknown",
								 daemon->addr() ? daemon->addr() : "unknown");
					}
					continue;
				}
			}
			else {
				if( pass == 2 ) {
					continue;
				}
			}
			sorted_collectors.Append( daemon );
		}
	}

	sorted_collectors.Rewind();
	while( sorted_collectors.Next( daemon ) ) {
		if ( ! daemon->addr() ) {
			if ( daemon->name() ) {
				dprintf( D_ALWAYS,
						 "Can't resolve collector %s; skipping\n",
						 daemon->name() );
			} else {
				dprintf( D_ALWAYS,
						 "Can't resolve nameless collector; skipping\n" );
			}
			problems_resolving = true;
			continue;
		}
		dprintf (D_FULLDEBUG,
				 "Trying to query collector %s\n",
				 daemon->addr());

		if( num_collectors > 1 ) {
			daemon->blacklistMonitorQueryStarted();
		}

		result =
			cQuery.fetchAds (adList, daemon->addr(), errstack);

		if( num_collectors > 1 ) {
			daemon->blacklistMonitorQueryFinished( result == Q_OK );
		}

		if (result == Q_OK) {
			return result;
		}
	}

	// only push an error if the error stack exists and is currently empty
	if(problems_resolving && errstack && !errstack->code(0)) {
		MyString errmsg;
		char* tmplist = getCmHostFromConfig( "COLLECTOR" );
		errmsg.sprintf ("Unable to resolve COLLECTOR_HOST (%s).",tmplist?tmplist:"(null)");
		errstack->push("CONDOR_STATUS",1,errmsg.Value());
	}

		// If we've gotten here, there are no good collectors
	return Q_COMMUNICATION_ERROR;
}

bool
CollectorList::next( DCCollector* & d )
{
	return DaemonList::Next( (Daemon*&)d );
}

bool
CollectorList::Next( DCCollector* & d )
{
	return next( d );
}

bool
CollectorList::next( Daemon* & d )
{
	return DaemonList::Next( d );
}

bool
CollectorList::Next( Daemon* & d )
{
	return next( d );
}
<commit_msg>fixed CollectorList to have broken hostname<commit_after>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

#include "condor_common.h"
#include "condor_debug.h"
#include "condor_config.h"
#include "condor_string.h"
#include "daemon_list.h"
#include "dc_collector.h"
#include "internet.h"
#include "ipv6_hostname.h"

DaemonList::DaemonList()
{
}

DaemonList::~DaemonList( void )
{
	Daemon* tmp;
	list.Rewind();
	while( list.Next(tmp) ) {
		delete tmp;
	}
}

void
DaemonList::init( daemon_t type, const char* host_list, const char* pool_list )
{
	Daemon* tmp;
	char* host;
	char const *pool = NULL;
	StringList foo;
	StringList pools;
	if( host_list ) {
		foo.initializeFromString( host_list );
		foo.rewind();
	}
	if( pool_list ) {
		pools.initializeFromString( pool_list );
		pools.rewind();
	}
	while( true ) {
		host = foo.next();
		pool = pools.next();
		if( !host && !pool ) {
			break;
		}
		tmp = buildDaemon( type, host, pool );
		append( tmp );
	}
}

Daemon*
DaemonList::buildDaemon( daemon_t type, const char* host, char const *pool )
{
	Daemon* tmp;
	switch( type ) {
	case DT_COLLECTOR:
		tmp = new DCCollector( host );
		break;
	default:
		tmp = new Daemon( type, host, pool );
		break;
	}
	return tmp;
}

/*************************************************************
 ** SimpleList API
 ************************************************************/

bool
DaemonList::append( Daemon* d) { return list.Append(d); }

bool
DaemonList::Append( Daemon* d) { return list.Append(d); }

bool
DaemonList::isEmpty( void ) { return list.IsEmpty(); }

bool
DaemonList::IsEmpty( void ) { return list.IsEmpty(); }

int
DaemonList::number( void ) { return list.Number(); }

int
DaemonList::Number( void ) { return list.Number(); }

void
DaemonList::rewind( void ) { list.Rewind(); }

void
DaemonList::Rewind( void ) { list.Rewind(); }

bool
DaemonList::current( Daemon* & d ) { return list.Current(d); }

bool
DaemonList::Current( Daemon* & d ) { return list.Current(d); }

bool
DaemonList::next( Daemon* & d ) { return list.Next(d); }

bool
DaemonList::Next( Daemon* & d ) { return list.Next(d); }

bool
DaemonList::atEnd() { return list.AtEnd(); }

bool
DaemonList::AtEnd() { return list.AtEnd(); }

void
DaemonList::deleteCurrent() { this->DeleteCurrent(); }

/*
  NOTE: SimpleList does NOT delete the Daemon objects themselves,
  DeleteCurrent() is only going to delete the pointer itself.  Since
  we're responsible for all this memory (we create the Daemon objects
  in DaemonList::init() and DaemonList::buildDaemon()), we have to be
  responsbile to deallocate it when we're done.  We're already doing
  this correctly in the DaemonList destructor, and we have to do it
  here in the DeleteCurrent() interface, too.
*/
void
DaemonList::DeleteCurrent() {
	Daemon* cur = NULL;
	if( list.Current(cur) && cur ) {
		delete cur;
	}
	list.DeleteCurrent();
}

CollectorList::CollectorList() {
}

CollectorList::~CollectorList() {
}

CollectorList *
CollectorList::create( const char * pool )
{
	CollectorList * result = new CollectorList();
	DCCollector * collector = NULL;

	if (pool) {
			// Eventually we might want to query this collector
			// for all the other collectors in the pool....
		result->append (new DCCollector (pool));
		return result;
	}

		// Read the new names from config file
	StringList collector_name_list;
	char * collector_name_param = NULL;
	collector_name_param = getCmHostFromConfig( "COLLECTOR" );
	if( collector_name_param ) {
		collector_name_list.initializeFromString(collector_name_param);

			// Create collector objects
		collector_name_list.rewind();
		char * collector_name = NULL;
		while ((collector_name = collector_name_list.next()) != NULL) {
			collector = new DCCollector (collector_name);
			result->append (collector);
		}
	} else {
			// Otherwise, just return an empty list
		dprintf( D_ALWAYS, "Warning: Collector information was not found in the configuration file. ClassAds will not be sent to the collector and this daemon will not join a larger Condor pool.\n");
	}
	if( collector_name_param ) {
		free( collector_name_param );
	}
	return result;
}

/***
 *
 * Resort a collector list for locality;
 * prioritize the collector that is best suited for the negotiator
 * running on this machine. This minimizes the delay for fetching
 * ads from the Collector by the Negotiator, which some people
 * consider more critical.
 *
 ***/

int
CollectorList::resortLocal( const char *preferred_collector )
{
		// Find the collector in the list that is best suited for
		// this host. This is determined either by
		// a) preferred_collector passed in
        // b) the collector that has the same hostname as this negotiator
	char * tmp_preferred_collector = NULL;

	if ( !preferred_collector ) {
        // figure out our hostname for plan b) above
		MyString _hostname_str = get_local_fqdn();
		const char * _hostname = _hostname_str.Value();
		if (!(*_hostname)) {
				// Can't get our hostname??? fuck off
			return -1;
		}

		tmp_preferred_collector = strdup(_hostname);
		preferred_collector = preferred_collector; // So we know to free later
	}

		// First, pick out collector(s) that is on this host
	Daemon *daemon;
	SimpleList<Daemon*> prefer_list;
	this->list.Rewind();
	while ( this->list.Next(daemon) ) {
		if ( same_host (preferred_collector, daemon->fullHostname()) ) {
			this->list.DeleteCurrent();
			prefer_list.Prepend( daemon );
		}
	}

		// Walk through the list of preferred collectors,
		// stuff 'em in the main "list"
	this->list.Rewind();
	prefer_list.Rewind();
	while ( prefer_list.Next(daemon) ) {
		this->list.Prepend( daemon );
	}

	free(tmp_preferred_collector); // Warning, preferred_collector (may have) just became invalid, so do this just before returning.
	return 0;
}

int
CollectorList::sendUpdates (int cmd, ClassAd * ad1, ClassAd* ad2, bool nonblocking) {
	int success_count = 0;

	this->rewind();
	DCCollector * daemon;
	while (this->next(daemon)) {
		dprintf( D_FULLDEBUG,
				 "Trying to update collector %s\n",
				 daemon->addr() );
		if( daemon->sendUpdate(cmd, ad1, ad2, nonblocking) ) {
			success_count++;
		}
	}

	return success_count;
}

QueryResult
CollectorList::query(CondorQuery & cQuery, ClassAdList & adList, CondorError *errstack) {

	int num_collectors = this->number();
	if (num_collectors < 1) {
		return Q_NO_COLLECTOR_HOST;
	}

	SimpleList<DCCollector *> sorted_collectors;
	DCCollector * daemon;
	QueryResult result;
	int pass = 0;

	bool problems_resolving = false;

	for( pass = 1; pass <= 2; pass++ ) {
		this->rewind();
		while (this->next(daemon)) {
				// Only try blacklisted collectors on the second pass
			if( daemon->isBlacklisted() ) {
				if( pass == 1 ) {
					if( num_collectors > 1 ) {
						dprintf( D_ALWAYS,
								 "Collector %s %s is still being avoided if "
								 "an alternative succeeds.\n",
								 daemon->name() ? daemon->name() : "unknown",
								 daemon->addr() ? daemon->addr() : "unknown");
					}
					continue;
				}
			}
			else {
				if( pass == 2 ) {
					continue;
				}
			}
			sorted_collectors.Append( daemon );
		}
	}

	sorted_collectors.Rewind();
	while( sorted_collectors.Next( daemon ) ) {
		if ( ! daemon->addr() ) {
			if ( daemon->name() ) {
				dprintf( D_ALWAYS,
						 "Can't resolve collector %s; skipping\n",
						 daemon->name() );
			} else {
				dprintf( D_ALWAYS,
						 "Can't resolve nameless collector; skipping\n" );
			}
			problems_resolving = true;
			continue;
		}
		dprintf (D_FULLDEBUG,
				 "Trying to query collector %s\n",
				 daemon->addr());

		if( num_collectors > 1 ) {
			daemon->blacklistMonitorQueryStarted();
		}

		result =
			cQuery.fetchAds (adList, daemon->addr(), errstack);

		if( num_collectors > 1 ) {
			daemon->blacklistMonitorQueryFinished( result == Q_OK );
		}

		if (result == Q_OK) {
			return result;
		}
	}

	// only push an error if the error stack exists and is currently empty
	if(problems_resolving && errstack && !errstack->code(0)) {
		MyString errmsg;
		char* tmplist = getCmHostFromConfig( "COLLECTOR" );
		errmsg.sprintf ("Unable to resolve COLLECTOR_HOST (%s).",tmplist?tmplist:"(null)");
		errstack->push("CONDOR_STATUS",1,errmsg.Value());
	}

		// If we've gotten here, there are no good collectors
	return Q_COMMUNICATION_ERROR;
}

bool
CollectorList::next( DCCollector* & d )
{
	return DaemonList::Next( (Daemon*&)d );
}

bool
CollectorList::Next( DCCollector* & d )
{
	return next( d );
}

bool
CollectorList::next( Daemon* & d )
{
	return DaemonList::Next( d );
}

bool
CollectorList::Next( Daemon* & d )
{
	return next( d );
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <cmath>

#include <geometry_msgs/PoseStamped.h>
#include <jsk_rviz_plugins/OverlayText.h>
#include <ros/ros.h>
#include <std_msgs/String.h>
#include <std_msgs/UInt8.h>

#include <autoware_msgs/lane.h>
#include <autoware_msgs/traffic_light.h>

#include <cross_road_area.hpp>
#include <decision_maker_node.hpp>
#include <state.hpp>
#include <state_context.hpp>

namespace decision_maker
{
void DecisionMakerNode::callbackFromCurrentPose(const geometry_msgs::PoseStamped &msg)
{
  geometry_msgs::PoseStamped _pose = current_pose_ = msg;
  bool initLocalizationFlag = ctx->isCurrentState(state_machine::INITIAL_LOCATEVEHICLE_STATE);
  if (initLocalizationFlag &&
      isLocalizationConvergence(_pose.pose.position.x, _pose.pose.position.y, _pose.pose.position.z,
                                _pose.pose.orientation.x, _pose.pose.orientation.y, _pose.pose.orientation.z))
  {
    ROS_INFO("Localization was convergence");
  }
}

bool DecisionMakerNode::handleStateCmd(const uint64_t _state_num)
{
  bool _ret;
  ctx->setEnableForceSetState(true);
  if (!ctx->isCurrentState(_state_num))
  {
    _ret = ctx->setCurrentState((state_machine::StateFlags)_state_num);
    if(_state_num == state_machine::DRIVE_BEHAVIOR_TRAFFICLIGHT_RED_STATE
		    || _state_num == state_machine::DRIVE_BEHAVIOR_TRAFFICLIGHT_GREEN_STATE){
	    isManualLight = true;
    }
  }
  else
  {
    _ret = ctx->disableCurrentState((state_machine::StateFlags)_state_num);
    if(_state_num == state_machine::DRIVE_BEHAVIOR_TRAFFICLIGHT_RED_STATE
		    || _state_num == state_machine::DRIVE_BEHAVIOR_TRAFFICLIGHT_GREEN_STATE){
	    isManualLight = false;
  }
  ctx->setEnableForceSetState(false);

  return _ret;
}

void DecisionMakerNode::callbackFromSimPose(const geometry_msgs::PoseStamped &msg)
{
  ROS_INFO("Received system is going to simulation mode");
  handleStateCmd(state_machine::DRIVE_STATE);
  Subs["sim_pose"].shutdown();
}

void DecisionMakerNode::callbackFromStateCmd(const std_msgs::Int32 &msg)
{
  ROS_INFO("Received forcing state changing request: %llx", 1ULL << (uint64_t)msg.data);
  handleStateCmd((uint64_t)1ULL << (uint64_t)msg.data);
}

void DecisionMakerNode::callbackFromLaneChangeFlag(const std_msgs::Int32 &msg)
{
  if (msg.data == enumToInteger<E_ChangeFlags>(E_ChangeFlags::LEFT))
  {
    ctx->disableCurrentState(state_machine::DRIVE_BEHAVIOR_LANECHANGE_RIGHT_STATE);
    ctx->setCurrentState(state_machine::DRIVE_BEHAVIOR_LANECHANGE_LEFT_STATE);
  }
  else if (msg.data == enumToInteger<E_ChangeFlags>(E_ChangeFlags::RIGHT))
  {
    ctx->disableCurrentState(state_machine::DRIVE_BEHAVIOR_LANECHANGE_LEFT_STATE);
    ctx->setCurrentState(state_machine::DRIVE_BEHAVIOR_LANECHANGE_RIGHT_STATE);
  }
  else
  {
    ctx->disableCurrentState(state_machine::DRIVE_BEHAVIOR_LANECHANGE_RIGHT_STATE);
    ctx->disableCurrentState(state_machine::DRIVE_BEHAVIOR_LANECHANGE_LEFT_STATE);
  }
}

void DecisionMakerNode::callbackFromConfig(const autoware_msgs::ConfigDecisionMaker &msg)
{
  ROS_INFO("Param setted by Runtime Manager");
  enableDisplayMarker = msg.enable_display_marker;
  ctx->setEnableForceSetState(msg.enable_force_state_change);

  param_target_waypoint_ = msg.target_waypoint;
  param_stopline_target_waypoint_ = msg.stopline_target_waypoint;
  param_shift_width_ = msg.shift_width;
}

void DecisionMakerNode::callbackFromLightColor(const ros::MessageEvent<autoware_msgs::traffic_light const> &event)
{
  const autoware_msgs::traffic_light *light = event.getMessage().get();
//  const ros::M_string &header = event.getConnectionHeader();
//  std::string topic = header.at("topic");

  if(!isManualLight){// && topic.find("manage") == std::string::npos){
	  current_traffic_light_ = light->traffic_light;
	  if (current_traffic_light_ == state_machine::E_RED || current_traffic_light_ == state_machine::E_YELLOW)
	  {
		  ctx->setCurrentState(state_machine::DRIVE_BEHAVIOR_TRAFFICLIGHT_RED_STATE);
		  ctx->disableCurrentState(state_machine::DRIVE_BEHAVIOR_TRAFFICLIGHT_GREEN_STATE);
	  }
	  else
	  {
		  ctx->setCurrentState(state_machine::DRIVE_BEHAVIOR_TRAFFICLIGHT_GREEN_STATE);
		  ctx->disableCurrentState(state_machine::DRIVE_BEHAVIOR_TRAFFICLIGHT_RED_STATE);
	  }
  }
}

void DecisionMakerNode::callbackFromPointsRaw(const sensor_msgs::PointCloud2::ConstPtr &msg)
{
  if (ctx->setCurrentState(state_machine::INITIAL_LOCATEVEHICLE_STATE))
    Subs["points_raw"].shutdown();
}

void DecisionMakerNode::insertPointWithinCrossRoad(const std::vector<CrossRoadArea> &_intersects,
                                                   autoware_msgs::LaneArray &lane_array)
{
  for (auto &lane : lane_array.lanes)
  {
    for (auto &wp : lane.waypoints)
    {
      geometry_msgs::Point pp;
      pp.x = wp.pose.pose.position.x;
      pp.y = wp.pose.pose.position.y;
      pp.z = wp.pose.pose.position.z;

      for (auto &area : intersects)
      {
        if (CrossRoadArea::isInsideArea(&area, pp))
        {
          // area's
          if (area.insideLanes.empty() || wp.gid != area.insideLanes.back().waypoints.back().gid + 1)
          {
            autoware_msgs::lane nlane;
            area.insideLanes.push_back(nlane);
          }
          area.insideLanes.back().waypoints.push_back(wp);
          area.insideWaypoint_points.push_back(pp);  // geometry_msgs::point
          // area.insideLanes.Waypoints.push_back(wp);//autoware_msgs::waypoint
          // lane's wp
          wp.wpstate.aid = area.area_id;
        }
      }
    }
  }
}

geometry_msgs::Point to_geoPoint(const vector_map_msgs::Point &vp)
{
  geometry_msgs::Point gp;
  gp.x = vp.ly;
  gp.y = vp.bx;
  gp.z = vp.h;
  return gp;
}

void DecisionMakerNode::setWaypointState(autoware_msgs::LaneArray &lane_array)
{
  insertPointWithinCrossRoad(intersects, lane_array);
  // STR
  for (auto &area : intersects)
  {
    for (auto &laneinArea : area.insideLanes)
    {
      // To straight/left/right recognition by using angle
      // between first-waypoint and end-waypoint in intersection area.
      int angle_deg = ((int)std::floor(calcIntersectWayAngle(laneinArea)));  // normalized
      int steering_state;

      if (angle_deg <= ANGLE_LEFT)
        steering_state = autoware_msgs::WaypointState::STR_LEFT;
      else if (angle_deg >= ANGLE_RIGHT)
        steering_state = autoware_msgs::WaypointState::STR_RIGHT;
      else
        steering_state = autoware_msgs::WaypointState::STR_STRAIGHT;

      for (auto &wp_lane : laneinArea.waypoints)
        for (auto &lane : lane_array.lanes)
          for (auto &wp : lane.waypoints)
            if (wp.gid == wp_lane.gid && wp.wpstate.aid == area.area_id)
            {
              wp.wpstate.steering_state = steering_state;
            }
    }
  }
  // STOP
  std::vector<StopLine> stoplines = g_vmap.findByFilter([&](const StopLine &stopline) {
    return (g_vmap.findByKey(Key<RoadSign>(stopline.signid)).type == (int)vector_map_msgs::RoadSign::TYPE_STOP);
  });

  for (auto &lane : lane_array.lanes)
  {
    for (size_t wp_idx = 0; wp_idx < lane.waypoints.size() - 1; wp_idx++)
    {
      for (auto &stopline : stoplines)
      {
        geometry_msgs::Point bp =
            to_geoPoint(g_vmap.findByKey(Key<Point>(g_vmap.findByKey(Key<Line>(stopline.lid)).bpid)));
        geometry_msgs::Point fp =
            to_geoPoint(g_vmap.findByKey(Key<Point>(g_vmap.findByKey(Key<Line>(stopline.lid)).fpid)));

        if (amathutils::isIntersectLine(lane.waypoints.at(wp_idx).pose.pose.position.x,
                                        lane.waypoints.at(wp_idx).pose.pose.position.y,
                                        lane.waypoints.at(wp_idx + 1).pose.pose.position.x,
                                        lane.waypoints.at(wp_idx + 1).pose.pose.position.y, bp.x, bp.y, fp.x, fp.y))
        {
          geometry_msgs::Point center_point;
          center_point.x = (bp.x * 2 + fp.x) / 3;
          center_point.y = (bp.y * 2 + fp.y) / 3;
          if (amathutils::isPointLeftFromLine(
                  center_point.x, center_point.y, lane.waypoints.at(wp_idx).pose.pose.position.x,
                  lane.waypoints.at(wp_idx).pose.pose.position.y, lane.waypoints.at(wp_idx + 1).pose.pose.position.x,
                  lane.waypoints.at(wp_idx + 1).pose.pose.position.y))
          {
            lane.waypoints.at(wp_idx).wpstate.stopline_state = 1;
            // lane.waypoints.at(wp_idx + 1).wpstate.stopline_state = 1;
          }
        }
      }
    }
  }
}

// for based waypoint
void DecisionMakerNode::callbackFromLaneWaypoint(const autoware_msgs::LaneArray &msg)
{
  ROS_INFO("[%s]:LoadedWaypointLaneArray\n", __func__);
  current_based_lane_array_ = msg;  // cached based path
  // indexing
  int gid = 0;
  for (auto &lane : current_based_lane_array_.lanes)
  {
    int lid = 0;
    for (auto &wp : lane.waypoints)
    {
      wp.gid = gid++;
      wp.lid = lid++;
      wp.wpstate.aid = 0;
      wp.wpstate.steering_state = autoware_msgs::WaypointState::NULLSTATE;
      wp.wpstate.accel_state = autoware_msgs::WaypointState::NULLSTATE;
      wp.wpstate.stopline_state = autoware_msgs::WaypointState::NULLSTATE;
      wp.wpstate.lanechange_state = autoware_msgs::WaypointState::NULLSTATE;
      wp.wpstate.event_state = 0;
    }
  }
  setWaypointState(current_based_lane_array_);
  current_controlled_lane_array_ = current_shifted_lane_array_ = current_based_lane_array_;  // controlled path

  publishControlledLaneArray();
  updateLaneWaypointsArray();
}

state_machine::StateFlags getStateFlags(uint8_t msg_state)
{
  if (msg_state == (uint8_t)autoware_msgs::WaypointState::STR_LEFT)
    return state_machine::DRIVE_STR_LEFT_STATE;
  else if (msg_state == (uint8_t)autoware_msgs::WaypointState::STR_RIGHT)
    return state_machine::DRIVE_STR_RIGHT_STATE;
  else
    return state_machine::DRIVE_STR_STRAIGHT_STATE;
}

void DecisionMakerNode::callbackFromFinalWaypoint(const autoware_msgs::lane &msg)
{
  if (!hasvMap())
  {
    std::cerr << "Not found vmap subscribe" << std::endl;
    return;
  }

  if (!ctx->isCurrentState(state_machine::DRIVE_STATE))
  {
    std::cerr << "State is not DRIVE_STATE[" << ctx->getCurrentStateName() << "]" << std::endl;
    return;
  }
  // cached
  current_finalwaypoints_ = msg;

  size_t idx = current_finalwaypoints_.waypoints.size() - 1 > param_stopline_target_waypoint_ ?
                   param_stopline_target_waypoint_ :
                   current_finalwaypoints_.waypoints.size() - 1;

  if (current_finalwaypoints_.waypoints.at(idx).wpstate.stopline_state)
	  ctx->setCurrentState(state_machine::DRIVE_ACC_STOPLINE_STATE);
  // steering
  idx = current_finalwaypoints_.waypoints.size() - 1 > param_target_waypoint_ ?
            param_target_waypoint_ :
            current_finalwaypoints_.waypoints.size() - 1;
  if (ctx->isCurrentState(state_machine::DRIVE_BEHAVIOR_LANECHANGE_LEFT_STATE))
  {
	  ctx->setCurrentState(state_machine::DRIVE_STR_LEFT_STATE);
  }
  if (ctx->isCurrentState(state_machine::DRIVE_BEHAVIOR_LANECHANGE_RIGHT_STATE))
  {
	  ctx->setCurrentState(state_machine::DRIVE_STR_RIGHT_STATE);
  }
  else
  {
	  ctx->setCurrentState(getStateFlags(current_finalwaypoints_.waypoints.at(idx).wpstate.steering_state));
  }

  // for publish plan of velocity
  publishToVelocityArray();
}
void DecisionMakerNode::callbackFromTwistCmd(const geometry_msgs::TwistStamped &msg)
{
  static bool Twistflag = false;

  if (Twistflag)
    ctx->handleTwistCmd(false);
  else
    Twistflag = true;
}

void DecisionMakerNode::callbackFromClosestWaypoint(const std_msgs::Int32 &msg)
{
  closest_waypoint_ = msg.data;
}

void DecisionMakerNode::callbackFromVectorMapArea(const vector_map_msgs::AreaArray &msg)
{
  initVectorMap();
}
void DecisionMakerNode::callbackFromVectorMapPoint(const vector_map_msgs::PointArray &msg)
{
  initVectorMap();
}
void DecisionMakerNode::callbackFromVectorMapLine(const vector_map_msgs::LineArray &msg)
{
  initVectorMap();
}
void DecisionMakerNode::callbackFromVectorMapCrossRoad(const vector_map_msgs::CrossRoadArray &msg)
{
  initVectorMap();
}

void DecisionMakerNode::callbackFromCurrentVelocity(const geometry_msgs::TwistStamped &msg)
{
  current_velocity_ = amathutils::mps2kmph(msg.twist.linear.x);
}
}
<commit_msg>fix a build bug<commit_after>#include <stdio.h>
#include <cmath>

#include <geometry_msgs/PoseStamped.h>
#include <jsk_rviz_plugins/OverlayText.h>
#include <ros/ros.h>
#include <std_msgs/String.h>
#include <std_msgs/UInt8.h>

#include <autoware_msgs/lane.h>
#include <autoware_msgs/traffic_light.h>

#include <cross_road_area.hpp>
#include <decision_maker_node.hpp>
#include <state.hpp>
#include <state_context.hpp>

namespace decision_maker
{
void DecisionMakerNode::callbackFromCurrentPose(const geometry_msgs::PoseStamped &msg)
{
  geometry_msgs::PoseStamped _pose = current_pose_ = msg;
  bool initLocalizationFlag = ctx->isCurrentState(state_machine::INITIAL_LOCATEVEHICLE_STATE);
  if (initLocalizationFlag &&
      isLocalizationConvergence(_pose.pose.position.x, _pose.pose.position.y, _pose.pose.position.z,
                                _pose.pose.orientation.x, _pose.pose.orientation.y, _pose.pose.orientation.z))
  {
    ROS_INFO("Localization was convergence");
  }
}

bool DecisionMakerNode::handleStateCmd(const uint64_t _state_num)
{
  bool _ret;
  ctx->setEnableForceSetState(true);
  if (!ctx->isCurrentState(_state_num))
  {
    _ret = ctx->setCurrentState((state_machine::StateFlags)_state_num);
    if(_state_num == state_machine::DRIVE_BEHAVIOR_TRAFFICLIGHT_RED_STATE
		    || _state_num == state_machine::DRIVE_BEHAVIOR_TRAFFICLIGHT_GREEN_STATE){
	    isManualLight = true;
    }
    }
  }
  else
  {
    _ret = ctx->disableCurrentState((state_machine::StateFlags)_state_num);
    if(_state_num == state_machine::DRIVE_BEHAVIOR_TRAFFICLIGHT_RED_STATE
		    || _state_num == state_machine::DRIVE_BEHAVIOR_TRAFFICLIGHT_GREEN_STATE){
	    isManualLight = false;
    }
  }
  ctx->setEnableForceSetState(false);

  return _ret;
}

void DecisionMakerNode::callbackFromSimPose(const geometry_msgs::PoseStamped &msg)
{
  ROS_INFO("Received system is going to simulation mode");
  handleStateCmd(state_machine::DRIVE_STATE);
  Subs["sim_pose"].shutdown();
}

void DecisionMakerNode::callbackFromStateCmd(const std_msgs::Int32 &msg)
{
  ROS_INFO("Received forcing state changing request: %llx", 1ULL << (uint64_t)msg.data);
  handleStateCmd((uint64_t)1ULL << (uint64_t)msg.data);
}

void DecisionMakerNode::callbackFromLaneChangeFlag(const std_msgs::Int32 &msg)
{
  if (msg.data == enumToInteger<E_ChangeFlags>(E_ChangeFlags::LEFT))
  {
    ctx->disableCurrentState(state_machine::DRIVE_BEHAVIOR_LANECHANGE_RIGHT_STATE);
    ctx->setCurrentState(state_machine::DRIVE_BEHAVIOR_LANECHANGE_LEFT_STATE);
  }
  else if (msg.data == enumToInteger<E_ChangeFlags>(E_ChangeFlags::RIGHT))
  {
    ctx->disableCurrentState(state_machine::DRIVE_BEHAVIOR_LANECHANGE_LEFT_STATE);
    ctx->setCurrentState(state_machine::DRIVE_BEHAVIOR_LANECHANGE_RIGHT_STATE);
  }
  else
  {
    ctx->disableCurrentState(state_machine::DRIVE_BEHAVIOR_LANECHANGE_RIGHT_STATE);
    ctx->disableCurrentState(state_machine::DRIVE_BEHAVIOR_LANECHANGE_LEFT_STATE);
  }
}

void DecisionMakerNode::callbackFromConfig(const autoware_msgs::ConfigDecisionMaker &msg)
{
  ROS_INFO("Param setted by Runtime Manager");
  enableDisplayMarker = msg.enable_display_marker;
  ctx->setEnableForceSetState(msg.enable_force_state_change);

  param_target_waypoint_ = msg.target_waypoint;
  param_stopline_target_waypoint_ = msg.stopline_target_waypoint;
  param_shift_width_ = msg.shift_width;
}

void DecisionMakerNode::callbackFromLightColor(const ros::MessageEvent<autoware_msgs::traffic_light const> &event)
{
  const autoware_msgs::traffic_light *light = event.getMessage().get();
//  const ros::M_string &header = event.getConnectionHeader();
//  std::string topic = header.at("topic");

  if(!isManualLight){// && topic.find("manage") == std::string::npos){
	  current_traffic_light_ = light->traffic_light;
	  if (current_traffic_light_ == state_machine::E_RED || current_traffic_light_ == state_machine::E_YELLOW)
	  {
		  ctx->setCurrentState(state_machine::DRIVE_BEHAVIOR_TRAFFICLIGHT_RED_STATE);
		  ctx->disableCurrentState(state_machine::DRIVE_BEHAVIOR_TRAFFICLIGHT_GREEN_STATE);
	  }
	  else
	  {
		  ctx->setCurrentState(state_machine::DRIVE_BEHAVIOR_TRAFFICLIGHT_GREEN_STATE);
		  ctx->disableCurrentState(state_machine::DRIVE_BEHAVIOR_TRAFFICLIGHT_RED_STATE);
	  }
  }
}

void DecisionMakerNode::callbackFromPointsRaw(const sensor_msgs::PointCloud2::ConstPtr &msg)
{
  if (ctx->setCurrentState(state_machine::INITIAL_LOCATEVEHICLE_STATE))
    Subs["points_raw"].shutdown();
}

void DecisionMakerNode::insertPointWithinCrossRoad(const std::vector<CrossRoadArea> &_intersects,
                                                   autoware_msgs::LaneArray &lane_array)
{
  for (auto &lane : lane_array.lanes)
  {
    for (auto &wp : lane.waypoints)
    {
      geometry_msgs::Point pp;
      pp.x = wp.pose.pose.position.x;
      pp.y = wp.pose.pose.position.y;
      pp.z = wp.pose.pose.position.z;

      for (auto &area : intersects)
      {
        if (CrossRoadArea::isInsideArea(&area, pp))
        {
          // area's
          if (area.insideLanes.empty() || wp.gid != area.insideLanes.back().waypoints.back().gid + 1)
          {
            autoware_msgs::lane nlane;
            area.insideLanes.push_back(nlane);
          }
          area.insideLanes.back().waypoints.push_back(wp);
          area.insideWaypoint_points.push_back(pp);  // geometry_msgs::point
          // area.insideLanes.Waypoints.push_back(wp);//autoware_msgs::waypoint
          // lane's wp
          wp.wpstate.aid = area.area_id;
        }
      }
    }
  }
}

geometry_msgs::Point to_geoPoint(const vector_map_msgs::Point &vp)
{
  geometry_msgs::Point gp;
  gp.x = vp.ly;
  gp.y = vp.bx;
  gp.z = vp.h;
  return gp;
}

void DecisionMakerNode::setWaypointState(autoware_msgs::LaneArray &lane_array)
{
  insertPointWithinCrossRoad(intersects, lane_array);
  // STR
  for (auto &area : intersects)
  {
    for (auto &laneinArea : area.insideLanes)
    {
      // To straight/left/right recognition by using angle
      // between first-waypoint and end-waypoint in intersection area.
      int angle_deg = ((int)std::floor(calcIntersectWayAngle(laneinArea)));  // normalized
      int steering_state;

      if (angle_deg <= ANGLE_LEFT)
        steering_state = autoware_msgs::WaypointState::STR_LEFT;
      else if (angle_deg >= ANGLE_RIGHT)
        steering_state = autoware_msgs::WaypointState::STR_RIGHT;
      else
        steering_state = autoware_msgs::WaypointState::STR_STRAIGHT;

      for (auto &wp_lane : laneinArea.waypoints)
        for (auto &lane : lane_array.lanes)
          for (auto &wp : lane.waypoints)
            if (wp.gid == wp_lane.gid && wp.wpstate.aid == area.area_id)
            {
              wp.wpstate.steering_state = steering_state;
            }
    }
  }
  // STOP
  std::vector<StopLine> stoplines = g_vmap.findByFilter([&](const StopLine &stopline) {
    return (g_vmap.findByKey(Key<RoadSign>(stopline.signid)).type == (int)vector_map_msgs::RoadSign::TYPE_STOP);
  });

  for (auto &lane : lane_array.lanes)
  {
    for (size_t wp_idx = 0; wp_idx < lane.waypoints.size() - 1; wp_idx++)
    {
      for (auto &stopline : stoplines)
      {
        geometry_msgs::Point bp =
            to_geoPoint(g_vmap.findByKey(Key<Point>(g_vmap.findByKey(Key<Line>(stopline.lid)).bpid)));
        geometry_msgs::Point fp =
            to_geoPoint(g_vmap.findByKey(Key<Point>(g_vmap.findByKey(Key<Line>(stopline.lid)).fpid)));

        if (amathutils::isIntersectLine(lane.waypoints.at(wp_idx).pose.pose.position.x,
                                        lane.waypoints.at(wp_idx).pose.pose.position.y,
                                        lane.waypoints.at(wp_idx + 1).pose.pose.position.x,
                                        lane.waypoints.at(wp_idx + 1).pose.pose.position.y, bp.x, bp.y, fp.x, fp.y))
        {
          geometry_msgs::Point center_point;
          center_point.x = (bp.x * 2 + fp.x) / 3;
          center_point.y = (bp.y * 2 + fp.y) / 3;
          if (amathutils::isPointLeftFromLine(
                  center_point.x, center_point.y, lane.waypoints.at(wp_idx).pose.pose.position.x,
                  lane.waypoints.at(wp_idx).pose.pose.position.y, lane.waypoints.at(wp_idx + 1).pose.pose.position.x,
                  lane.waypoints.at(wp_idx + 1).pose.pose.position.y))
          {
            lane.waypoints.at(wp_idx).wpstate.stopline_state = 1;
            // lane.waypoints.at(wp_idx + 1).wpstate.stopline_state = 1;
          }
        }
      }
    }
  }
}

// for based waypoint
void DecisionMakerNode::callbackFromLaneWaypoint(const autoware_msgs::LaneArray &msg)
{
  ROS_INFO("[%s]:LoadedWaypointLaneArray\n", __func__);
  current_based_lane_array_ = msg;  // cached based path
  // indexing
  int gid = 0;
  for (auto &lane : current_based_lane_array_.lanes)
  {
    int lid = 0;
    for (auto &wp : lane.waypoints)
    {
      wp.gid = gid++;
      wp.lid = lid++;
      wp.wpstate.aid = 0;
      wp.wpstate.steering_state = autoware_msgs::WaypointState::NULLSTATE;
      wp.wpstate.accel_state = autoware_msgs::WaypointState::NULLSTATE;
      wp.wpstate.stopline_state = autoware_msgs::WaypointState::NULLSTATE;
      wp.wpstate.lanechange_state = autoware_msgs::WaypointState::NULLSTATE;
      wp.wpstate.event_state = 0;
    }
  }
  setWaypointState(current_based_lane_array_);
  current_controlled_lane_array_ = current_shifted_lane_array_ = current_based_lane_array_;  // controlled path

  publishControlledLaneArray();
  updateLaneWaypointsArray();
}

state_machine::StateFlags getStateFlags(uint8_t msg_state)
{
  if (msg_state == (uint8_t)autoware_msgs::WaypointState::STR_LEFT)
    return state_machine::DRIVE_STR_LEFT_STATE;
  else if (msg_state == (uint8_t)autoware_msgs::WaypointState::STR_RIGHT)
    return state_machine::DRIVE_STR_RIGHT_STATE;
  else
    return state_machine::DRIVE_STR_STRAIGHT_STATE;
}

void DecisionMakerNode::callbackFromFinalWaypoint(const autoware_msgs::lane &msg)
{
  if (!hasvMap())
  {
    std::cerr << "Not found vmap subscribe" << std::endl;
    return;
  }

  if (!ctx->isCurrentState(state_machine::DRIVE_STATE))
  {
    std::cerr << "State is not DRIVE_STATE[" << ctx->getCurrentStateName() << "]" << std::endl;
    return;
  }
  // cached
  current_finalwaypoints_ = msg;

  size_t idx = current_finalwaypoints_.waypoints.size() - 1 > param_stopline_target_waypoint_ ?
                   param_stopline_target_waypoint_ :
                   current_finalwaypoints_.waypoints.size() - 1;

  if (current_finalwaypoints_.waypoints.at(idx).wpstate.stopline_state)
	  ctx->setCurrentState(state_machine::DRIVE_ACC_STOPLINE_STATE);
  // steering
  idx = current_finalwaypoints_.waypoints.size() - 1 > param_target_waypoint_ ?
            param_target_waypoint_ :
            current_finalwaypoints_.waypoints.size() - 1;
  if (ctx->isCurrentState(state_machine::DRIVE_BEHAVIOR_LANECHANGE_LEFT_STATE))
  {
	  ctx->setCurrentState(state_machine::DRIVE_STR_LEFT_STATE);
  }
  if (ctx->isCurrentState(state_machine::DRIVE_BEHAVIOR_LANECHANGE_RIGHT_STATE))
  {
	  ctx->setCurrentState(state_machine::DRIVE_STR_RIGHT_STATE);
  }
  else
  {
	  ctx->setCurrentState(getStateFlags(current_finalwaypoints_.waypoints.at(idx).wpstate.steering_state));
  }

  // for publish plan of velocity
  publishToVelocityArray();
}
void DecisionMakerNode::callbackFromTwistCmd(const geometry_msgs::TwistStamped &msg)
{
  static bool Twistflag = false;

  if (Twistflag)
    ctx->handleTwistCmd(false);
  else
    Twistflag = true;
}

void DecisionMakerNode::callbackFromClosestWaypoint(const std_msgs::Int32 &msg)
{
  closest_waypoint_ = msg.data;
}

void DecisionMakerNode::callbackFromVectorMapArea(const vector_map_msgs::AreaArray &msg)
{
  initVectorMap();
}
void DecisionMakerNode::callbackFromVectorMapPoint(const vector_map_msgs::PointArray &msg)
{
  initVectorMap();
}
void DecisionMakerNode::callbackFromVectorMapLine(const vector_map_msgs::LineArray &msg)
{
  initVectorMap();
}
void DecisionMakerNode::callbackFromVectorMapCrossRoad(const vector_map_msgs::CrossRoadArray &msg)
{
  initVectorMap();
}

void DecisionMakerNode::callbackFromCurrentVelocity(const geometry_msgs::TwistStamped &msg)
{
  current_velocity_ = amathutils::mps2kmph(msg.twist.linear.x);
}
}
<|endoftext|>


<commit_before>/*
 * NavRenderer.cpp
 *
 *  Created on: 09.05.2012
 *      Author: Ralph
 */
#include "navrenderer.h"

#include <QtCore/QDebug>

#include <QtOpenGL/QGLShaderProgram>
#include <QtGui/QVector3D>
#include <QtGui/QMatrix4x4>

#include "../data/datastore.h"

#ifndef GL_MULTISAMPLE
#define GL_MULTISAMPLE  0x809D
#endif

NavRenderer::NavRenderer( DataStore* dataStore, QString name ) :
    m_dataStore( dataStore ),
    m_name( name ),
    m_ratio( 1.0 ),
    m_program( new QGLShaderProgram ),
    vboIds( new GLuint[ 2 ] ),
    m_x( 0. ),
    m_y( 0. ),
    m_z( 0. ),
    m_xb( 0 ),
    m_yb( 0 ),
    m_zb( 0 )
{
}

NavRenderer::~NavRenderer()
{
}

void NavRenderer::initGL()
{
    glClearColor( 1.0, 0.0, 1.0, 0.0 );

    glEnable( GL_DEPTH_TEST );

    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
    glEnable( GL_BLEND );

    glShadeModel( GL_SMOOTH );
    glEnable( GL_LIGHTING );
    glEnable( GL_LIGHT0 );
    glEnable( GL_MULTISAMPLE );
    static GLfloat lightPosition[ 4 ] = { 0.5, 5.0, -3000.0, 1.0 };
    glLightfv( GL_LIGHT0, GL_POSITION, lightPosition );

    initShader();
}

void NavRenderer::resizeGL( int width, int height )
{

    m_ratio = static_cast<float>( width )/ static_cast<float>(height);
    glViewport( 0, 0, width, height );

    // Reset projection
    QMatrix4x4 pMatrix;
    pMatrix.setToIdentity();

    if ( m_name == "axial" )
    {
        pMatrix.ortho( 0, m_xb, 0, m_yb, -3000, 3000 );
    }
    else if ( m_name == "coronal" )
    {
        pMatrix.ortho( 0, m_xb, 0, m_zb, -3000, 3000 );
    }
    else
    {
        pMatrix.ortho( 0, m_yb, 0, m_zb, -3000, 3000 );
    }
    m_mvpMatrix = pMatrix;
}

void NavRenderer::leftMouseDown( int x, int y )
{
}

void NavRenderer::leftMouseDrag( int x, int y )
{
}

void NavRenderer::initShader()
{
    // Overriding system locale until shaders are compiled
    setlocale( LC_NUMERIC, "C" );

    // Compiling vertex shader
    if ( !m_program->addShaderFromSourceFile( QGLShader::Vertex, ":/shaders/vshader.glsl" ) )
    {
        exit( false );
    }

    // Compiling fragment shader
    if ( !m_program->addShaderFromSourceFile( QGLShader::Fragment, ":/shaders/fshader.glsl" ) )
    {
        exit( false );
    }

    // Linking shader pipeline
    if ( !m_program->link() )
    {
        exit( false );
    }

    // Binding shader pipeline for use
    if ( !m_program->bind() )
    {
        exit( false );
    }

    // Restore system locale
    setlocale( LC_ALL, "" );
}

void NavRenderer::initGeometry()
{
    glGenBuffers( 4, vboIds );

    m_x = m_dataStore->getGlobalSetting( "sagittal" ).toFloat();
    m_y = m_dataStore->getGlobalSetting( "coronal" ).toFloat();
    m_z = m_dataStore->getGlobalSetting( "axial" ).toFloat();
    m_xb = m_dataStore->getGlobalSetting( "max_sagittal" ).toFloat();
    m_yb = m_dataStore->getGlobalSetting( "max_coronal" ).toFloat();
    m_zb = m_dataStore->getGlobalSetting( "max_axial" ).toFloat();

    float dx = m_dataStore->getGlobalSetting( "slice_dx" ).toFloat();
    float dy = m_dataStore->getGlobalSetting( "slice_dy" ).toFloat();
    float dz = m_dataStore->getGlobalSetting( "slice_dz" ).toFloat();

    m_x *= dx;
    m_y *= dy;
    m_z *= dz;
    m_xb *= dx;
    m_yb *= dy;
    m_zb *= dz;

    VertexData verticesAxial[] =
    {
            { QVector3D( 0.0,  0.0,  m_z ), QVector3D( 0.0, 0.0, m_z/m_zb ) },
            { QVector3D( m_xb, 0.0,  m_z ), QVector3D( 1.0, 0.0, m_z/m_zb ) },
            { QVector3D( m_xb, m_yb, m_z ), QVector3D( 1.0, 1.0, m_z/m_zb ) },
            { QVector3D( 0.0,  m_yb, m_z ), QVector3D( 0.0, 1.0, m_z/m_zb ) }
    };

    VertexData verticesCoronal[] =
    {
            { QVector3D( 0.0,  0.0,  m_y ), QVector3D( 0.0, m_y/m_yb, 0.0 ) },
            { QVector3D( m_xb, 0.0,  m_y ), QVector3D( 1.0, m_y/m_yb, 0.0 ) },
            { QVector3D( m_xb, m_zb, m_y ), QVector3D( 1.0, m_y/m_yb, 1.0 ) },
            { QVector3D( 0.0,  m_zb, m_y ), QVector3D( 0.0, m_y/m_yb, 1.0 ) }
    };

    VertexData verticesSagittal[] =
    {
            { QVector3D( 0.0,  0.0,  m_x ), QVector3D( m_x/m_xb, 0.0, 0.0 ) },
            { QVector3D( m_yb, 0.0,  m_x ), QVector3D( m_x/m_xb, 1.0, 0.0 ) },
            { QVector3D( m_yb, m_zb, m_x ), QVector3D( m_x/m_xb, 1.0, 1.0 ) },
            { QVector3D( 0.0,  m_zb, m_x ), QVector3D( m_x/m_xb, 0.0, 1.0 ) }
    };

    GLushort indices[] = { 0, 1, 2, 0, 2, 3 };

    // Transfer index data to VBO 0
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, vboIds[ 0 ] );
    glBufferData( GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(GLushort), indices, GL_STATIC_DRAW );

    // Transfer vertex data to VBO 1
    glBindBuffer( GL_ARRAY_BUFFER, vboIds[ 1 ] );
    glBufferData( GL_ARRAY_BUFFER, 4 * sizeof(VertexData), verticesAxial, GL_STATIC_DRAW );

    // Transfer vertex data to VBO 2
    glBindBuffer( GL_ARRAY_BUFFER, vboIds[ 2 ] );
    glBufferData( GL_ARRAY_BUFFER, 4 * sizeof(VertexData), verticesCoronal, GL_STATIC_DRAW );

    // Transfer vertex data to VBO 3
    glBindBuffer( GL_ARRAY_BUFFER, vboIds[ 3 ] );
    glBufferData( GL_ARRAY_BUFFER, 4 * sizeof(VertexData), verticesSagittal, GL_STATIC_DRAW );

}

void NavRenderer::setupTextures()
{
    GLuint tex = m_dataStore->getFirstTexture();

    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );

    int allocatedTextureCount = 0;

    glActiveTexture( GL_TEXTURE0 + allocatedTextureCount );
    glBindTexture( GL_TEXTURE_3D, tex );

    bool interpolation = false;
    if ( interpolation )
    {
        glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
        glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
    }
    else
    {
        glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
        glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
    }
}

void NavRenderer::setShaderVars()
{
    // Offset for position
    int offset = 0;

    // Tell OpenGL programmable pipeline how to locate vertex position data
    int vertexLocation = m_program->attributeLocation( "a_position" );
    m_program->enableAttributeArray( vertexLocation );
    glVertexAttribPointer( vertexLocation, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (const void *) offset );

    // Offset for texture coordinate
    offset += sizeof(QVector3D);

    // Tell OpenGL programmable pipeline how to locate vertex texture coordinate data
    int texcoordLocation = m_program->attributeLocation("a_texcoord");
    m_program->enableAttributeArray(texcoordLocation);
    glVertexAttribPointer(texcoordLocation, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (const void *)offset);
}

void NavRenderer::draw()
{
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    setupTextures();

    glColor4f( 0.0, 0.0, 0.0, 1.0 );

    // Set modelview-projection matrix
    m_program->setUniformValue( "mvp_matrix", m_mvpMatrix );

    initGeometry();

    if ( m_name == "axial" )
    {
        drawAxial();
    }
    else if ( m_name == "coronal" )
    {
        drawCoronal();
    }
    else
    {
        drawSagittal();
    }

    glDeleteBuffers( 1, &vboIds[0] );
    glDeleteBuffers( 1, &vboIds[1] );
    glDeleteBuffers( 1, &vboIds[2] );
    glDeleteBuffers( 1, &vboIds[3] );
}

void NavRenderer::drawAxial()
{
    // Tell OpenGL which VBOs to use
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, vboIds[ 0 ] );
    glBindBuffer( GL_ARRAY_BUFFER, vboIds[ 1 ] );
    setShaderVars();

    // Draw cube geometry using indices from VBO 0
    glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0 );
}

void NavRenderer::drawCoronal()
{
    // Tell OpenGL which VBOs to use
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, vboIds[ 0 ] );
    glBindBuffer( GL_ARRAY_BUFFER, vboIds[ 2 ] );
    setShaderVars();
    // Draw cube geometry using indices from VBO 0
    glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0 );
}

void NavRenderer::drawSagittal()
{
    // Tell OpenGL which VBOs to use
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, vboIds[ 0 ] );
    glBindBuffer( GL_ARRAY_BUFFER, vboIds[ 3 ] );
    setShaderVars();
    // Draw cube geometry using indices from VBO 0
    glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0 );
}

<commit_msg>adjust ratio of nav slices<commit_after>/*
 * NavRenderer.cpp
 *
 *  Created on: 09.05.2012
 *      Author: Ralph
 */
#include "navrenderer.h"

#include <QtCore/QDebug>

#include <QtOpenGL/QGLShaderProgram>
#include <QtGui/QVector3D>
#include <QtGui/QMatrix4x4>

#include "../data/datastore.h"

#ifndef GL_MULTISAMPLE
#define GL_MULTISAMPLE  0x809D
#endif

NavRenderer::NavRenderer( DataStore* dataStore, QString name ) :
    m_dataStore( dataStore ),
    m_name( name ),
    m_ratio( 1.0 ),
    m_program( new QGLShaderProgram ),
    vboIds( new GLuint[ 2 ] ),
    m_x( 0. ),
    m_y( 0. ),
    m_z( 0. ),
    m_xb( 0 ),
    m_yb( 0 ),
    m_zb( 0 )
{
}

NavRenderer::~NavRenderer()
{
}

void NavRenderer::initGL()
{
    glClearColor( 1.0, 0.0, 1.0, 0.0 );

    glEnable( GL_DEPTH_TEST );

    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
    glEnable( GL_BLEND );

    glShadeModel( GL_SMOOTH );
    glEnable( GL_LIGHTING );
    glEnable( GL_LIGHT0 );
    glEnable( GL_MULTISAMPLE );
    static GLfloat lightPosition[ 4 ] = { 0.5, 5.0, -3000.0, 1.0 };
    glLightfv( GL_LIGHT0, GL_POSITION, lightPosition );

    initShader();
}

void NavRenderer::resizeGL( int width, int height )
{

    m_ratio = static_cast<float>( width )/ static_cast<float>(height);
    glViewport( 0, 0, width, height );

    // Reset projection
    QMatrix4x4 pMatrix;
    pMatrix.setToIdentity();

    if ( m_name == "axial" )
    {

        float textureRatio = m_xb/ m_yb;
        float mult = m_ratio / textureRatio;

        if ( mult >= 1.0 )
        {
            pMatrix.ortho( 0, m_xb * mult, 0, m_yb, -3000, 3000 );
        }
        else
        {
            pMatrix.ortho( 0, m_xb, 0, m_yb * ( 1.0 / mult ) , -3000, 3000 );
        }
    }
    else if ( m_name == "coronal" )
    {
        float textureRatio = m_xb/ m_zb;
        float mult = m_ratio / textureRatio;
        if ( mult >= 1.0 )
        {
            pMatrix.ortho( 0, m_xb * mult, 0, m_zb, -3000, 3000 );
        }
        else
        {
            pMatrix.ortho( 0, m_xb, 0, m_zb * ( 1.0 / mult ), -3000, 3000 );
        }
    }
    else
    {
        float textureRatio = m_yb/ m_zb;
        float mult = m_ratio / textureRatio;
        if ( mult >= 1.0 )
        {
            pMatrix.ortho( 0, m_yb * mult, 0, m_zb, -3000, 3000 );
        }
        else
        {
            pMatrix.ortho( 0, m_yb, 0, m_zb * ( 1.0 / mult ), -3000, 3000 );
        }
    }
    m_mvpMatrix = pMatrix;
}

void NavRenderer::leftMouseDown( int x, int y )
{
}

void NavRenderer::leftMouseDrag( int x, int y )
{
}

void NavRenderer::initShader()
{
    // Overriding system locale until shaders are compiled
    setlocale( LC_NUMERIC, "C" );

    // Compiling vertex shader
    if ( !m_program->addShaderFromSourceFile( QGLShader::Vertex, ":/shaders/vshader.glsl" ) )
    {
        exit( false );
    }

    // Compiling fragment shader
    if ( !m_program->addShaderFromSourceFile( QGLShader::Fragment, ":/shaders/fshader.glsl" ) )
    {
        exit( false );
    }

    // Linking shader pipeline
    if ( !m_program->link() )
    {
        exit( false );
    }

    // Binding shader pipeline for use
    if ( !m_program->bind() )
    {
        exit( false );
    }

    // Restore system locale
    setlocale( LC_ALL, "" );
}

void NavRenderer::initGeometry()
{
    glGenBuffers( 4, vboIds );

    m_x = m_dataStore->getGlobalSetting( "sagittal" ).toFloat();
    m_y = m_dataStore->getGlobalSetting( "coronal" ).toFloat();
    m_z = m_dataStore->getGlobalSetting( "axial" ).toFloat();
    m_xb = m_dataStore->getGlobalSetting( "max_sagittal" ).toFloat();
    m_yb = m_dataStore->getGlobalSetting( "max_coronal" ).toFloat();
    m_zb = m_dataStore->getGlobalSetting( "max_axial" ).toFloat();

    float dx = m_dataStore->getGlobalSetting( "slice_dx" ).toFloat();
    float dy = m_dataStore->getGlobalSetting( "slice_dy" ).toFloat();
    float dz = m_dataStore->getGlobalSetting( "slice_dz" ).toFloat();

    m_x *= dx;
    m_y *= dy;
    m_z *= dz;
    m_xb *= dx;
    m_yb *= dy;
    m_zb *= dz;

    VertexData verticesAxial[] =
    {
            { QVector3D( 0.0,  0.0,  m_z ), QVector3D( 0.0, 0.0, m_z/m_zb ) },
            { QVector3D( m_xb, 0.0,  m_z ), QVector3D( 1.0, 0.0, m_z/m_zb ) },
            { QVector3D( m_xb, m_yb, m_z ), QVector3D( 1.0, 1.0, m_z/m_zb ) },
            { QVector3D( 0.0,  m_yb, m_z ), QVector3D( 0.0, 1.0, m_z/m_zb ) }
    };

    VertexData verticesCoronal[] =
    {
            { QVector3D( 0.0,  0.0,  m_y ), QVector3D( 0.0, m_y/m_yb, 0.0 ) },
            { QVector3D( m_xb, 0.0,  m_y ), QVector3D( 1.0, m_y/m_yb, 0.0 ) },
            { QVector3D( m_xb, m_zb, m_y ), QVector3D( 1.0, m_y/m_yb, 1.0 ) },
            { QVector3D( 0.0,  m_zb, m_y ), QVector3D( 0.0, m_y/m_yb, 1.0 ) }
    };

    VertexData verticesSagittal[] =
    {
            { QVector3D( 0.0,  0.0,  m_x ), QVector3D( m_x/m_xb, 0.0, 0.0 ) },
            { QVector3D( m_yb, 0.0,  m_x ), QVector3D( m_x/m_xb, 1.0, 0.0 ) },
            { QVector3D( m_yb, m_zb, m_x ), QVector3D( m_x/m_xb, 1.0, 1.0 ) },
            { QVector3D( 0.0,  m_zb, m_x ), QVector3D( m_x/m_xb, 0.0, 1.0 ) }
    };

    GLushort indices[] = { 0, 1, 2, 0, 2, 3 };

    // Transfer index data to VBO 0
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, vboIds[ 0 ] );
    glBufferData( GL_ELEMENT_ARRAY_BUFFER, 6 * sizeof(GLushort), indices, GL_STATIC_DRAW );

    // Transfer vertex data to VBO 1
    glBindBuffer( GL_ARRAY_BUFFER, vboIds[ 1 ] );
    glBufferData( GL_ARRAY_BUFFER, 4 * sizeof(VertexData), verticesAxial, GL_STATIC_DRAW );

    // Transfer vertex data to VBO 2
    glBindBuffer( GL_ARRAY_BUFFER, vboIds[ 2 ] );
    glBufferData( GL_ARRAY_BUFFER, 4 * sizeof(VertexData), verticesCoronal, GL_STATIC_DRAW );

    // Transfer vertex data to VBO 3
    glBindBuffer( GL_ARRAY_BUFFER, vboIds[ 3 ] );
    glBufferData( GL_ARRAY_BUFFER, 4 * sizeof(VertexData), verticesSagittal, GL_STATIC_DRAW );

}

void NavRenderer::setupTextures()
{
    GLuint tex = m_dataStore->getFirstTexture();

    glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );

    int allocatedTextureCount = 0;

    glActiveTexture( GL_TEXTURE0 + allocatedTextureCount );
    glBindTexture( GL_TEXTURE_3D, tex );

    bool interpolation = false;
    if ( interpolation )
    {
        glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
        glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
    }
    else
    {
        glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
        glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
    }
}

void NavRenderer::setShaderVars()
{
    // Offset for position
    int offset = 0;

    // Tell OpenGL programmable pipeline how to locate vertex position data
    int vertexLocation = m_program->attributeLocation( "a_position" );
    m_program->enableAttributeArray( vertexLocation );
    glVertexAttribPointer( vertexLocation, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (const void *) offset );

    // Offset for texture coordinate
    offset += sizeof(QVector3D);

    // Tell OpenGL programmable pipeline how to locate vertex texture coordinate data
    int texcoordLocation = m_program->attributeLocation("a_texcoord");
    m_program->enableAttributeArray(texcoordLocation);
    glVertexAttribPointer(texcoordLocation, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (const void *)offset);
}

void NavRenderer::draw()
{
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    setupTextures();

    glColor4f( 0.0, 0.0, 0.0, 1.0 );

    // Set modelview-projection matrix
    m_program->setUniformValue( "mvp_matrix", m_mvpMatrix );

    initGeometry();

    if ( m_name == "axial" )
    {
        drawAxial();
    }
    else if ( m_name == "coronal" )
    {
        drawCoronal();
    }
    else
    {
        drawSagittal();
    }

    glDeleteBuffers( 1, &vboIds[0] );
    glDeleteBuffers( 1, &vboIds[1] );
    glDeleteBuffers( 1, &vboIds[2] );
    glDeleteBuffers( 1, &vboIds[3] );
}

void NavRenderer::drawAxial()
{
    // Tell OpenGL which VBOs to use
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, vboIds[ 0 ] );
    glBindBuffer( GL_ARRAY_BUFFER, vboIds[ 1 ] );
    setShaderVars();

    // Draw cube geometry using indices from VBO 0
    glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0 );
}

void NavRenderer::drawCoronal()
{
    // Tell OpenGL which VBOs to use
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, vboIds[ 0 ] );
    glBindBuffer( GL_ARRAY_BUFFER, vboIds[ 2 ] );
    setShaderVars();
    // Draw cube geometry using indices from VBO 0
    glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0 );
}

void NavRenderer::drawSagittal()
{
    // Tell OpenGL which VBOs to use
    glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, vboIds[ 0 ] );
    glBindBuffer( GL_ARRAY_BUFFER, vboIds[ 3 ] );
    setShaderVars();
    // Draw cube geometry using indices from VBO 0
    glDrawElements( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0 );
}

<|endoftext|>