<commit_before>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2012 Scientific Computing and Imaging Institute,
   University of Utah.

   License for the specific language governing rights and limitations under
   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/
/// @todo Documentation Dataflow/Engine/Controller/NetworkEditorController.cc

#include <iostream>
#include <boost/thread.hpp>
#include <boost/foreach.hpp>
#include <Dataflow/Engine/Controller/NetworkEditorController.h>

#include <Dataflow/Network/Connection.h>
#include <Dataflow/Network/Network.h>
#include <Dataflow/Network/ModuleDescription.h>
#include <Dataflow/Network/Module.h>
#include <Dataflow/Network/ModuleFactory.h>
#include <Dataflow/Serialization/Network/NetworkXMLSerializer.h>
#include <Dataflow/Serialization/Network/NetworkDescriptionSerialization.h>
#include <Dataflow/Engine/Controller/DynamicPortManager.h>
#include <Core/Logging/Log.h>

#ifdef BUILD_WITH_PYTHON
#include <Dataflow/Engine/Python/NetworkEditorPythonAPI.h>
#include <Dataflow/Engine/Controller/PythonImpl.h>
#endif

using namespace SCIRun;
using namespace SCIRun::Dataflow::Engine;
using namespace SCIRun::Dataflow::Networks;
using namespace SCIRun::Core::Algorithms;
using namespace SCIRun::Core::Logging;
using namespace SCIRun::Core;
using namespace SCIRun::Core::Thread;

NetworkEditorController::NetworkEditorController(ModuleFactoryHandle mf, ModuleStateFactoryHandle sf, ExecutionStrategyFactoryHandle executorFactory,
  AlgorithmFactoryHandle af, ReexecuteStrategyFactoryHandle reex, NetworkEditorSerializationManager* nesm) :
  theNetwork_(new Network(mf, sf, af, reex)),
  moduleFactory_(mf),
  stateFactory_(sf),
  algoFactory_(af),
  reexFactory_(reex),
  executorFactory_(executorFactory),
  serializationManager_(nesm),
  signalSwitch_(true)
{
  dynamicPortManager_.reset(new DynamicPortManager(connectionAdded_, connectionRemoved_, this));

  /// @todo should this class own the network or just keep a reference?

#ifdef BUILD_WITH_PYTHON
  NetworkEditorPythonAPI::setImpl(boost::make_shared<PythonImpl>(*this));
#endif
}

NetworkEditorController::NetworkEditorController(SCIRun::Dataflow::Networks::NetworkHandle network, ExecutionStrategyFactoryHandle executorFactory, NetworkEditorSerializationManager* nesm)
  : theNetwork_(network), executorFactory_(executorFactory), serializationManager_(nesm)
{
}

ModuleHandle NetworkEditorController::addModule(const std::string& name)
{
  return addModule(ModuleLookupInfo(name));
}

ModuleHandle NetworkEditorController::addModule(const ModuleLookupInfo& info)
{
  auto realModule = addModuleImpl(info.module_name_);
  if (signalSwitch_)
  {
    static ModuleCounter dummy;
    /*emit*/ moduleAdded_(info.module_name_, realModule, dummy);
  }
  printNetwork();
  return realModule;
}

ModuleHandle NetworkEditorController::addModuleImpl(const std::string& moduleName)
{
  /// @todo: should pass in entire info struct
  ModuleLookupInfo info;
  info.module_name_ = moduleName;
  ModuleHandle realModule = theNetwork_->add_module(info);
  if (realModule) /// @todo: mock network throws here due to null, need to have it return a mock module.
  {
    realModule->addPortConnection(connectPortAdded(boost::bind(&ModuleInterface::portAddedSlot, realModule.get(), _1, _2)));
    realModule->addPortConnection(connectPortRemoved(boost::bind(&ModuleInterface::portRemovedSlot, realModule.get(), _1, _2)));
  }
  return realModule;
}

void NetworkEditorController::removeModule(const ModuleId& id)
{
  //auto disableDynamicPortManager(createDynamicPortSwitch());
  theNetwork_->remove_module(id);
  //before or after?
  // deciding on after: ProvenanceWindow/Manager wants the state *after* removal.
  /*emit*/ moduleRemoved_(id);

  printNetwork();
}

ModuleHandle NetworkEditorController::duplicateModule(const ModuleHandle& module)
{
  //auto disableDynamicPortManager(createDynamicPortSwitch());
  ENSURE_NOT_NULL(module, "Cannot duplicate null module");
  ModuleId id(module->get_id());
  auto newModule = addModuleImpl(id.name_);
  newModule->set_state(module->get_state()->clone());
  static ModuleCounter dummy;
  moduleAdded_(id.name_, newModule, dummy);

  /// @todo: probably a pretty poor way to deal with what I think is a race condition with signaling the GUI to place the module widget.
  boost::this_thread::sleep(boost::posix_time::milliseconds(1));

  BOOST_FOREACH(InputPortHandle input, module->inputPorts())
  {
    if (input->nconnections() == 1)
    {
      auto conn = input->connection(0);
      auto source = conn->oport_;
      /// @todo: this will work if we define PortId.id# to be 0..n, unique for each module. But what about gaps?
      requestConnection(source.get(), newModule->getInputPort(input->id()).get());
    }
  }

  return newModule;
}

void NetworkEditorController::connectNewModule(const SCIRun::Dataflow::Networks::ModuleHandle& moduleToConnectTo, const SCIRun::Dataflow::Networks::PortDescriptionInterface* portToConnect, const std::string& newModuleName)
{
  auto newMod = addModule(newModuleName);

  /// @todo: see above
  boost::this_thread::sleep(boost::posix_time::milliseconds(1));

  /// @todo duplication
  if (portToConnect->isInput())
  {
    BOOST_FOREACH(OutputPortHandle p, newMod->outputPorts())
    {
      if (p->get_typename() == portToConnect->get_typename())
      {
        requestConnection(p.get(), portToConnect);
        return;
      }
    }
  }
  else
  {
    BOOST_FOREACH(InputPortHandle p, newMod->inputPorts())
    {
      if (p->get_typename() == portToConnect->get_typename())
      {
        requestConnection(p.get(), portToConnect);
        return;
      }
    }
  }
}

void NetworkEditorController::printNetwork() const
{
  /// @todo: and make this switchable
  if (false)
  {
    if (theNetwork_)
      LOG_DEBUG(theNetwork_->toString() << std::endl);
  }
}

void NetworkEditorController::requestConnection(const SCIRun::Dataflow::Networks::PortDescriptionInterface* from, const SCIRun::Dataflow::Networks::PortDescriptionInterface* to)
{
  ENSURE_NOT_NULL(from, "from port");
  ENSURE_NOT_NULL(to, "to port");

  auto out = from->isInput() ? to : from;
  auto in = from->isInput() ? from : to;

  ConnectionDescription desc(
    OutgoingConnectionDescription(out->getUnderlyingModuleId(), out->id()),
    IncomingConnectionDescription(in->getUnderlyingModuleId(), in->id()));

  PortConnectionDeterminer q;
  if (q.canBeConnected(*from, *to))
  {
    ConnectionId id = theNetwork_->connect(ConnectionOutputPort(theNetwork_->lookupModule(desc.out_.moduleId_), desc.out_.portId_),
      ConnectionInputPort(theNetwork_->lookupModule(desc.in_.moduleId_), desc.in_.portId_));
    if (!id.id_.empty())
      connectionAdded_(desc);

    printNetwork();
  }
  else
  {
    Log::get() << NOTICE << "Invalid Connection request: input port is full, or ports are different datatype or same i/o type, or on the same module." << std::endl;
    invalidConnection_(desc);
  }
}

void NetworkEditorController::removeConnection(const ConnectionId& id)
{
  if (theNetwork_->disconnect(id))
    connectionRemoved_(id);
  printNetwork();
}

boost::signals2::connection NetworkEditorController::connectModuleAdded(const ModuleAddedSignalType::slot_type& subscriber)
{
  return moduleAdded_.connect(subscriber);
}

boost::signals2::connection NetworkEditorController::connectModuleRemoved(const ModuleRemovedSignalType::slot_type& subscriber)
{
  return moduleRemoved_.connect(subscriber);
}

boost::signals2::connection NetworkEditorController::connectConnectionAdded(const ConnectionAddedSignalType::slot_type& subscriber)
{
  return connectionAdded_.connect(subscriber);
}

boost::signals2::connection NetworkEditorController::connectConnectionRemoved(const ConnectionRemovedSignalType::slot_type& subscriber)
{
  return connectionRemoved_.connect(subscriber);
}

boost::signals2::connection NetworkEditorController::connectInvalidConnection(const InvalidConnectionSignalType::slot_type& subscriber)
{
  return invalidConnection_.connect(subscriber);
}

boost::signals2::connection NetworkEditorController::connectNetworkExecutionStarts(const ExecuteAllStartsSignalType::slot_type& subscriber)
{
  return ExecutionContext::connectNetworkExecutionStarts(subscriber);
}

boost::signals2::connection NetworkEditorController::connectNetworkExecutionFinished(const ExecuteAllFinishesSignalType::slot_type& subscriber)
{
  return ExecutionContext::connectNetworkExecutionFinished(subscriber);
}

boost::signals2::connection NetworkEditorController::connectPortAdded(const PortAddedSignalType::slot_type& subscriber)
{
  return dynamicPortManager_->connectPortAdded(subscriber);
}

boost::signals2::connection NetworkEditorController::connectPortRemoved(const PortRemovedSignalType::slot_type& subscriber)
{
  return dynamicPortManager_->connectPortRemoved(subscriber);
}

boost::signals2::connection NetworkEditorController::connectNetworkDoneLoading(const NetworkDoneLoadingSignalType::slot_type& subscriber)
{
  return networkDoneLoading_.connect(subscriber);
}

NetworkFileHandle NetworkEditorController::saveNetwork() const
{
  NetworkToXML conv(serializationManager_);
  return conv.to_xml_data(theNetwork_);
}

void NetworkEditorController::loadNetwork(const NetworkFileHandle& xml)
{
  if (xml)
  {
    try
    {
      NetworkXMLConverter conv(moduleFactory_, stateFactory_, algoFactory_, reexFactory_, this);
      theNetwork_ = conv.from_xml_data(xml->network);
      ModuleCounter modulesDone;
      for (size_t i = 0; i < theNetwork_->nmodules(); ++i)
      {
        ModuleHandle module = theNetwork_->module(i);
        moduleAdded_(module->get_module_name(), module, modulesDone);
        networkDoneLoading_(i);
      }

      {
        auto disable(createDynamicPortSwitch());
        //this is handled by NetworkXMLConverter now--but now the logic is convoluted.
        //They need to be signaled again after the modules are signaled to alert the GUI. Hence the disabling of DPM
        BOOST_FOREACH(const ConnectionDescription& cd, theNetwork_->connections())
        {
          ConnectionId id = ConnectionId::create(cd);
          connectionAdded_(cd);
        }
      }
      if (serializationManager_)
      {
        serializationManager_->updateModulePositions(xml->modulePositions);
        serializationManager_->updateModuleNotes(xml->moduleNotes);
        serializationManager_->updateConnectionNotes(xml->connectionNotes);
      }
      else
        Log::get() << INFO <<  "module position editor unavailable, module positions at default" << std::endl;
      networkDoneLoading_(static_cast<int>(theNetwork_->nmodules()) + 1);
    }
    catch (ExceptionBase& e)
    {
      Log::get() << ERROR_LOG << "File load failed: exception while processing xml network data: " << e.what() << std::endl;
      theNetwork_->clear();
      throw;
    }
  }
}

void NetworkEditorController::clear()
{
  LOG_DEBUG("NetworkEditorController::clear()" << std::endl);
}

void NetworkEditorController::executeAll(const ExecutableLookup* lookup)
{
  if (!currentExecutor_)
  {
    currentExecutor_ = executorFactory_->createDefault();
  }

  ExecuteAllModules filter;
  theNetwork_->setModuleExecutionState(ModuleInterface::Waiting, filter);
  ExecutionContext context(*theNetwork_, lookup ? *lookup : *theNetwork_, filter);
  currentExecutor_->execute(context);
}

void NetworkEditorController::executeModule(const ModuleHandle& module, const ExecutableLookup* lookup)
{
  if (!currentExecutor_)
  {
    currentExecutor_ = executorFactory_->createDefault();
  }

  ExecuteSingleModule filter(module, *theNetwork_);
  theNetwork_->setModuleExecutionState(ModuleInterface::Waiting, filter);
  ExecutionContext context(*theNetwork_, lookup ? *lookup : *theNetwork_, filter);
  currentExecutor_->execute(context);
}

NetworkHandle NetworkEditorController::getNetwork() const
{
  return theNetwork_;
}

void NetworkEditorController::setNetwork(NetworkHandle nh)
{
  ENSURE_NOT_NULL(nh, "Null network.");
  theNetwork_ = nh;
}

NetworkGlobalSettings& NetworkEditorController::getSettings()
{
  return theNetwork_->settings();
}

void NetworkEditorController::setExecutorType(int type)
{
  currentExecutor_ = executorFactory_->create((ExecutionStrategy::Type)type);
}

const ModuleDescriptionMap& NetworkEditorController::getAllAvailableModuleDescriptions() const
{
  return moduleFactory_->getAllAvailableModuleDescriptions();
}

boost::shared_ptr<DisableDynamicPortSwitch> NetworkEditorController::createDynamicPortSwitch()
{
  return boost::make_shared<DisableDynamicPortSwitch>(dynamicPortManager_);
}

DisableDynamicPortSwitch::DisableDynamicPortSwitch(boost::shared_ptr<DynamicPortManager> dpm) : first_(true), dpm_(dpm)
{
  if (dpm_)
  {
    first_ = !dpm_->isDisabled();
    if (first_)
      dpm_->disable();
  }
}

DisableDynamicPortSwitch::~DisableDynamicPortSwitch()
{
  if (dpm_ && first_)
    dpm_->enable();
}

void NetworkEditorController::disableSignals()
{
  signalSwitch_ = false;
}

void NetworkEditorController::enableSignals()
{
  signalSwitch_ = true;
}
<commit_msg>Notes<commit_after>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2012 Scientific Computing and Imaging Institute,
   University of Utah.

   License for the specific language governing rights and limitations under
   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/
/// @todo Documentation Dataflow/Engine/Controller/NetworkEditorController.cc

#include <iostream>
#include <boost/thread.hpp>
#include <boost/foreach.hpp>
#include <Dataflow/Engine/Controller/NetworkEditorController.h>

#include <Dataflow/Network/Connection.h>
#include <Dataflow/Network/Network.h>
#include <Dataflow/Network/ModuleDescription.h>
#include <Dataflow/Network/Module.h>
#include <Dataflow/Network/ModuleFactory.h>
#include <Dataflow/Serialization/Network/NetworkXMLSerializer.h>
#include <Dataflow/Serialization/Network/NetworkDescriptionSerialization.h>
#include <Dataflow/Engine/Controller/DynamicPortManager.h>
#include <Core/Logging/Log.h>

#ifdef BUILD_WITH_PYTHON
#include <Dataflow/Engine/Python/NetworkEditorPythonAPI.h>
#include <Dataflow/Engine/Controller/PythonImpl.h>
#endif

using namespace SCIRun;
using namespace SCIRun::Dataflow::Engine;
using namespace SCIRun::Dataflow::Networks;
using namespace SCIRun::Core::Algorithms;
using namespace SCIRun::Core::Logging;
using namespace SCIRun::Core;
using namespace SCIRun::Core::Thread;

NetworkEditorController::NetworkEditorController(ModuleFactoryHandle mf, ModuleStateFactoryHandle sf, ExecutionStrategyFactoryHandle executorFactory,
  AlgorithmFactoryHandle af, ReexecuteStrategyFactoryHandle reex, NetworkEditorSerializationManager* nesm) :
  theNetwork_(new Network(mf, sf, af, reex)),
  moduleFactory_(mf),
  stateFactory_(sf),
  algoFactory_(af),
  reexFactory_(reex),
  executorFactory_(executorFactory),
  serializationManager_(nesm),
  signalSwitch_(true)
{
  dynamicPortManager_.reset(new DynamicPortManager(connectionAdded_, connectionRemoved_, this));

  /// @todo should this class own the network or just keep a reference?

#ifdef BUILD_WITH_PYTHON
  NetworkEditorPythonAPI::setImpl(boost::make_shared<PythonImpl>(*this));
#endif
}

NetworkEditorController::NetworkEditorController(SCIRun::Dataflow::Networks::NetworkHandle network, ExecutionStrategyFactoryHandle executorFactory, NetworkEditorSerializationManager* nesm)
  : theNetwork_(network), executorFactory_(executorFactory), serializationManager_(nesm)
{
}

ModuleHandle NetworkEditorController::addModule(const std::string& name)
{
  return addModule(ModuleLookupInfo(name));
}

ModuleHandle NetworkEditorController::addModule(const ModuleLookupInfo& info)
{
  auto realModule = addModuleImpl(info.module_name_);
  if (signalSwitch_)
  {
    static ModuleCounter dummy;
    /*emit*/ moduleAdded_(info.module_name_, realModule, dummy);
  }
  printNetwork();
  return realModule;
}

ModuleHandle NetworkEditorController::addModuleImpl(const std::string& moduleName)
{
  /// @todo: should pass in entire info struct
  ModuleLookupInfo info;
  info.module_name_ = moduleName;
  ModuleHandle realModule = theNetwork_->add_module(info);
  if (realModule) /// @todo: mock network throws here due to null, need to have it return a mock module.
  {
    realModule->addPortConnection(connectPortAdded(boost::bind(&ModuleInterface::portAddedSlot, realModule.get(), _1, _2)));
    realModule->addPortConnection(connectPortRemoved(boost::bind(&ModuleInterface::portRemovedSlot, realModule.get(), _1, _2)));
  }
  return realModule;
}

void NetworkEditorController::removeModule(const ModuleId& id)
{
  //auto disableDynamicPortManager(createDynamicPortSwitch());
  theNetwork_->remove_module(id);
  //before or after?
  // deciding on after: ProvenanceWindow/Manager wants the state *after* removal.
  /*emit*/ moduleRemoved_(id);

  printNetwork();
}

ModuleHandle NetworkEditorController::duplicateModule(const ModuleHandle& module)
{
  //auto disableDynamicPortManager(createDynamicPortSwitch());
  ENSURE_NOT_NULL(module, "Cannot duplicate null module");
  ModuleId id(module->get_id());
  auto newModule = addModuleImpl(id.name_);
  newModule->set_state(module->get_state()->clone());
  static ModuleCounter dummy;
  moduleAdded_(id.name_, newModule, dummy);

  /// @todo: probably a pretty poor way to deal with what I think is a race condition with signaling the GUI to place the module widget.
  boost::this_thread::sleep(boost::posix_time::milliseconds(1));

  BOOST_FOREACH(InputPortHandle input, module->inputPorts())
  {
    if (input->nconnections() == 1)
    {
      auto conn = input->connection(0);
      auto source = conn->oport_;
      /// @todo: this will work if we define PortId.id# to be 0..n, unique for each module. But what about gaps?
      requestConnection(source.get(), newModule->getInputPort(input->id()).get());
    }
  }

  return newModule;
}

void NetworkEditorController::connectNewModule(const SCIRun::Dataflow::Networks::ModuleHandle& moduleToConnectTo, const SCIRun::Dataflow::Networks::PortDescriptionInterface* portToConnect, const std::string& newModuleName)
{
  auto newMod = addModule(newModuleName);

  /// @todo: see above
  boost::this_thread::sleep(boost::posix_time::milliseconds(1));

  /// @todo duplication
  if (portToConnect->isInput())
  {
    BOOST_FOREACH(OutputPortHandle p, newMod->outputPorts())
    {
      if (p->get_typename() == portToConnect->get_typename())
      {
        requestConnection(p.get(), portToConnect);
        return;
      }
    }
  }
  else
  {
    BOOST_FOREACH(InputPortHandle p, newMod->inputPorts())
    {
      if (p->get_typename() == portToConnect->get_typename())
      {
        requestConnection(p.get(), portToConnect);
        return;
      }
    }
  }
}

void NetworkEditorController::printNetwork() const
{
  /// @todo: and make this switchable
  if (false)
  {
    if (theNetwork_)
      LOG_DEBUG(theNetwork_->toString() << std::endl);
  }
}

void NetworkEditorController::requestConnection(const SCIRun::Dataflow::Networks::PortDescriptionInterface* from, const SCIRun::Dataflow::Networks::PortDescriptionInterface* to)
{
  ENSURE_NOT_NULL(from, "from port");
  ENSURE_NOT_NULL(to, "to port");

  auto out = from->isInput() ? to : from;
  auto in = from->isInput() ? from : to;

  ConnectionDescription desc(
    OutgoingConnectionDescription(out->getUnderlyingModuleId(), out->id()),
    IncomingConnectionDescription(in->getUnderlyingModuleId(), in->id()));

  PortConnectionDeterminer q;
  if (q.canBeConnected(*from, *to))
  {
    ConnectionId id = theNetwork_->connect(ConnectionOutputPort(theNetwork_->lookupModule(desc.out_.moduleId_), desc.out_.portId_),
      ConnectionInputPort(theNetwork_->lookupModule(desc.in_.moduleId_), desc.in_.portId_));
    if (!id.id_.empty())
      connectionAdded_(desc);

    printNetwork();
  }
  else
  {
    Log::get() << NOTICE << "Invalid Connection request: input port is full, or ports are different datatype or same i/o type, or on the same module." << std::endl;
    invalidConnection_(desc);
  }
}

void NetworkEditorController::removeConnection(const ConnectionId& id)
{
  if (theNetwork_->disconnect(id))
    connectionRemoved_(id);
  printNetwork();
}

boost::signals2::connection NetworkEditorController::connectModuleAdded(const ModuleAddedSignalType::slot_type& subscriber)
{
  return moduleAdded_.connect(subscriber);
}

boost::signals2::connection NetworkEditorController::connectModuleRemoved(const ModuleRemovedSignalType::slot_type& subscriber)
{
  return moduleRemoved_.connect(subscriber);
}

boost::signals2::connection NetworkEditorController::connectConnectionAdded(const ConnectionAddedSignalType::slot_type& subscriber)
{
  return connectionAdded_.connect(subscriber);
}

boost::signals2::connection NetworkEditorController::connectConnectionRemoved(const ConnectionRemovedSignalType::slot_type& subscriber)
{
  return connectionRemoved_.connect(subscriber);
}

boost::signals2::connection NetworkEditorController::connectInvalidConnection(const InvalidConnectionSignalType::slot_type& subscriber)
{
  return invalidConnection_.connect(subscriber);
}

boost::signals2::connection NetworkEditorController::connectNetworkExecutionStarts(const ExecuteAllStartsSignalType::slot_type& subscriber)
{
  return ExecutionContext::connectNetworkExecutionStarts(subscriber);
}

boost::signals2::connection NetworkEditorController::connectNetworkExecutionFinished(const ExecuteAllFinishesSignalType::slot_type& subscriber)
{
  return ExecutionContext::connectNetworkExecutionFinished(subscriber);
}

boost::signals2::connection NetworkEditorController::connectPortAdded(const PortAddedSignalType::slot_type& subscriber)
{
  return dynamicPortManager_->connectPortAdded(subscriber);
}

boost::signals2::connection NetworkEditorController::connectPortRemoved(const PortRemovedSignalType::slot_type& subscriber)
{
  return dynamicPortManager_->connectPortRemoved(subscriber);
}

boost::signals2::connection NetworkEditorController::connectNetworkDoneLoading(const NetworkDoneLoadingSignalType::slot_type& subscriber)
{
  return networkDoneLoading_.connect(subscriber);
}

NetworkFileHandle NetworkEditorController::saveNetwork() const
{
  NetworkToXML conv(serializationManager_);
  return conv.to_xml_data(theNetwork_);
}

void NetworkEditorController::loadNetwork(const NetworkFileHandle& xml)
{
  if (xml)
  {
    try
    {
      NetworkXMLConverter conv(moduleFactory_, stateFactory_, algoFactory_, reexFactory_, this);
      theNetwork_ = conv.from_xml_data(xml->network);
      ModuleCounter modulesDone;
      for (size_t i = 0; i < theNetwork_->nmodules(); ++i)
      {
        ModuleHandle module = theNetwork_->module(i);
        moduleAdded_(module->get_module_name(), module, modulesDone);
        networkDoneLoading_(i);
      }

      {
        auto disable(createDynamicPortSwitch());
        //this is handled by NetworkXMLConverter now--but now the logic is convoluted.
        //They need to be signaled again after the modules are signaled to alert the GUI. Hence the disabling of DPM
        BOOST_FOREACH(const ConnectionDescription& cd, theNetwork_->connections())
        {
          ConnectionId id = ConnectionId::create(cd);
          connectionAdded_(cd);
        }
      }
      if (serializationManager_)
      {
        serializationManager_->updateModulePositions(xml->modulePositions);
        serializationManager_->updateModuleNotes(xml->moduleNotes);
        serializationManager_->updateConnectionNotes(xml->connectionNotes);
      }
      else
        Log::get() << INFO <<  "module position editor unavailable, module positions at default" << std::endl;
      networkDoneLoading_(static_cast<int>(theNetwork_->nmodules()) + 1);
    }
    catch (ExceptionBase& e)
    {
      Log::get() << ERROR_LOG << "File load failed: exception while processing xml network data: " << e.what() << std::endl;
      theNetwork_->clear();
      throw;
    }
  }
}

void NetworkEditorController::clear()
{
  LOG_DEBUG("NetworkEditorController::clear()" << std::endl);
}

// TODO:
// - [ ] refactor duplication
// - [ ] set up execution context queue
// - [ ] separate threads for looping through queue: another producer/consumer pair

void NetworkEditorController::executeAll(const ExecutableLookup* lookup)
{
  if (!currentExecutor_)
  {
    currentExecutor_ = executorFactory_->createDefault();
  }

  ExecuteAllModules filter;
  theNetwork_->setModuleExecutionState(ModuleInterface::Waiting, filter);
  ExecutionContext context(*theNetwork_, lookup ? *lookup : *theNetwork_, filter);
  currentExecutor_->execute(context);
}

void NetworkEditorController::executeModule(const ModuleHandle& module, const ExecutableLookup* lookup)
{
  if (!currentExecutor_)
  {
    currentExecutor_ = executorFactory_->createDefault();
  }

  ExecuteSingleModule filter(module, *theNetwork_);
  theNetwork_->setModuleExecutionState(ModuleInterface::Waiting, filter);
  ExecutionContext context(*theNetwork_, lookup ? *lookup : *theNetwork_, filter);
  currentExecutor_->execute(context);
}

NetworkHandle NetworkEditorController::getNetwork() const
{
  return theNetwork_;
}

void NetworkEditorController::setNetwork(NetworkHandle nh)
{
  ENSURE_NOT_NULL(nh, "Null network.");
  theNetwork_ = nh;
}

NetworkGlobalSettings& NetworkEditorController::getSettings()
{
  return theNetwork_->settings();
}

void NetworkEditorController::setExecutorType(int type)
{
  currentExecutor_ = executorFactory_->create((ExecutionStrategy::Type)type);
}

const ModuleDescriptionMap& NetworkEditorController::getAllAvailableModuleDescriptions() const
{
  return moduleFactory_->getAllAvailableModuleDescriptions();
}

boost::shared_ptr<DisableDynamicPortSwitch> NetworkEditorController::createDynamicPortSwitch()
{
  return boost::make_shared<DisableDynamicPortSwitch>(dynamicPortManager_);
}

DisableDynamicPortSwitch::DisableDynamicPortSwitch(boost::shared_ptr<DynamicPortManager> dpm) : first_(true), dpm_(dpm)
{
  if (dpm_)
  {
    first_ = !dpm_->isDisabled();
    if (first_)
      dpm_->disable();
  }
}

DisableDynamicPortSwitch::~DisableDynamicPortSwitch()
{
  if (dpm_ && first_)
    dpm_->enable();
}

void NetworkEditorController::disableSignals()
{
  signalSwitch_ = false;
}

void NetworkEditorController::enableSignals()
{
  signalSwitch_ = true;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2004-2010  See the AUTHORS file for details.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published
 * by the Free Software Foundation.
 */

#include "Modules.h"
#include "User.h"

class CPreventIdMsgMod : public CModule {
public:
	MODCONSTRUCTOR(CPreventIdMsgMod) {}

	/* Old style:
	 * -> CAPAB :identify-msg
	 * We just block this request from the client.
	 *
	 * New style:
	 * -> CAP LS
	 * <- :farmer.freenode.net CAP <nick> LS :identify-msg <other stuff>
	 * -> CAP REQ :identify-msg
	 * <- :farmer.freenode.net CAP a ACK :identify-msg
	 * We block the identify-msg token from CAP LS and CAP REQ,
	 * just to be sure.
	 */

	// Returns true if an "identify-msg" was skipped
	static bool MakeCleanCapList(CString& sList) {
		bool bRet = false;
		VCString vsList;
		sList.Split(" ", vsList);
		sList = "";

		// Append each token to the output list
		for (VCString::const_iterator it = vsList.begin();
				it != vsList.end(); ++it) {
			if (!it->Equals("identify-msg")) {
				sList += *it + " ";
			} else {
				bRet = true;
			}
		}

		// Remove the last space we added
		sList.RightChomp();

		return bRet;
	}

	virtual EModRet OnUserRaw(CString& sLine) {
		if (sLine.Token(0).Equals("CAPAB")) {
			if (sLine.AsLower().find("identify-msg") != CString::npos
					|| sLine.AsLower().find("identify-ctcp") != CString::npos)
				return HALTCORE;
		} else if (sLine.Token(0).Equals("CAP")) {
			if (sLine.Token(1).Equals("REQ")) {
				CString sList = sLine.Token(2, true).TrimPrefix_n(":");
				if (MakeCleanCapList(sList)) {
					// There was an identify-msg requested,
					// block the whole list
					PutUser(":irc.znc.in CAP " + m_pUser->GetIRCNick().GetNick()
							+ " NAK " + sLine.Token(2, true));
					return HALTCORE;
				}
			}
		}
		return CONTINUE;
	}

	virtual EModRet OnRaw(CString& sLine) {
		if (!sLine.Token(1).Equals("CAP"))
			return CONTINUE;
		if (!sLine.Token(3).Equals("LS"))
			return CONTINUE;

		// It's CAP LS, strip identify-msg

		// First, copy over the "prefix" from the old line
		CString sNewLine = sLine.Token(0) + " " + sLine.Token(1) + " ";
		sNewLine += sLine.Token(2) + " " + sLine.Token(3) + " :";

		// Grab the list of CAP tokens and clean them up
		CString sTokens = sLine.Token(4, true).TrimPrefix_n(":");
		MakeCleanCapList(sTokens);

		sLine = sNewLine + sTokens;
		return CONTINUE;
	}
};

MODULEDEFS(CPreventIdMsgMod, "Prevent client from sending IDENTIFY-MSG to server")
<commit_msg>Revert r2016<commit_after>/*
 * Copyright (C) 2004-2010  See the AUTHORS file for details.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published
 * by the Free Software Foundation.
 */

#include "Modules.h"

class CPreventIdMsgMod : public CModule {
public:
	MODCONSTRUCTOR(CPreventIdMsgMod) {}

	virtual EModRet OnUserRaw(CString& sLine) {
		if (sLine.Token(0).AsLower() == "capab") {
			if (sLine.AsLower().find("identify-msg") != CString::npos
					|| sLine.AsLower().find("identify-ctcp") != CString::npos)
				return HALTCORE;
		}
		return CONTINUE;
	}
};

MODULEDEFS(CPreventIdMsgMod, "Prevent client from sending IDENTIFY-MSG to server")
<|endoftext|>


<commit_before>// Copyright © 2018, Prosoft Engineering, Inc. (A.K.A "Prosoft")
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of Prosoft nor the names of its contributors may be
//       used to endorse or promote products derived from this software without
//       specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL PROSOFT ENGINEERING, INC. BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Currently, private to filesystem module for Mac only.

#include <filesystem/src/spawn.hpp>
#include <string/string_component.hpp>

#include "catch.hpp"

TEST_CASE("spawn") {
    using namespace prosoft;
    spawn_cout cout;
    spawn_cerr cerr;

    std::system_error err{1, std::system_category()};
    CHECK(err.code().value() == 1);
    prosoft::spawn("sw_vers", spawn_args{"-productName"}, cout, cerr, err);
    CHECK(err.code().value() == 0);
    CHECK(trim(cout) == "Mac OS X");
    CHECK(cerr.empty());

    err = std::system_error{1, std::system_category()};
    CHECK(err.code().value() == 1);
    prosoft::spawn("8F48A42AFE184DD1B0F43B9D95BC22E1", spawn_args{}, cout, cerr, err);
    CHECK(err.code().value() == ENOENT);
    CHECK(cout.empty());
    CHECK(cerr.find("8F48A42AFE184DD1B0F43B9D95BC22E1") != spawn_cerr::npos);

    err = std::system_error{1, std::system_category()};
    CHECK(err.code().value() == 1);
    prosoft::spawn("top", spawn_args{}, cout, cerr, std::chrono::seconds{1}, err);
    CHECK(err.code().value() == EAGAIN);
}
<commit_msg>spawn_tests: add macos_product_name value for macOS 11 Big Sur<commit_after>// Copyright © 2018, Prosoft Engineering, Inc. (A.K.A "Prosoft")
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of Prosoft nor the names of its contributors may be
//       used to endorse or promote products derived from this software without
//       specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL PROSOFT ENGINEERING, INC. BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Currently, private to filesystem module for Mac only.

#include <filesystem/src/spawn.hpp>
#include <string/string_component.hpp>

#include "catch.hpp"

TEST_CASE("spawn") {
    using namespace prosoft;
    spawn_cout cout;
    spawn_cerr cerr;

    std::system_error err{1, std::system_category()};
    CHECK(err.code().value() == 1);
    prosoft::spawn("sw_vers", spawn_args{"-productName"}, cout, cerr, err);
    CHECK(err.code().value() == 0);
    const auto macos_product_name = trim(cout);
    CHECK((macos_product_name == "macOS"        // macOS 11 Big Sur
            || macos_product_name == "Mac OS X"));
    CHECK(cerr.empty());

    err = std::system_error{1, std::system_category()};
    CHECK(err.code().value() == 1);
    prosoft::spawn("8F48A42AFE184DD1B0F43B9D95BC22E1", spawn_args{}, cout, cerr, err);
    CHECK(err.code().value() == ENOENT);
    CHECK(cout.empty());
    CHECK(cerr.find("8F48A42AFE184DD1B0F43B9D95BC22E1") != spawn_cerr::npos);

    err = std::system_error{1, std::system_category()};
    CHECK(err.code().value() == 1);
    prosoft::spawn("top", spawn_args{}, cout, cerr, std::chrono::seconds{1}, err);
    CHECK(err.code().value() == EAGAIN);
}
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2010, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "IECoreMaya/ParameterisedHolderManipContextCommand.h"

#include "IECoreMaya/ParameterisedHolderManipContext.h"

#include <maya/MArgParser.h>

using namespace IECoreMaya;

ParameterisedHolderManipContextCommand::ParameterisedHolderManipContextCommand()
{
}

void *ParameterisedHolderManipContextCommand::creator()
{
	return new ParameterisedHolderManipContextCommand;
}

MPxContext *ParameterisedHolderManipContextCommand::makeObj()
{
	m_context = new ParameterisedHolderManipContext;
	return m_context;
}

MStatus ParameterisedHolderManipContextCommand::doEditFlags()
{
	 MStatus stat;

	 MArgParser args = parser();

	 if( args.isFlagSet( kModeFlag ) )
	 {
	 	MString mode;
		stat = args.getFlagArgument( kModeFlag, 0, mode );
		if( !stat )
		{
			stat.perror( "Invalid argument passed to "kModeFlagLong" flag. Valid options are: 'all', 'first' or 'targeted'." );
			return stat;
		}
		if( mode == "all" )
		{
			m_context->setMode( ParameterisedHolderManipContext::All );
		}
		else if( mode == "first" )
		{
			m_context->setMode( ParameterisedHolderManipContext::First );
		}
		else if( mode == "targeted" )
		{
			m_context->setMode( ParameterisedHolderManipContext::Targeted );
		}
		else
		{
			stat.perror( "Unknkown mode passed to "kModeFlagLong" flag. Valid options are: 'all', 'first' or 'targeted'." );
			return stat;
		}
	 }

	 if( args.isFlagSet( kTargetFlag ) )
	 {
	 	MString param;
		stat = args.getFlagArgument( kTargetFlag, 0, param );
		if( !stat )
		{
			stat.perror( "Invalid argument passed to "kTargetFlagLong" flag." );
			return stat;
		}
		m_context->setTarget( param );
	 }

	 return MS::kSuccess;
}

MStatus ParameterisedHolderManipContextCommand::doQueryFlags()
{
	MArgParser args = parser();

	if( args.isFlagSet( kModeFlag ) )
	{
		ParameterisedHolderManipContext::Mode m = m_context->getMode();
		switch( m )
		{
			case ParameterisedHolderManipContext::All:
				setResult( MString( "all" ) );
				break;

			case ParameterisedHolderManipContext::First:
				setResult( MString( "first" ) );
				break;

			case ParameterisedHolderManipContext::Targeted:
				setResult( MString( "targeted" ) );
				break;

			default:
				setResult( MString( "unknown" ) );
		}
	}

	if( args.isFlagSet( kTargetFlag ) )
	{
		setResult( m_context->getTarget() );
	}

	return MS::kSuccess;
}

MStatus ParameterisedHolderManipContextCommand::appendSyntax()
{
	MStatus stat;

	MSyntax mySyntax = syntax();

	stat = mySyntax.addFlag( kModeFlag, kModeFlagLong, MSyntax::kString );
	if ( !stat )
	{
		return MS::kFailure;
	}

	stat = mySyntax.addFlag( kTargetFlag, kTargetFlagLong, MSyntax::kString );
	if ( !stat )
	{
		return MS::kFailure;
	}

	return MS::kSuccess;
}

<commit_msg>IECoreMaya : Fix for c++11<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2010, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "IECoreMaya/ParameterisedHolderManipContextCommand.h"

#include "IECoreMaya/ParameterisedHolderManipContext.h"

#include <maya/MArgParser.h>

using namespace IECoreMaya;

ParameterisedHolderManipContextCommand::ParameterisedHolderManipContextCommand()
{
}

void *ParameterisedHolderManipContextCommand::creator()
{
	return new ParameterisedHolderManipContextCommand;
}

MPxContext *ParameterisedHolderManipContextCommand::makeObj()
{
	m_context = new ParameterisedHolderManipContext;
	return m_context;
}

MStatus ParameterisedHolderManipContextCommand::doEditFlags()
{
	 MStatus stat;

	 MArgParser args = parser();

	 if( args.isFlagSet( kModeFlag ) )
	 {
	 	MString mode;
		stat = args.getFlagArgument( kModeFlag, 0, mode );
		if( !stat )
		{
			stat.perror( "Invalid argument passed to " kModeFlagLong " flag. Valid options are: 'all', 'first' or 'targeted'." );
			return stat;
		}
		if( mode == "all" )
		{
			m_context->setMode( ParameterisedHolderManipContext::All );
		}
		else if( mode == "first" )
		{
			m_context->setMode( ParameterisedHolderManipContext::First );
		}
		else if( mode == "targeted" )
		{
			m_context->setMode( ParameterisedHolderManipContext::Targeted );
		}
		else
		{
			stat.perror( "Unknkown mode passed to " kModeFlagLong " flag. Valid options are: 'all', 'first' or 'targeted'." );
			return stat;
		}
	 }

	 if( args.isFlagSet( kTargetFlag ) )
	 {
	 	MString param;
		stat = args.getFlagArgument( kTargetFlag, 0, param );
		if( !stat )
		{
			stat.perror( "Invalid argument passed to " kTargetFlagLong " flag." );
			return stat;
		}
		m_context->setTarget( param );
	 }

	 return MS::kSuccess;
}

MStatus ParameterisedHolderManipContextCommand::doQueryFlags()
{
	MArgParser args = parser();

	if( args.isFlagSet( kModeFlag ) )
	{
		ParameterisedHolderManipContext::Mode m = m_context->getMode();
		switch( m )
		{
			case ParameterisedHolderManipContext::All:
				setResult( MString( "all" ) );
				break;

			case ParameterisedHolderManipContext::First:
				setResult( MString( "first" ) );
				break;

			case ParameterisedHolderManipContext::Targeted:
				setResult( MString( "targeted" ) );
				break;

			default:
				setResult( MString( "unknown" ) );
		}
	}

	if( args.isFlagSet( kTargetFlag ) )
	{
		setResult( m_context->getTarget() );
	}

	return MS::kSuccess;
}

MStatus ParameterisedHolderManipContextCommand::appendSyntax()
{
	MStatus stat;

	MSyntax mySyntax = syntax();

	stat = mySyntax.addFlag( kModeFlag, kModeFlagLong, MSyntax::kString );
	if ( !stat )
	{
		return MS::kFailure;
	}

	stat = mySyntax.addFlag( kTargetFlag, kTargetFlagLong, MSyntax::kString );
	if ( !stat )
	{
		return MS::kFailure;
	}

	return MS::kSuccess;
}

<|endoftext|>


<commit_before>// BLETest.cpp : Defines the entry point for the console application.
//

#include "ble_util.h"
#include "fido_apduresponses.h"

#include "U2FTests.h"
#include "BLETransportTests.h"

#include "../BleApi/BleApi.h"
#include "../BleApi/fido_ble.h"

int arg_Verbose = 0;		// default
bool arg_hasButton = false;
bool arg_preapproval = false;
bool arg_u2f = true;
bool arg_transport = true;
bool arg_iso7816 = false;
bool arg_encryption = true;

#define REPLY_BUFFER_LENGTH 256
static unsigned char reply[REPLY_BUFFER_LENGTH];
static unsigned int replyLength = REPLY_BUFFER_LENGTH;

void BleApiTestEventHandler(BleDevice::FIDOEventType type,
			    unsigned char *buffer, unsigned int bufferLength)
{
	if (type != BleDevice::EVENT_FRAGMENT)
		return;

	BleApiTest_TransportEventHandler(type, buffer, bufferLength);
}

ReturnValue GetBleInterfaceVersion(pBleDevice dev)
{
	ReturnValue retval;

	unsigned char version[128];
	unsigned int len = sizeof(version);

	/* read version */
	retval = dev->U2FVersionRead(version, &len);
	if (retval != BLEAPI_ERROR_SUCCESS)
		return retval;

	/* verify version */
	CHECK_EQ(memcmp(version, "1.0", 3), 0);

	INFO << "U2F BLE Version: " << version;

	return BLEAPI_ERROR_SUCCESS;
}

static
void pause(const std::string & prompt)
{
	printf("\n%s", prompt.c_str());
	getchar();
	printf("\n");
}

void WaitForUserPresence(pBleDevice dev, bool hasButton)
{
	ReturnValue retval;

	pause(std::string(hasButton ? "Touch" : "Turn on") +
	      " device and hit enter..");

	/* check for U2F Interface version */
	retval = GetBleInterfaceVersion(dev);
	if (retval != BLEAPI_ERROR_SUCCESS)
		abort();

	/* register for notification to receive data */
	retval = dev->RegisterNotifications(BleApiTestEventHandler);
	if (retval != BLEAPI_ERROR_SUCCESS)
		abort();
}

ReturnValue BLETransportTests(pBleDevice dev)
{
	std::cout << std::endl << "==== BLE Transport tests ====" << std::endl;

	WaitForUserPresence(dev, arg_hasButton);

	// set timeout at 30 seconds, just in case devices just doesn't answer.
	dev->SetTimeout(30000);

	PASS(BleApiTest_TransportPing(dev));
	PASS(BleApiTest_TransportLongPing(dev));
	PASS(BleApiTest_TransportLimits(dev));
	PASS(BleApiTest_TransportUnknown
	     (dev, (4 + (rand() % (TYPE_INIT - 0x04)))));
	PASS(BleApiTest_TransportNotCont(dev));
	PASS(BleApiTest_TransportBadSequence(dev));
	PASS(BleApiTest_TransportContFirst(dev));
	PASS(BleApiTest_TransportTooLong(dev));

	return BLEAPI_ERROR_SUCCESS;
}

ReturnValue U2FISO7816EncodingTests(pBleDevice dev)
{
	std::
	    cout << std::endl << "==== BLE ISO7816-4 Encoding tests ====" <<
	    std::endl;
	WaitForUserPresence(dev, arg_hasButton);

	PASS(BleApiTest_TestEncodingLongAnyLength(dev));
	PASS(BleApiTest_TestEncodingLongExactLength(dev));
	PASS(BleApiTest_TestEncodingLongWrongLength(dev));

	// must do enroll before long data tests because it uses
	//   Sign command.
	BleApiTest_Enroll(dev);

	WaitForUserPresence(dev, arg_hasButton);
	PASS(BleApiTest_TestEncodingLongDataAnyLength(dev));

	WaitForUserPresence(dev, arg_hasButton);
	PASS(BleApiTest_TestEncodingLongDataExactLength(dev));

	WaitForUserPresence(dev, arg_hasButton);
	PASS(BleApiTest_TestEncodingLongDataWrongLength(dev));

	return BLEAPI_ERROR_SUCCESS;
}

ReturnValue U2FTests(pBleDevice dev)
{
	std::cout << std::
	    endl << "==== U2F Raw Message tests ====" << std::endl;
	WaitForUserPresence(dev, arg_hasButton);

	PASS(BleApiTest_GetU2FProtocolVersion(dev));
	PASS(BleApiTest_UnknownINS(dev));
	PASS(BleApiTest_BadCLA(dev));
	PASS(BleApiTest_VersionWrongLength(dev));
	PASS(BleApiTest_RegisterWrongLength(dev));

	if (arg_hasButton && !arg_preapproval)
		PASS(BleApiTest_Enroll(dev, FIDO_RESP_USERPRESENCE_REQUIRED));

	PASS(BleApiTest_Enroll(dev));

	WaitForUserPresence(dev, arg_hasButton);

	// fob with button but without pre-approval should need approval.
	if (arg_hasButton && !arg_preapproval)
		PASS(BleApiTest_Sign(dev, FIDO_RESP_USERPRESENCE_REQUIRED));

	// Sign with check only should not produce signature.
	if (!arg_preapproval)
		PASS(BleApiTest_Sign
		     (dev, FIDO_RESP_USERPRESENCE_REQUIRED, true));

	// Sign with wrong kh.
	PASS(BleApiTest_Sign(dev, FIDO_RESP_WRONG_DATA, false, true, false));

	// Sign with wrong AppID.
	PASS(BleApiTest_Sign(dev, FIDO_RESP_WRONG_DATA, false, false, true));

	if (!arg_preapproval)
		WaitForUserPresence(dev, arg_hasButton);

	// Sign with check only should not produce signature.
	PASS(BleApiTest_Sign(dev, FIDO_RESP_USERPRESENCE_REQUIRED, true));

	uint32_t ctr1;
	PASS(ctr1 = BleApiTest_Sign(dev));
	if (!arg_preapproval)
		PASS(BleApiTest_Sign(dev, FIDO_RESP_USERPRESENCE_REQUIRED));

	WaitForUserPresence(dev, arg_hasButton);

	uint32_t ctr2;
	PASS(ctr2 = BleApiTest_Sign(dev));

	// Ctr should have incremented by 1.
	PASS(ctr2 == (ctr1 + 1));

	return BLEAPI_ERROR_SUCCESS;
}

void Usage(char *name)
{
	std::cerr << "Usage: " << name << std::endl
	    <<
	    " [ -d <device-identifier>] [-l] [-h] [-a] [-v] [-V] [-p] [-e] [-u] [-t] [-w] [-i]"
	    << std::endl
	    << "  -h : this text." << std::endl
	    << "  -a : Do not abort on failed test." << std::endl
	    << "  -v : Verbose" << std::endl
	    << "  -V : Rven more verbose" << std::endl
	    << "  -p : Pause at failed test" << std::endl
	    << "  -e : Device does preapproval when turned on" << std::endl
	    << "  -u : Disable U2F Raw Message tests. " << std::endl
	    << "  -t : Disable BLE Transport tests." << std::endl
	    << "  -i : Enable U2F ISO7816-4 encoding tests." << std::endl
	    << "  -w : Warnings are treated as errors." << std::endl
	    << "  -x : Disable encrypted connection requirement." << std::endl
	    << "  -c : Toggle ANSI colors." << std::endl
	    << "  -l : Show all known FIDO BLE devices and exit." << std::endl
	    << "  -d : Select specific FIDO BLE device." << std::endl;
	exit(-1);
}

int __cdecl main(int argc, char *argv[])
{
	int count = 1;
	pBleDevice dev = NULL;
	bool arg_ShowDevices = false;
	char *arg_DeviceIdentifier = NULL;

	while (count < argc) {
		if (!strncmp(argv[count], "-v", 2)) {
			// INFO only
			arg_Verbose |= 1;
		}
		if (!strncmp(argv[count], "-V", 2)) {
			// INFO only
			arg_Verbose |= 2;
		}
		if (!strncmp(argv[count], "-a", 2)) {
			// Don't abort, try continue;
			arg_Abort = false;
		}
		if (!strncmp(argv[count], "-p", 2)) {
			// Pause at abort
			arg_Pause = true;
		}
		if (!strncmp(argv[count], "-h", 2)) {
			Usage(argv[0]);
		}
		if (!strncmp(argv[count], "-b", 2)) {
			// Fob does not have button
			arg_hasButton = false;
		}
		if (!strncmp(argv[count], "-e", 2)) {
			// fob uses pre-approval
			arg_preapproval = true;
		}
		if (!strncmp(argv[count], "-u", 2)) {
			// skip u2f tests
			arg_u2f = false;
		}
		if (!strncmp(argv[count], "-t", 2)) {
			// skip ble tests
			arg_transport = false;
		}
		if (!strncmp(argv[count], "-i", 2)) {
			// skip iso7816 tests
			arg_iso7816 = true;
		}
		if (!strncmp(argv[count], "-w", 2)) {
			// treat warnings as errors
			arg_LethalWarn = false;
		}
		if (!strncmp(argv[count], "-l", 2)) {
			// treat warnings as errors
			arg_ShowDevices = true;
		}
		if (!strncmp(argv[count], "-d", 2)) {
			// treat warnings as errors
			++count;
			if (count == argc) {
				std::cerr << "Argument required for -d." <<
				    std::endl;
				Usage(argv[0]);
			}
			arg_DeviceIdentifier = argv[count];
		}
		if (!strncmp(argv[count], "-x", 2)) {
			arg_encryption = false;
			std::cout << "BLE connection encryption disabled." <<
			    std::endl;
		}
		if (!strncmp(argv[count], "-c", 2)) {
			arg_ansi = !arg_ansi;
		}
		++count;
	}

	try {
		pBleApi api = BleApi::CreateAPI(arg_encryption);

		/* find U2F Devices */
		std::vector < pBleDevice > devices = api->findDevices();

		/* no devices found */
		if (!devices.size())
			return -1;

		/* show all valid devices? */
		if (arg_ShowDevices) {
			std::vector < pBleDevice >::iterator i;

			std::cout << "All valid FIDO BLE devices:" << std::endl;
			for (i = devices.begin(); i != devices.end(); i++) {
				std::cout << "  " << (*i)->
				    Identifier() << std::endl;
			}
			exit(0);
		}

		/* select a specific device ? */
		if (arg_DeviceIdentifier) {
			std::string id(arg_DeviceIdentifier);
			std::vector < pBleDevice >::iterator i;

			for (i = devices.begin(); i != devices.end(); i++) {
				if (((*i)->Identifier() == id)
				    && ((*i)->Identifier().length() ==
					id.length()))
					dev = (*i);
			}
		} else {
			/* grab the first device */
			dev = devices[0];
		}

		/* verify device is valid. */
		if (!dev) {
			std::cout << "No valid device found.\n" << std::endl;
			exit(-1);
		} else {
			std::cout << "Running tests on device " <<
			    dev->Identifier() << std::endl;
		}

		/* something to do? */
		if (!(arg_transport || arg_u2f || arg_iso7816)) {
			std::cout << "Nothing to do." << std::endl;
			return 0;
		}

		/* check that link encryption is enabled */
		WARN_EQ(arg_encryption, true);

		/* do ble transport tests */
		if (arg_transport) {
			if (BLETransportTests(dev) != BLEAPI_ERROR_SUCCESS)
				return -1;
		}

		/* do the u2f tests */
		if (arg_u2f) {
			if (U2FTests(dev) != BLEAPI_ERROR_SUCCESS)
				return -1;
		}
		/* do the iso7816-4 tests */
		if (arg_iso7816) {
			if (U2FISO7816EncodingTests(dev) !=
			    BLEAPI_ERROR_SUCCESS)
				return -1;

		}
	}
	catch(std::exception e) {
		std::cout << "ERROR: " << e.what() << std::endl;

		return -1;
	}

	std::cout << std::endl << "==== Test completed. ====" << std::endl;

	return 0;
}
<commit_msg>Update BLETest.cpp<commit_after>// BLETest.cpp : Defines the entry point for the console application.
//

#include "ble_util.h"
#include "fido_apduresponses.h"

#include "U2FTests.h"
#include "BLETransportTests.h"

#include "../BleApi/BleApi.h"
#include "../BleApi/fido_ble.h"

int arg_Verbose = 0;		// default
bool arg_hasButton = false;
bool arg_preapproval = false;
bool arg_u2f = true;
bool arg_transport = true;
bool arg_iso7816 = false;
bool arg_encryption = true;

#define REPLY_BUFFER_LENGTH 256
static unsigned char reply[REPLY_BUFFER_LENGTH];
static unsigned int replyLength = REPLY_BUFFER_LENGTH;

void BleApiTestEventHandler(BleDevice::FIDOEventType type,
			    unsigned char *buffer, unsigned int bufferLength)
{
	if (type != BleDevice::EVENT_FRAGMENT)
		return;

	BleApiTest_TransportEventHandler(type, buffer, bufferLength);
}

ReturnValue GetBleInterfaceVersion(pBleDevice dev)
{
	ReturnValue retval;

	unsigned char version[128];
	unsigned int len = sizeof(version);

	/* read version */
	retval = dev->U2FVersionRead(version, &len);
	if (retval != BLEAPI_ERROR_SUCCESS)
		return retval;

	/* verify version */
	CHECK_EQ(memcmp(version, "1.0", 3), 0);

	INFO << "U2F BLE Version: " << version;

	return BLEAPI_ERROR_SUCCESS;
}

static
void pause(const std::string & prompt)
{
	printf("\n%s", prompt.c_str());
	getchar();
	printf("\n");
}

void WaitForUserPresence(pBleDevice dev, bool hasButton)
{
	ReturnValue retval;

	pause(std::string(hasButton ? "Touch" : "Turn on") +
	      " device and hit enter..");

	/* check for U2F Interface version */
	retval = GetBleInterfaceVersion(dev);
	if (retval != BLEAPI_ERROR_SUCCESS)
		abort();

	/* register for notification to receive data */
	retval = dev->RegisterNotifications(BleApiTestEventHandler);
	if (retval != BLEAPI_ERROR_SUCCESS)
		abort();
}

ReturnValue BLETransportTests(pBleDevice dev)
{
	std::cout << std::endl << "==== BLE Transport tests ====" << std::endl;

	WaitForUserPresence(dev, arg_hasButton);

	// set timeout at 30 seconds, just in case devices just doesn't answer.
	dev->SetTimeout(30000);

	PASS(BleApiTest_TransportPing(dev));
	PASS(BleApiTest_TransportLongPing(dev));
	PASS(BleApiTest_TransportLimits(dev));
	PASS(BleApiTest_TransportUnknown
	     (dev, (4 + (rand() % (TYPE_INIT - 0x04)))));
	PASS(BleApiTest_TransportNotCont(dev));
	PASS(BleApiTest_TransportBadSequence(dev));
	PASS(BleApiTest_TransportContFirst(dev));
	PASS(BleApiTest_TransportTooLong(dev));

	return BLEAPI_ERROR_SUCCESS;
}

ReturnValue U2FISO7816EncodingTests(pBleDevice dev)
{
	std::
	    cout << std::endl << "==== BLE ISO7816-4 Encoding tests ====" <<
	    std::endl;
	WaitForUserPresence(dev, arg_hasButton);

	PASS(BleApiTest_TestEncodingLongAnyLength(dev));
	PASS(BleApiTest_TestEncodingLongExactLength(dev));
	PASS(BleApiTest_TestEncodingLongWrongLength(dev));

	// must do enroll before long data tests because it uses
	//   Sign command.
	BleApiTest_Enroll(dev);

	WaitForUserPresence(dev, arg_hasButton);
	PASS(BleApiTest_TestEncodingLongDataAnyLength(dev));

	WaitForUserPresence(dev, arg_hasButton);
	PASS(BleApiTest_TestEncodingLongDataExactLength(dev));

	WaitForUserPresence(dev, arg_hasButton);
	PASS(BleApiTest_TestEncodingLongDataWrongLength(dev));

	return BLEAPI_ERROR_SUCCESS;
}

ReturnValue U2FTests(pBleDevice dev)
{
	std::cout << std::
	    endl << "==== U2F Raw Message tests ====" << std::endl;
	WaitForUserPresence(dev, arg_hasButton);

	PASS(BleApiTest_GetU2FProtocolVersion(dev));
	PASS(BleApiTest_UnknownINS(dev));
	PASS(BleApiTest_BadCLA(dev));
	PASS(BleApiTest_VersionWrongLength(dev));
	PASS(BleApiTest_RegisterWrongLength(dev));

	if (arg_hasButton && !arg_preapproval)
		PASS(BleApiTest_Enroll(dev, FIDO_RESP_USERPRESENCE_REQUIRED));

	PASS(BleApiTest_Enroll(dev));

	WaitForUserPresence(dev, arg_hasButton);

	// fob with button but without pre-approval should need approval.
	if (arg_hasButton && !arg_preapproval)
		PASS(BleApiTest_Sign(dev, FIDO_RESP_USERPRESENCE_REQUIRED));

	// Sign with check only should not produce signature.
	if (!arg_preapproval)
		PASS(BleApiTest_Sign
		     (dev, FIDO_RESP_USERPRESENCE_REQUIRED, true));

	// Sign with wrong kh.
	PASS(BleApiTest_Sign(dev, FIDO_RESP_WRONG_DATA, false, true, false));

	// Sign with wrong AppID.
	PASS(BleApiTest_Sign(dev, FIDO_RESP_WRONG_DATA, false, false, true));

	if (!arg_preapproval)
		WaitForUserPresence(dev, arg_hasButton);

	// Sign with check only should not produce signature.
	PASS(BleApiTest_Sign(dev, FIDO_RESP_USERPRESENCE_REQUIRED, true));

	uint32_t ctr1;
	PASS(ctr1 = BleApiTest_Sign(dev));
	if (!arg_preapproval)
		PASS(BleApiTest_Sign(dev, FIDO_RESP_USERPRESENCE_REQUIRED));

	WaitForUserPresence(dev, arg_hasButton);

	uint32_t ctr2;
	PASS(ctr2 = BleApiTest_Sign(dev));

	// Ctr should have incremented by 1.
	PASS(ctr2 == (ctr1 + 1));

	return BLEAPI_ERROR_SUCCESS;
}

void Usage(char *name)
{
	std::cerr << "Usage: " << name << std::endl
	    <<
	    " [ -d <device-identifier>] [-l] [-h] [-a] [-v] [-V] [-p] [-e] [-u] [-t] [-w] [-i]"
	    << std::endl
	    << "  -h : this text." << std::endl
	    << "  -a : Do not abort on failed test." << std::endl
	    << "  -v : Verbose" << std::endl
	    << "  -V : Even more verbose" << std::endl
	    << "  -p : Pause at failed test" << std::endl
	    << "  -e : Device does preapproval when turned on" << std::endl
	    << "  -u : Disable U2F Raw Message tests. " << std::endl
	    << "  -t : Disable BLE Transport tests." << std::endl
	    << "  -i : Enable U2F ISO7816-4 encoding tests." << std::endl
	    << "  -w : Warnings are treated as errors." << std::endl
	    << "  -x : Disable encrypted connection requirement." << std::endl
	    << "  -c : Toggle ANSI colors." << std::endl
	    << "  -l : Show all known FIDO BLE devices and exit." << std::endl
	    << "  -d : Select specific FIDO BLE device." << std::endl;
	exit(-1);
}

int __cdecl main(int argc, char *argv[])
{
	int count = 1;
	pBleDevice dev = NULL;
	bool arg_ShowDevices = false;
	char *arg_DeviceIdentifier = NULL;

	while (count < argc) {
		if (!strncmp(argv[count], "-v", 2)) {
			// INFO only
			arg_Verbose |= 1;
		}
		if (!strncmp(argv[count], "-V", 2)) {
			// INFO only
			arg_Verbose |= 2;
		}
		if (!strncmp(argv[count], "-a", 2)) {
			// Don't abort, try continue;
			arg_Abort = false;
		}
		if (!strncmp(argv[count], "-p", 2)) {
			// Pause at abort
			arg_Pause = true;
		}
		if (!strncmp(argv[count], "-h", 2)) {
			Usage(argv[0]);
		}
		if (!strncmp(argv[count], "-b", 2)) {
			// Fob does not have button
			arg_hasButton = false;
		}
		if (!strncmp(argv[count], "-e", 2)) {
			// fob uses pre-approval
			arg_preapproval = true;
		}
		if (!strncmp(argv[count], "-u", 2)) {
			// skip u2f tests
			arg_u2f = false;
		}
		if (!strncmp(argv[count], "-t", 2)) {
			// skip ble tests
			arg_transport = false;
		}
		if (!strncmp(argv[count], "-i", 2)) {
			// skip iso7816 tests
			arg_iso7816 = true;
		}
		if (!strncmp(argv[count], "-w", 2)) {
			// treat warnings as errors
			arg_LethalWarn = false;
		}
		if (!strncmp(argv[count], "-l", 2)) {
			// treat warnings as errors
			arg_ShowDevices = true;
		}
		if (!strncmp(argv[count], "-d", 2)) {
			// treat warnings as errors
			++count;
			if (count == argc) {
				std::cerr << "Argument required for -d." <<
				    std::endl;
				Usage(argv[0]);
			}
			arg_DeviceIdentifier = argv[count];
		}
		if (!strncmp(argv[count], "-x", 2)) {
			arg_encryption = false;
			std::cout << "BLE connection encryption disabled." <<
			    std::endl;
		}
		if (!strncmp(argv[count], "-c", 2)) {
			arg_ansi = !arg_ansi;
		}
		++count;
	}

	try {
		pBleApi api = BleApi::CreateAPI(arg_encryption);

		/* find U2F Devices */
		std::vector < pBleDevice > devices = api->findDevices();

		/* no devices found */
		if (!devices.size())
			return -1;

		/* show all valid devices? */
		if (arg_ShowDevices) {
			std::vector < pBleDevice >::iterator i;

			std::cout << "All valid FIDO BLE devices:" << std::endl;
			for (i = devices.begin(); i != devices.end(); i++) {
				std::cout << "  " << (*i)->
				    Identifier() << std::endl;
			}
			exit(0);
		}

		/* select a specific device ? */
		if (arg_DeviceIdentifier) {
			std::string id(arg_DeviceIdentifier);
			std::vector < pBleDevice >::iterator i;

			for (i = devices.begin(); i != devices.end(); i++) {
				if (((*i)->Identifier() == id)
				    && ((*i)->Identifier().length() ==
					id.length()))
					dev = (*i);
			}
		} else {
			/* grab the first device */
			dev = devices[0];
		}

		/* verify device is valid. */
		if (!dev) {
			std::cout << "No valid device found.\n" << std::endl;
			exit(-1);
		} else {
			std::cout << "Running tests on device " <<
			    dev->Identifier() << std::endl;
		}

		/* something to do? */
		if (!(arg_transport || arg_u2f || arg_iso7816)) {
			std::cout << "Nothing to do." << std::endl;
			return 0;
		}

		/* check that link encryption is enabled */
		WARN_EQ(arg_encryption, true);

		/* do ble transport tests */
		if (arg_transport) {
			if (BLETransportTests(dev) != BLEAPI_ERROR_SUCCESS)
				return -1;
		}

		/* do the u2f tests */
		if (arg_u2f) {
			if (U2FTests(dev) != BLEAPI_ERROR_SUCCESS)
				return -1;
		}
		/* do the iso7816-4 tests */
		if (arg_iso7816) {
			if (U2FISO7816EncodingTests(dev) !=
			    BLEAPI_ERROR_SUCCESS)
				return -1;

		}
	}
	catch(std::exception e) {
		std::cout << "ERROR: " << e.what() << std::endl;

		return -1;
	}

	std::cout << std::endl << "==== Test completed. ====" << std::endl;

	return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include "unit.h"

#include <Thor/Math.hpp>
#include <Thor/Shapes.hpp>

Unit::Unit(const sf::Texture &texture, const sf::Texture &shadow_texture, const sf::Texture& selectedBitmap, float x, float y,int body_facing):
    sprite(texture),
    shadow_sprite(shadow_texture),
    selectedSprite(selectedBitmap),
    selected(false),
    map(nullptr)
  //owner(&thePlayer)
{
    this->selected = false;
    this->is_infantry = false;
    //this->shadowset = shadowset;
    setFacing(body_facing);
    this->desired_body_facing = body_facing;
    this->view_range = view_range;
    //this->position = Point(world_x, world_y);
//    this->next_move_position = this->position;
//    this->prev_position = this->position;
//    this->map=map;
//    this->move_behavior.reset(move_behavior);
    sprite.setPosition(x,y);
    shadow_sprite.setPosition(x,y);
    this->target = sprite.getPosition();

    //init(tileset, shadowset, map, world_x, world_y, view_range, move_behavior, sub_cell, tile_size, unit_size);
    selectedSprite.setPosition(x,y);
}

void Unit::draw(sf::RenderTarget &target, sf::RenderStates states) const
{
    target.draw(shadow_sprite, sf::BlendAlpha);
    target.draw(sprite);
    if (selected)
        target.draw(selectedSprite);

    if (has_target())
        target.draw(thor::Arrow(getCenter(), this->target - getCenter(), sf::Color(51,255,51,125)), sf::BlendAdd);
}

void Unit::select() {
  selected = true;
}

void Unit::unselect() {
  selected = false;
}

bool Unit::is_selected() {
  return selected;
}

//bool Unit::is_within(const Rectangle& rectangle) {
//  return rectangle.is_point_within(Point(position.x, position.y));
//}

//bool Unit::is_on_air_layer() {
//  return isOnLayer(MAP_LAYER_AIR);
//}

//bool Unit::is_on_ground_layer() {
//  return isOnLayer(MAP_LAYER_GROUND);
//}

//bool Unit::is_point_within(const Point& point) {
//  Point start_of_click_area = Point(position.x, position.y) - Point(unit_size.x, unit_size.y);
//  Rectangle current_area = Rectangle(start_of_click_area, (Point(position.x, position.y) + unit_size));
//  return current_area.is_point_within(point);
//}

//void Unit::moveUp() {
//  updateMovePosition(Point(0, -TILE_SIZE));
//}

//void Unit::moveDown() {
//  updateMovePosition(Point(0, TILE_SIZE));
//}

//void Unit::moveLeft() {
//  updateMovePosition(Point(-TILE_SIZE, 0));
//}

//void Unit::moveRight() {
//  updateMovePosition(Point(TILE_SIZE, 0));
//}

//void Unit::updateMovePosition(sf::Vector2i p) {
//  // this makes it troublesome to move to 'sub cells' (other parts than center of cell, given by p from mouse)
//  this->next_move_position = this->next_move_position + p;
//  this->desired_body_facing = desired_facing();
//}

bool Unit::is_moving() {
  return position != next_move_position;
}

bool Unit::has_target() const {
    return sprite.getPosition() != target;
}

bool Unit::should_turn_body() {
  return desired_body_facing != body_facing;
}

void Unit::stopMoving() {
  this->next_move_position = position;
}

int Unit::getDrawX() {
  return (position.x + offset_x);
}

int Unit::getDrawY() {
  return (position.y + offset_y);
}

bool Unit::isOnLayer(short layer) {
  return this->move_behavior->is_layer(layer);
}

void Unit::order_move(sf::Vector2f target) {
  // snap coordinates to center of cell
//  int y = ((target.y / TILE_SIZE) * TILE_SIZE) + (TILE_SIZE / 2);
//  int x = ((target.x / TILE_SIZE) * TILE_SIZE) + (TILE_SIZE / 2);

//  this->target = sf::Vector2i(x, y);
  this->target = target;

  // then apply the same offset if given
//  this->target = this->target + this->sub_position;
}

//const Player &Unit::getOwner() const
//{
//    return *owner;
//}

void Unit::setFacing(int facing) {
  body_facing = facing;
  int size = sprite.getTexture()->getSize().x / FACINGS;
  sprite.setTextureRect({size * body_facing, 0, size, size});
  shadow_sprite.setTextureRect({size * body_facing, 0, size, size});
  shadow_sprite.setColor(sf::Color(255, 255, 255, 128));
}

int Unit::desired_facing() {
  if (position == next_move_position) return body_facing;

  int nx = next_move_position.x;
  int ny = next_move_position.y;
  int x = position.x;
  int y = position.y;

  if (nx > x && ny == y) return FACING_RIGHT;
  if (nx < x && ny == y) return FACING_LEFT;
  if (nx == x && ny > y) return FACING_DOWN;
  if (nx == x && ny < y) return FACING_UP;

  if (nx > x && ny > y) return FACING_RIGHT_DOWN;
  if (nx < x && ny > y) return FACING_DOWN_LEFT;
  if (nx > x && ny < y) return FACING_UP_RIGHT;
  if (nx < x && ny < y) return FACING_LEFT_UP;

  return body_facing;
}

void Unit::turn_body() {
  int body_facing = this->body_facing;
  int desired = desired_facing();

  int turning_left = (body_facing + FACINGS) - desired;
  if (turning_left > (FACINGS - 1)) turning_left -= FACINGS;
  int turning_right = abs(turning_left - FACINGS);

  if (turning_right < turning_left) {
    body_facing++;
  } else if (turning_left < turning_right) {
    body_facing--;
  } else {
    thor::random(0, 10) < 5 ? body_facing-- : body_facing++;
  }

  // wrap around
  if (body_facing < 0) body_facing += FACINGS;
  if (body_facing > 7) body_facing -= FACINGS;

  setFacing(body_facing);
}

void Unit::updateMovePosition()
{
    if (has_target()){
        static const float speed = 5.f;
        sf::Vector2f direction = target - getCenter();
        sf::Vector2f unitDirection = thor::unitVector(direction);
        sprite.move(speed*unitDirection);
    }
}

sf::FloatRect Unit::getBounds() const
{
    return sprite.getGlobalBounds();
}

sf::Vector2f Unit::getPosition() const
{
    return sprite.getPosition();
}

sf::Vector2f Unit::getCenter() const
{
    sf::FloatRect spriteRect(sprite.getGlobalBounds());
    return (sprite.getPosition() + sf::Vector2f(spriteRect.width/2, spriteRect.height/2));
}

void Unit::updateState() {

    updateMovePosition();

  if (should_turn_body()) {
    turn_body();
    return;
  }

}
  // think about movement
//  if (!is_moving()) {
//    if (prev_position != position) {
//      move_behavior->unOccupyCell(Point(prev_position.x, prev_position.y));
//      map->removeShroud(Point(position.x, position.y), this->view_range);
//    }

//    if (has_target()) {
//      // determine what the next adjecent tile should be
//      if (target.x < position.x) moveLeft();
//      if (target.x > position.x) moveRight();
//      if (target.y < position.y) moveUp();
//      if (target.y > position.y) moveDown();

//      // check if we can move to this
//      if (!move_behavior->canMoveTo(Point(next_move_position.x, next_move_position.y))) {
//        stopMoving();
//      } else {
//        // we can move to this tile, claim it
//        move_behavior->occupyCell(Point(next_move_position.x, next_move_position.y));
//        prev_position = position;

//        // TODO!??! - determine sub-cell / position for infantry if applicable?

//        // calculate the direction once
//        this->next_move_direction = Vector2D(position, next_move_position).normalize();
//      }

//    } else {
//      prev_position = position;
//    }

//  }

//  if (has_target()) {
//    Vector2D vector = Vector2D(position, next_move_position);

//    float distance = vector.length();
//    float speed = 2.0F;
//    if (distance < speed) speed = distance;

//    position.x = position.x + (next_move_direction.x * speed);
//    position.y = position.y + (next_move_direction.y * speed);
//  }

//}

////////////////////////////////////////////
//// Unit Repository
////
////////////////////////////////////////////
//UnitRepository::UnitRepository(Map* map) {
//  this->map = map;

//  for (int i = 0; i < MAX_UNIT_TYPES; i++) {
//    unit_animation[i] = NULL;
//    unit_shadow[i] = NULL;
//  }

//  unit_animation[UNIT_QUAD] = Surface::load8bit("graphics/Unit_Quad.bmp");
//  unit_shadow[UNIT_QUAD] = Surface::load("graphics/Unit_Quad_s.bmp", 255, 0, 255);

//  unit_animation[UNIT_DEVASTATOR] = Surface::load8bit("graphics/Unit_Devastator.bmp");
//  unit_shadow[UNIT_DEVASTATOR] = Surface::load("graphics/Unit_Devastator_s.bmp", 255, 0, 255);

//  unit_animation[UNIT_FRIGATE] = Surface::load8bit("graphics/Unit_Frigate.bmp");
//  unit_shadow[UNIT_FRIGATE] = Surface::load("graphics/Unit_Frigate_s.bmp", 255, 0, 255);

//  unit_animation[UNIT_CARRYALL] = Surface::load8bit("graphics/Unit_Carryall.bmp");
//  unit_shadow[UNIT_CARRYALL] = Surface::load("graphics/Unit_Carryall_s.bmp", 255, 0, 255);

//  unit_animation[UNIT_TRIKE] = Surface::load8bit("graphics/Unit_Trike.bmp");
//  unit_shadow[UNIT_TRIKE] = Surface::load("graphics/Unit_Trike_s.bmp", 255, 0, 255);

//  unit_animation[UNIT_SOLDIER] = Surface::load8bit("graphics/Unit_Soldier.bmp");
//  unit_shadow[UNIT_SOLDIER] = NULL;

//  air_unit_move_behavior    = new AirUnitMoveBehavior(map);
//  ground_unit_move_behavior = new GroundUnitMoveBehavior(map);
//  foot_unit_move_behavior   = new FootUnitMoveBehavior(map);
//}

//UnitRepository::~UnitRepository() {
//  for (int i = 0; i < MAX_UNIT_TYPES; i++) {
//    SDL_FreeSurface(unit_animation[i]);
//    SDL_FreeSurface(unit_shadow[i]);
//  }
//}

//Unit* UnitRepository::create(int unitType, int x, int y, int view_range, int sub_cell) {
//  SDL_Surface* copy = Surface::copy(unit_animation[unitType]);
//  int paletteIndex = thePlayer.getColor();
//  SDL_SetColors(copy, &copy->format->palette->colors[paletteIndex], 144, 8); //magic numbers

//  UnitMoveBehavior *move_behavior = NULL;
//  if (unitType == UNIT_FRIGATE) {
//    move_behavior = air_unit_move_behavior;
//  } else if (unitType == UNIT_SOLDIER) {
//    move_behavior = foot_unit_move_behavior;
//  } else {
//    move_behavior = ground_unit_move_behavior;
//  }
//  SDL_Surface* shadow_copy = Surface::copy(unit_shadow[unitType]);

//  int tile_height = 0, tile_width = 0;
//  tile_width = copy->w / FACINGS;

//  // check if our assumption (width==height) is true for this tileset, and if not warn the user.
//  if (copy->h % tile_width > 0) {
//    cerr << "WARNING: This copy does not meet the requirement : tile height must equal width." << endl << endl;
//    cerr << "Based on 8 sides of a unit, the calculated width of a tile on this copy is " << tile_width << ". The general assumption is that the height of a tile must equal width. " << endl;
//    cerr << "However the height of this copy (" << copy->h << ") was not one or more multiplications of " << tile_width << ". Its dimensions are " << copy->h << "x" << copy->w << ".";
//    cerr << endl;

//    // if it is less height than wide, we
//    if (copy->h < tile_width) {
//      cerr << "Because the height of the copy (" << copy->h << ") is *lower* than the width of a calculated tile(=" << tile_width << ") (and therefor has no animations). We assume the height of the copy of " << copy->h << "." << endl;
//      tile_height = copy->h;
//    } else {
//      cerr << "Since the height of the copy (" << copy->h << ") is *greater* than the width of a calculated tile(=" << tile_width <<") (which means there could be animations) we assume the height equals the calculated width of " << tile_width << "." << endl;
//      tile_height = tile_width;
//    }
//    cerr << endl;
//  } else {
//    tile_height = tile_width;
//  }

//  int unit_width = tile_width;
//  int unit_height = tile_height;

//  if (unitType == UNIT_SOLDIER) {
//    unit_width = unit_height = 8;
//  }

//  return new Unit(copy, shadow_copy, map, move_behavior, (x * TILE_SIZE) + (TILE_SIZE / 2), (y * TILE_SIZE) + (TILE_SIZE / 2), view_range, sub_cell, Point(tile_width, tile_height), Point(unit_width, unit_height), thePlayer);
//}
<commit_msg>movement is affected by floating point errors<commit_after>#include <iostream>
#include "unit.h"

#include <Thor/Math.hpp>
#include <Thor/Shapes.hpp>

Unit::Unit(const sf::Texture &texture, const sf::Texture &shadow_texture, const sf::Texture& selectedBitmap, float x, float y,int body_facing):
    sprite(texture),
    shadow_sprite(shadow_texture),
    selectedSprite(selectedBitmap),
    selected(false),
    map(nullptr)
  //owner(&thePlayer)
{
    this->selected = false;
    this->is_infantry = false;
    //this->shadowset = shadowset;
    setFacing(body_facing);
    this->desired_body_facing = body_facing;
    this->view_range = view_range;
    //this->position = Point(world_x, world_y);
//    this->next_move_position = this->position;
//    this->prev_position = this->position;
//    this->map=map;
//    this->move_behavior.reset(move_behavior);
    sprite.setPosition(x,y);
    shadow_sprite.setPosition(x,y);
    this->target = getCenter();

    //init(tileset, shadowset, map, world_x, world_y, view_range, move_behavior, sub_cell, tile_size, unit_size);
    selectedSprite.setPosition(x,y);
}

void Unit::draw(sf::RenderTarget &target, sf::RenderStates states) const
{
    target.draw(shadow_sprite, sf::BlendAlpha);
    target.draw(sprite);
    if (selected)
        target.draw(selectedSprite);

    if (has_target())
        target.draw(thor::Arrow(getCenter(), this->target - getCenter(), sf::Color(51,255,51,125)), sf::BlendAdd);
}

void Unit::select() {
  selected = true;
}

void Unit::unselect() {
  selected = false;
}

bool Unit::is_selected() {
  return selected;
}

//bool Unit::is_within(const Rectangle& rectangle) {
//  return rectangle.is_point_within(Point(position.x, position.y));
//}

//bool Unit::is_on_air_layer() {
//  return isOnLayer(MAP_LAYER_AIR);
//}

//bool Unit::is_on_ground_layer() {
//  return isOnLayer(MAP_LAYER_GROUND);
//}

//bool Unit::is_point_within(const Point& point) {
//  Point start_of_click_area = Point(position.x, position.y) - Point(unit_size.x, unit_size.y);
//  Rectangle current_area = Rectangle(start_of_click_area, (Point(position.x, position.y) + unit_size));
//  return current_area.is_point_within(point);
//}

//void Unit::moveUp() {
//  updateMovePosition(Point(0, -TILE_SIZE));
//}

//void Unit::moveDown() {
//  updateMovePosition(Point(0, TILE_SIZE));
//}

//void Unit::moveLeft() {
//  updateMovePosition(Point(-TILE_SIZE, 0));
//}

//void Unit::moveRight() {
//  updateMovePosition(Point(TILE_SIZE, 0));
//}

//void Unit::updateMovePosition(sf::Vector2i p) {
//  // this makes it troublesome to move to 'sub cells' (other parts than center of cell, given by p from mouse)
//  this->next_move_position = this->next_move_position + p;
//  this->desired_body_facing = desired_facing();
//}

bool Unit::is_moving() {
  return position != next_move_position;
}

bool Unit::has_target() const {
    return getCenter() != target;
}

bool Unit::should_turn_body() {
  return desired_body_facing != body_facing;
}

void Unit::stopMoving() {
  this->next_move_position = position;
}

int Unit::getDrawX() {
  return (position.x + offset_x);
}

int Unit::getDrawY() {
  return (position.y + offset_y);
}

bool Unit::isOnLayer(short layer) {
  return this->move_behavior->is_layer(layer);
}

void Unit::order_move(sf::Vector2f target) {
  // snap coordinates to center of cell
//  int y = ((target.y / TILE_SIZE) * TILE_SIZE) + (TILE_SIZE / 2);
//  int x = ((target.x / TILE_SIZE) * TILE_SIZE) + (TILE_SIZE / 2);

//  this->target = sf::Vector2i(x, y);
  this->target = target;

  // then apply the same offset if given
//  this->target = this->target + this->sub_position;
}

//const Player &Unit::getOwner() const
//{
//    return *owner;
//}

void Unit::setFacing(int facing) {
  body_facing = facing;
  int size = sprite.getTexture()->getSize().x / FACINGS;
  sprite.setTextureRect({size * body_facing, 0, size, size});
  shadow_sprite.setTextureRect({size * body_facing, 0, size, size});
  shadow_sprite.setColor(sf::Color(255, 255, 255, 128));
}

int Unit::desired_facing() {
  if (position == next_move_position) return body_facing;

  int nx = next_move_position.x;
  int ny = next_move_position.y;
  int x = position.x;
  int y = position.y;

  if (nx > x && ny == y) return FACING_RIGHT;
  if (nx < x && ny == y) return FACING_LEFT;
  if (nx == x && ny > y) return FACING_DOWN;
  if (nx == x && ny < y) return FACING_UP;

  if (nx > x && ny > y) return FACING_RIGHT_DOWN;
  if (nx < x && ny > y) return FACING_DOWN_LEFT;
  if (nx > x && ny < y) return FACING_UP_RIGHT;
  if (nx < x && ny < y) return FACING_LEFT_UP;

  return body_facing;
}

void Unit::turn_body() {
  int body_facing = this->body_facing;
  int desired = desired_facing();

  int turning_left = (body_facing + FACINGS) - desired;
  if (turning_left > (FACINGS - 1)) turning_left -= FACINGS;
  int turning_right = abs(turning_left - FACINGS);

  if (turning_right < turning_left) {
    body_facing++;
  } else if (turning_left < turning_right) {
    body_facing--;
  } else {
    thor::random(0, 10) < 5 ? body_facing-- : body_facing++;
  }

  // wrap around
  if (body_facing < 0) body_facing += FACINGS;
  if (body_facing > 7) body_facing -= FACINGS;

  setFacing(body_facing);
}

void Unit::updateMovePosition()
{
    if (has_target()){
        static const float speed = 5.f;
        sf::Vector2f direction = target - getCenter();
        sf::Vector2f unitDirection = thor::unitVector(direction);
        sprite.move(speed*unitDirection);
    }
}

sf::FloatRect Unit::getBounds() const
{
    return sprite.getGlobalBounds();
}

sf::Vector2f Unit::getPosition() const
{
    return sprite.getPosition();
}

sf::Vector2f Unit::getCenter() const
{
    sf::FloatRect spriteRect(sprite.getGlobalBounds());
    return (sprite.getPosition() + sf::Vector2f(spriteRect.width/2, spriteRect.height/2));
}

void Unit::updateState() {

    updateMovePosition();

  if (should_turn_body()) {
    turn_body();
    return;
  }

}
  // think about movement
//  if (!is_moving()) {
//    if (prev_position != position) {
//      move_behavior->unOccupyCell(Point(prev_position.x, prev_position.y));
//      map->removeShroud(Point(position.x, position.y), this->view_range);
//    }

//    if (has_target()) {
//      // determine what the next adjecent tile should be
//      if (target.x < position.x) moveLeft();
//      if (target.x > position.x) moveRight();
//      if (target.y < position.y) moveUp();
//      if (target.y > position.y) moveDown();

//      // check if we can move to this
//      if (!move_behavior->canMoveTo(Point(next_move_position.x, next_move_position.y))) {
//        stopMoving();
//      } else {
//        // we can move to this tile, claim it
//        move_behavior->occupyCell(Point(next_move_position.x, next_move_position.y));
//        prev_position = position;

//        // TODO!??! - determine sub-cell / position for infantry if applicable?

//        // calculate the direction once
//        this->next_move_direction = Vector2D(position, next_move_position).normalize();
//      }

//    } else {
//      prev_position = position;
//    }

//  }

//  if (has_target()) {
//    Vector2D vector = Vector2D(position, next_move_position);

//    float distance = vector.length();
//    float speed = 2.0F;
//    if (distance < speed) speed = distance;

//    position.x = position.x + (next_move_direction.x * speed);
//    position.y = position.y + (next_move_direction.y * speed);
//  }

//}

////////////////////////////////////////////
//// Unit Repository
////
////////////////////////////////////////////
//UnitRepository::UnitRepository(Map* map) {
//  this->map = map;

//  for (int i = 0; i < MAX_UNIT_TYPES; i++) {
//    unit_animation[i] = NULL;
//    unit_shadow[i] = NULL;
//  }

//  unit_animation[UNIT_QUAD] = Surface::load8bit("graphics/Unit_Quad.bmp");
//  unit_shadow[UNIT_QUAD] = Surface::load("graphics/Unit_Quad_s.bmp", 255, 0, 255);

//  unit_animation[UNIT_DEVASTATOR] = Surface::load8bit("graphics/Unit_Devastator.bmp");
//  unit_shadow[UNIT_DEVASTATOR] = Surface::load("graphics/Unit_Devastator_s.bmp", 255, 0, 255);

//  unit_animation[UNIT_FRIGATE] = Surface::load8bit("graphics/Unit_Frigate.bmp");
//  unit_shadow[UNIT_FRIGATE] = Surface::load("graphics/Unit_Frigate_s.bmp", 255, 0, 255);

//  unit_animation[UNIT_CARRYALL] = Surface::load8bit("graphics/Unit_Carryall.bmp");
//  unit_shadow[UNIT_CARRYALL] = Surface::load("graphics/Unit_Carryall_s.bmp", 255, 0, 255);

//  unit_animation[UNIT_TRIKE] = Surface::load8bit("graphics/Unit_Trike.bmp");
//  unit_shadow[UNIT_TRIKE] = Surface::load("graphics/Unit_Trike_s.bmp", 255, 0, 255);

//  unit_animation[UNIT_SOLDIER] = Surface::load8bit("graphics/Unit_Soldier.bmp");
//  unit_shadow[UNIT_SOLDIER] = NULL;

//  air_unit_move_behavior    = new AirUnitMoveBehavior(map);
//  ground_unit_move_behavior = new GroundUnitMoveBehavior(map);
//  foot_unit_move_behavior   = new FootUnitMoveBehavior(map);
//}

//UnitRepository::~UnitRepository() {
//  for (int i = 0; i < MAX_UNIT_TYPES; i++) {
//    SDL_FreeSurface(unit_animation[i]);
//    SDL_FreeSurface(unit_shadow[i]);
//  }
//}

//Unit* UnitRepository::create(int unitType, int x, int y, int view_range, int sub_cell) {
//  SDL_Surface* copy = Surface::copy(unit_animation[unitType]);
//  int paletteIndex = thePlayer.getColor();
//  SDL_SetColors(copy, &copy->format->palette->colors[paletteIndex], 144, 8); //magic numbers

//  UnitMoveBehavior *move_behavior = NULL;
//  if (unitType == UNIT_FRIGATE) {
//    move_behavior = air_unit_move_behavior;
//  } else if (unitType == UNIT_SOLDIER) {
//    move_behavior = foot_unit_move_behavior;
//  } else {
//    move_behavior = ground_unit_move_behavior;
//  }
//  SDL_Surface* shadow_copy = Surface::copy(unit_shadow[unitType]);

//  int tile_height = 0, tile_width = 0;
//  tile_width = copy->w / FACINGS;

//  // check if our assumption (width==height) is true for this tileset, and if not warn the user.
//  if (copy->h % tile_width > 0) {
//    cerr << "WARNING: This copy does not meet the requirement : tile height must equal width." << endl << endl;
//    cerr << "Based on 8 sides of a unit, the calculated width of a tile on this copy is " << tile_width << ". The general assumption is that the height of a tile must equal width. " << endl;
//    cerr << "However the height of this copy (" << copy->h << ") was not one or more multiplications of " << tile_width << ". Its dimensions are " << copy->h << "x" << copy->w << ".";
//    cerr << endl;

//    // if it is less height than wide, we
//    if (copy->h < tile_width) {
//      cerr << "Because the height of the copy (" << copy->h << ") is *lower* than the width of a calculated tile(=" << tile_width << ") (and therefor has no animations). We assume the height of the copy of " << copy->h << "." << endl;
//      tile_height = copy->h;
//    } else {
//      cerr << "Since the height of the copy (" << copy->h << ") is *greater* than the width of a calculated tile(=" << tile_width <<") (which means there could be animations) we assume the height equals the calculated width of " << tile_width << "." << endl;
//      tile_height = tile_width;
//    }
//    cerr << endl;
//  } else {
//    tile_height = tile_width;
//  }

//  int unit_width = tile_width;
//  int unit_height = tile_height;

//  if (unitType == UNIT_SOLDIER) {
//    unit_width = unit_height = 8;
//  }

//  return new Unit(copy, shadow_copy, map, move_behavior, (x * TILE_SIZE) + (TILE_SIZE / 2), (y * TILE_SIZE) + (TILE_SIZE / 2), view_range, sub_cell, Point(tile_width, tile_height), Point(unit_width, unit_height), thePlayer);
//}
<|endoftext|>