text:
/*
 * Copyright (C) 2014-2015 Open Source Robotics Foundation
 *
 * 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 <boost/bind.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <string>
#include <vector>

#include "gazebo/common/MouseEvent.hh"

#include "gazebo/rendering/ogre_gazebo.h"
#include "gazebo/rendering/DynamicLines.hh"
#include "gazebo/rendering/Visual.hh"
#include "gazebo/rendering/JointVisual.hh"
#include "gazebo/rendering/UserCamera.hh"
#include "gazebo/rendering/Scene.hh"
#include "gazebo/rendering/RenderTypes.hh"

#include "gazebo/gui/GuiIface.hh"
#include "gazebo/gui/KeyEventHandler.hh"
#include "gazebo/gui/MouseEventHandler.hh"
#include "gazebo/gui/GuiEvents.hh"
#include "gazebo/gui/MainWindow.hh"

#include "gazebo/gui/model/JointInspector.hh"
#include "gazebo/gui/model/ModelEditorEvents.hh"
#include "gazebo/gui/model/JointMaker.hh"

using namespace gazebo;
using namespace gui;

std::map<JointMaker::JointType, std::string> JointMaker::jointTypes;
std::map<JointMaker::JointType, std::string> JointMaker::jointMaterials;

/////////////////////////////////////////////////
JointMaker::JointMaker()
{
  this->unitVectors.push_back(ignition::math::Vector3d::UnitX);
  this->unitVectors.push_back(ignition::math::Vector3d::UnitY);
  this->unitVectors.push_back(ignition::math::Vector3d::UnitZ);

  this->newJointCreated = false;
  this->mouseJoint = NULL;
  this->modelSDF.reset();
  this->jointType = JointMaker::JOINT_NONE;
  this->jointCounter = 0;

  this->jointMaterials[JOINT_FIXED]     = "Gazebo/Red";
  this->jointMaterials[JOINT_HINGE]     = "Gazebo/Orange";
  this->jointMaterials[JOINT_HINGE2]    = "Gazebo/DarkYellow";
  this->jointMaterials[JOINT_SLIDER]    = "Gazebo/Green";
  this->jointMaterials[JOINT_SCREW]     = "Gazebo/DarkGrey";
  this->jointMaterials[JOINT_UNIVERSAL] = "Gazebo/Blue";
  this->jointMaterials[JOINT_BALL]      = "Gazebo/Purple";
  this->jointMaterials[JOINT_GEARBOX]   = "Gazebo/Indigo";

  this->jointTypes[JOINT_FIXED]     = "fixed";
  this->jointTypes[JOINT_HINGE]     = "revolute";
  this->jointTypes[JOINT_HINGE2]    = "revolute2";
  this->jointTypes[JOINT_SLIDER]    = "prismatic";
  this->jointTypes[JOINT_SCREW]     = "screw";
  this->jointTypes[JOINT_UNIVERSAL] = "universal";
  this->jointTypes[JOINT_BALL]      = "ball";
  this->jointTypes[JOINT_GEARBOX]   = "gearbox";
  this->jointTypes[JOINT_NONE]      = "none";

  this->connections.push_back(
      event::Events::ConnectPreRender(
      boost::bind(&JointMaker::Update, this)));

  this->connections.push_back(
      gui::model::Events::ConnectOpenJointInspector(
      boost::bind(&JointMaker::OpenInspector, this, _1)));

  this->connections.push_back(
      gui::model::Events::ConnectShowJointContextMenu(
      boost::bind(&JointMaker::ShowContextMenu, this, _1)));

  this->connections.push_back(
      gui::model::Events::ConnectSetSelectedJoint(
      boost::bind(&JointMaker::OnSetSelectedJoint, this, _1, _2)));

  this->connections.push_back(
      event::Events::ConnectSetSelectedEntity(
      boost::bind(&JointMaker::OnSetSelectedEntity, this, _1, _2)));

  this->inspectAct = new QAction(tr("Open Joint Inspector"), this);
  connect(this->inspectAct, SIGNAL(triggered()), this, SLOT(OnOpenInspector()));

  this->updateMutex = new boost::recursive_mutex();

  // Gazebo event connections
  this->connections.push_back(
      gui::model::Events::ConnectLinkInserted(
      boost::bind(&JointMaker::OnLinkInserted, this, _1)));

  this->connections.push_back(
      gui::model::Events::ConnectLinkRemoved(
      boost::bind(&JointMaker::OnLinkRemoved, this, _1)));
}

/////////////////////////////////////////////////
JointMaker::~JointMaker()
{
  if (this->mouseJoint)
  {
    delete this->mouseJoint;
    this->mouseJoint = NULL;
  }

  {
    boost::recursive_mutex::scoped_lock lock(*this->updateMutex);
    while (this->joints.size() > 0)
    {
      std::string jointName = this->joints.begin()->first;
      this->RemoveJoint(jointName);
    }
    this->joints.clear();
  }

  delete this->updateMutex;
}

/////////////////////////////////////////////////
void JointMaker::Reset()
{
  boost::recursive_mutex::scoped_lock lock(*this->updateMutex);
  this->newJointCreated = false;
  if (this->mouseJoint)
  {
    delete this->mouseJoint;
    this->mouseJoint = NULL;
  }

  this->jointType = JointMaker::JOINT_NONE;
  this->selectedVis.reset();
  this->hoverVis.reset();
  this->inspectName = "";
  this->selectedJoints.clear();

  this->scopedLinkedNames.clear();

  while (!this->joints.empty())
  {
    std::string jointId = this->joints.begin()->first;
    this->RemoveJoint(jointId);
  }
  this->joints.clear();
}

/////////////////////////////////////////////////
void JointMaker::EnableEventHandlers()
{
  MouseEventHandler::Instance()->AddDoubleClickFilter("model_joint",
    boost::bind(&JointMaker::OnMouseDoubleClick, this, _1));

  MouseEventHandler::Instance()->AddReleaseFilter("model_joint",
      boost::bind(&JointMaker::OnMouseRelease, this, _1));

  MouseEventHandler::Instance()->AddPressFilter("model_joint",
      boost::bind(&JointMaker::OnMousePress, this, _1));

  KeyEventHandler::Instance()->AddPressFilter("model_joint",
      boost::bind(&JointMaker::OnKeyPress, this, _1));
}

/////////////////////////////////////////////////
void JointMaker::DisableEventHandlers()
{
  MouseEventHandler::Instance()->RemoveDoubleClickFilter("model_joint");
  MouseEventHandler::Instance()->RemoveReleaseFilter("model_joint");
  MouseEventHandler::Instance()->RemovePressFilter("model_joint");
  MouseEventHandler::Instance()->RemoveMoveFilter("model_joint");
  KeyEventHandler::Instance()->RemovePressFilter("model_joint");
}

/////////////////////////////////////////////////
void JointMaker::RemoveJoint(const std::string &_jointId)
{
  boost::recursive_mutex::scoped_lock lock(*this->updateMutex);
  auto jointIt = this->joints.find(_jointId);
  if (jointIt != this->joints.end())
  {
    // Copy the ID before it is deleted
    std::string jointId = _jointId;

    JointData *joint = jointIt->second;
    rendering::ScenePtr scene = joint->hotspot->GetScene();
    scene->GetManager()->destroyBillboardSet(joint->handles);
    scene->RemoveVisual(joint->hotspot);
    scene->RemoveVisual(joint->visual);
    joint->visual->Fini();
    if (joint->jointVisual)
    {
      rendering::JointVisualPtr parentAxisVis = joint->jointVisual
          ->GetParentAxisVisual();
      if (parentAxisVis)
      {
        parentAxisVis->GetParent()->DetachVisual(
            parentAxisVis->GetName());
        scene->RemoveVisual(parentAxisVis);
      }
      joint->jointVisual->GetParent()->DetachVisual(
          joint->jointVisual->GetName());
      scene->RemoveVisual(joint->jointVisual);
    }
    joint->hotspot.reset();
    joint->visual.reset();
    joint->jointVisual.reset();
    joint->parent.reset();
    joint->child.reset();
    joint->inspector->hide();
    delete joint->inspector;
    delete joint;
    this->joints.erase(jointIt);
    gui::model::Events::modelChanged();
    gui::model::Events::jointRemoved(jointId);
  }
}

/////////////////////////////////////////////////
void JointMaker::RemoveJointsByLink(const std::string &_linkName)
{
  std::vector<std::string> toDelete;
  for (auto it : this->joints)
  {
    JointData *joint = it.second;

    if (joint->child->GetName() == _linkName ||
        joint->parent->GetName() == _linkName)
    {
      toDelete.push_back(it.first);
    }
  }

  for (unsigned i = 0; i < toDelete.size(); ++i)
    this->RemoveJoint(toDelete[i]);

  toDelete.clear();
}

/////////////////////////////////////////////////
std::vector<JointData *> JointMaker::GetJointDataByLink(
    const std::string &_linkName) const
{
  std::vector<JointData *> linkJoints;
  for (auto jointIt : this->joints)
  {
    JointData *jointData = jointIt.second;

    if (jointData->child->GetName() == _linkName ||
        jointData->parent->GetName() == _linkName)
    {
      linkJoints.push_back(jointData);
    }
  }
  return linkJoints;
}

/////////////////////////////////////////////////
bool JointMaker::OnMousePress(const common::MouseEvent &_event)
{
  rendering::UserCameraPtr camera = gui::get_active_camera();
  if (_event.Button() == common::MouseEvent::MIDDLE)
  {
    QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));
    camera->HandleMouseEvent(_event);
    return true;
  }
  else if (_event.Button() != common::MouseEvent::LEFT)
    return false;

  if (this->jointType != JointMaker::JOINT_NONE)
    return false;

  // intercept mouse press events when user clicks on the joint hotspot visual
  rendering::VisualPtr vis = camera->GetVisual(_event.Pos());
  if (vis)
  {
    if (this->joints.find(vis->GetName()) != this->joints.end())
    {
      // stop event propagation as we don't want users to manipulate the
      // hotspot
      return true;
    }
  }
  return false;
}

/////////////////////////////////////////////////
bool JointMaker::OnMouseRelease(const common::MouseEvent &_event)
{
  rendering::UserCameraPtr camera = gui::get_active_camera();
  if (this->jointType == JointMaker::JOINT_NONE)
  {
    rendering::VisualPtr vis = camera->GetVisual(_event.Pos());
    if (vis)
    {
      if (this->joints.find(vis->GetName()) != this->joints.end())
      {
        // trigger joint inspector on right click
        if (_event.Button() == common::MouseEvent::RIGHT)
        {
          this->inspectName = vis->GetName();
          this->ShowContextMenu(this->inspectName);
          return true;
        }
        else if (_event.Button() == common::MouseEvent::LEFT)
        {
          // Not in multi-selection mode.
          if (!(QApplication::keyboardModifiers() & Qt::ControlModifier))
          {
            this->DeselectAll();
            this->SetSelected(vis, true);
          }
          // Multi-selection mode
          else
          {
            auto it = std::find(this->selectedJoints.begin(),
                this->selectedJoints.end(), vis);
            // Highlight and select clicked joint if not already selected
            // Otherwise deselect if already selected
            this->SetSelected(vis, it == this->selectedJoints.end());
          }
        }
      }
      else
        this->DeselectAll();
      return false;
    }
  }
  else
  {
    if (_event.Button() == common::MouseEvent::LEFT)
    {
      if (this->hoverVis)
      {
        if (this->hoverVis->IsPlane())
        {
          QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));
          camera->HandleMouseEvent(_event);
          return true;
        }

        // Pressed parent link
        if (!this->selectedVis)
        {
          if (this->mouseJoint)
            return false;

          this->hoverVis->SetEmissive(common::Color(0, 0, 0));
          this->selectedVis = this->hoverVis;
          this->hoverVis.reset();

          // Create joint data with selected visual as parent
          // the child will be set on the second mouse release.
          this->mouseJoint = this->CreateJointLine("JOINT_LINE",
              this->selectedVis);
        }
        // Pressed child link
        else if (this->selectedVis != this->hoverVis)
        {
          if (this->hoverVis)
            this->hoverVis->SetEmissive(common::Color(0, 0, 0));
          if (this->selectedVis)
            this->selectedVis->SetEmissive(common::Color(0, 0, 0));

          this->mouseJoint->child = this->hoverVis;
          JointData *newJoint = this->CreateJoint(this->mouseJoint->parent,
              this->mouseJoint->child);
          this->Stop();
          this->mouseJoint = newJoint;
          this->newJointCreated = true;
          gui::model::Events::modelChanged();
        }
      }
    }

    QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));
    camera->HandleMouseEvent(_event);
    return true;
  }
  return false;
}

/////////////////////////////////////////////////
JointData *JointMaker::CreateJointLine(const std::string &_name,
    rendering::VisualPtr _parent)
{
  rendering::VisualPtr jointVis(
      new rendering::Visual(_name, _parent->GetParent()));
  jointVis->Load();
  rendering::DynamicLines *jointLine =
      jointVis->CreateDynamicLine(rendering::RENDERING_LINE_LIST);
  math::Vector3 origin = _parent->GetWorldPose().pos
      - _parent->GetParent()->GetWorldPose().pos;
  jointLine->AddPoint(origin);
  jointLine->AddPoint(origin + math::Vector3(0, 0, 0.1));
  jointVis->GetSceneNode()->setInheritScale(false);
  jointVis->GetSceneNode()->setInheritOrientation(false);

  std::string jointVisName = jointVis->GetName();
  std::string leafName = jointVisName;
  size_t pIdx = jointVisName.rfind("::");
  if (pIdx != std::string::npos)
    leafName = jointVisName.substr(pIdx+2);

  JointData *jointData = new JointData();
  jointData->dirty = false;
  jointData->name = leafName;
  jointData->visual = jointVis;
  jointData->parent = _parent;
  jointData->line = jointLine;
  jointData->type = this->jointType;
  jointData->line->setMaterial(this->jointMaterials[jointData->type]);

  return jointData;
}

/////////////////////////////////////////////////
JointData *JointMaker::CreateJoint(rendering::VisualPtr _parent,
    rendering::VisualPtr _child)
{
  std::stringstream ss;
  ss << _parent->GetName() << "_JOINT_" << this->jointCounter++;

  JointData *jointData = this->CreateJointLine(ss.str(), _parent);
  jointData->child = _child;

  // Inspector
  jointData->inspector = new JointInspector(this);
  jointData->inspector->setModal(false);
  connect(jointData->inspector, SIGNAL(Applied()), jointData, SLOT(OnApply()));

  MainWindow *mainWindow = gui::get_main_window();
  if (mainWindow)
  {
    connect(gui::get_main_window(), SIGNAL(Close()), jointData->inspector,
        SLOT(close()));
  }

  // setup the joint msg
  jointData->jointMsg.reset(new msgs::Joint);
  jointData->jointMsg->set_name(jointData->name);
  if (jointData->parent)
  {
    std::string jointParentName = jointData->parent->GetName();
    std::string leafName = jointParentName;
    size_t pIdx = jointParentName.rfind("::");
    if (pIdx != std::string::npos)
      leafName = jointParentName.substr(pIdx+2);

    jointData->jointMsg->set_parent(leafName);
    jointData->jointMsg->set_parent_id(jointData->parent->GetId());
  }
  if (jointData->child)
  {
    std::string jointChildName = jointData->child->GetName();
    std::string leafName = jointChildName;
    size_t pIdx = jointChildName.rfind("::");
    if (pIdx != std::string::npos)
      leafName = jointChildName.substr(pIdx+2);

    jointData->jointMsg->set_child(leafName);
    jointData->jointMsg->set_child_id(jointData->child->GetId());
  }
  msgs::Set(jointData->jointMsg->mutable_pose(),
      ignition::math::Pose3d::Zero);

  jointData->jointMsg->set_type(
      msgs::ConvertJointType(this->GetTypeAsString(jointData->type)));

  unsigned int axisCount = JointMaker::GetJointAxisCount(jointData->type);
  for (unsigned int i = 0; i < axisCount; ++i)
  {
    msgs::Axis *axisMsg;
    if (i == 0u)
    {
      axisMsg = jointData->jointMsg->mutable_axis1();
    }
    else if (i == 1u)
    {
      axisMsg = jointData->jointMsg->mutable_axis2();
    }
    else
    {
      gzerr << "Invalid axis index["
            << i
            << "]"
            << std::endl;
      continue;
    }
    if (jointData->type == JointMaker::JOINT_GEARBOX)
      msgs::Set(axisMsg->mutable_xyz(), ignition::math::Vector3d::UnitZ);

    else
    {
      msgs::Set(axisMsg->mutable_xyz(),
          this->unitVectors[i%this->unitVectors.size()]);
    }

    axisMsg->set_use_parent_model_frame(false);
    axisMsg->set_limit_lower(-GZ_DBL_MAX);
    axisMsg->set_limit_upper(GZ_DBL_MAX);
    axisMsg->set_limit_effort(-1);
    axisMsg->set_limit_velocity(-1);
    axisMsg->set_damping(0);

    // Add angle field after we've checked that index i is valid
    jointData->jointMsg->add_angle(0);
  }
  jointData->jointMsg->set_limit_erp(0.2);
  jointData->jointMsg->set_suspension_erp(0.2);

  jointData->inspector->Update(jointData->jointMsg);
  return jointData;
}

/////////////////////////////////////////////////
JointMaker::JointType JointMaker::ConvertJointType(const std::string &_type)
{
  for (auto iter : jointTypes)
    if (iter.second == _type)
      return iter.first;

  return JOINT_NONE;
}

/////////////////////////////////////////////////
std::string JointMaker::GetJointMaterial(const std::string &_type)
{
  auto it = jointMaterials.find(ConvertJointType(_type));
  if (it != jointMaterials.end())
    return it->second;
  else
    return "";
}

/////////////////////////////////////////////////
void JointMaker::AddJoint(const std::string &_type)
{
  this->AddJoint(this->ConvertJointType(_type));
}

/////////////////////////////////////////////////
void JointMaker::AddJoint(JointMaker::JointType _type)
{
  this->jointType = _type;
  if (_type != JointMaker::JOINT_NONE)
  {
    // Add an event filter, which allows the JointMaker to capture mouse events.
    MouseEventHandler::Instance()->AddMoveFilter("model_joint",
        boost::bind(&JointMaker::OnMouseMove, this, _1));
  }
  else
  {
    // Remove the event filters.
    MouseEventHandler::Instance()->RemoveMoveFilter("model_joint");

    // signal the end of a joint action.
    emit JointAdded();
  }
}

/////////////////////////////////////////////////
void JointMaker::Stop()
{
  if (this->jointType != JointMaker::JOINT_NONE)
  {
    this->newJointCreated = false;
    if (this->mouseJoint)
    {
      this->mouseJoint->visual->DeleteDynamicLine(this->mouseJoint->line);
      rendering::ScenePtr scene = this->mouseJoint->visual->GetScene();
      scene->RemoveVisual(this->mouseJoint->visual);
      this->mouseJoint->visual.reset();
      delete this->mouseJoint;
      this->mouseJoint = NULL;
    }
    this->AddJoint(JointMaker::JOINT_NONE);
    if (this->hoverVis)
      this->hoverVis->SetEmissive(common::Color(0, 0, 0));
    if (this->selectedVis)
      this->selectedVis->SetEmissive(common::Color(0, 0, 0));
    this->selectedVis.reset();
    this->hoverVis.reset();
  }
}

/////////////////////////////////////////////////
bool JointMaker::OnMouseMove(const common::MouseEvent &_event)
{
  // Get the active camera and scene.
  rendering::UserCameraPtr camera = gui::get_active_camera();

  if (_event.Dragging())
  {
    // this enables the joint maker to pan while connecting joints
    QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));
    camera->HandleMouseEvent(_event);
    return true;
  }

  rendering::VisualPtr vis = camera->GetVisual(_event.Pos());

  // Highlight visual on hover
  if (vis)
  {
    if (this->hoverVis && this->hoverVis != this->selectedVis)
      this->hoverVis->SetEmissive(common::Color(0.0, 0.0, 0.0));

    // only highlight editor links by making sure it's not an item in the
    // gui tree widget or a joint hotspot.
    rendering::VisualPtr rootVis = vis->GetRootVisual();
    if (rootVis->IsPlane())
      this->hoverVis = vis->GetParent();
    else if (!gui::get_entity_id(rootVis->GetName()) &&
        vis->GetName().find("_UNIQUE_ID_") == std::string::npos)
    {
      this->hoverVis = vis->GetParent();
      if (!this->selectedVis ||
           (this->selectedVis && this->hoverVis != this->selectedVis))
        this->hoverVis->SetEmissive(common::Color(0.5, 0.5, 0.5));
    }
  }

  // Case when a parent link is already selected and currently
  // extending the joint line to a child link
  if (this->selectedVis && this->hoverVis
      && this->mouseJoint && this->mouseJoint->line)
  {
    math::Vector3 parentPos;
    // Set end point to center of child link
    if (!this->hoverVis->IsPlane())
    {
      if (this->mouseJoint->parent)
      {
        parentPos =  this->GetLinkWorldCentroid(this->mouseJoint->parent)
            - this->mouseJoint->line->GetPoint(0);
        this->mouseJoint->line->SetPoint(1,
            this->GetLinkWorldCentroid(this->hoverVis) - parentPos);
      }
    }
    else
    {
      // Set end point to mouse plane intersection
      math::Vector3 pt;
      camera->GetWorldPointOnPlane(_event.Pos().X(), _event.Pos().Y(),
          math::Plane(math::Vector3(0, 0, 1)), pt);
      if (this->mouseJoint->parent)
      {
        parentPos = this->GetLinkWorldCentroid(this->mouseJoint->parent)
            - this->mouseJoint->line->GetPoint(0);
        this->mouseJoint->line->SetPoint(1,
            this->GetLinkWorldCentroid(this->hoverVis) - parentPos + pt);
      }
    }
  }
  return true;
}

/////////////////////////////////////////////////
void JointMaker::OnOpenInspector()
{
  if (this->inspectName.empty())
    return;

  this->OpenInspector(this->inspectName);
  this->inspectName = "";
}

/////////////////////////////////////////////////
void JointMaker::OpenInspector(const std::string &_jointId)
{
  JointData *joint = this->joints[_jointId];
  if (!joint)
  {
    gzerr << "Joint [" << _jointId << "] not found." << std::endl;
    return;
  }
  joint->OpenInspector();
}

/////////////////////////////////////////////////
bool JointMaker::OnMouseDoubleClick(const common::MouseEvent &_event)
{
  rendering::UserCameraPtr camera = gui::get_active_camera();
  rendering::VisualPtr vis = camera->GetVisual(_event.Pos());

  if (vis)
  {
    if (this->joints.find(vis->GetName()) != this->joints.end())
    {
      this->OpenInspector(vis->GetName());
      return true;
    }
  }

  return false;
}

/////////////////////////////////////////////////
bool JointMaker::OnKeyPress(const common::KeyEvent &_event)
{
  if (_event.key == Qt::Key_Delete)
  {
    if (!this->selectedJoints.empty())
    {
      for (auto jointVis : this->selectedJoints)
      {
        this->RemoveJoint(jointVis->GetName());
      }
      this->DeselectAll();
      return true;
    }
  }

  return false;
}

/////////////////////////////////////////////////
void JointMaker::OnDelete()
{
  if (this->inspectName.empty())
    return;

  this->RemoveJoint(this->inspectName);
  this->inspectName = "";
}

/////////////////////////////////////////////////
void JointMaker::CreateHotSpot(JointData *_joint)
{
  if (!_joint)
    return;

  rendering::UserCameraPtr camera = gui::get_active_camera();

  // Joint hotspot visual name is the JointId for easy access when clicking
  std::string jointId = _joint->visual->GetName() + "_UNIQUE_ID_";
  rendering::VisualPtr hotspotVisual(
      new rendering::Visual(jointId, _joint->visual, false));

  // create a cylinder to represent the joint
  hotspotVisual->InsertMesh("unit_cylinder");
  Ogre::MovableObject *hotspotObj =
      (Ogre::MovableObject*)(camera->GetScene()->GetManager()->createEntity(
      _joint->visual->GetName(), "unit_cylinder"));
  hotspotObj->getUserObjectBindings().setUserAny(Ogre::Any(jointId));
  hotspotVisual->GetSceneNode()->attachObject(hotspotObj);
  hotspotVisual->SetMaterial(this->jointMaterials[_joint->type]);
  hotspotVisual->SetTransparency(0.7);

  // create a handle at the parent end
  Ogre::BillboardSet *handleSet =
      camera->GetScene()->GetManager()->createBillboardSet(1);
  handleSet->setAutoUpdate(true);
  handleSet->setMaterialName("Gazebo/PointHandle");
  Ogre::MaterialPtr mat =
      Ogre::MaterialManager::getSingleton().getByName(
      this->jointMaterials[_joint->type]);
  Ogre::ColourValue color = mat->getTechnique(0)->getPass(0)->getDiffuse();
  color.a = 0.5;

  double linkSize = std::min(0.1,
      _joint->parent->GetBoundingBox().GetSize().GetLength()*0.05);
  linkSize = std::max(linkSize, 0.01);

  double dimension = linkSize;
  handleSet->setDefaultDimensions(dimension, dimension);
  Ogre::Billboard *parentHandle = handleSet->createBillboard(0, 0, 0);
  parentHandle->setColour(color);
  Ogre::SceneNode *handleNode =
      hotspotVisual->GetSceneNode()->createChildSceneNode();
  handleNode->attachObject(handleSet);
  handleNode->setInheritScale(false);
  handleNode->setInheritOrientation(false);
  _joint->handles = handleSet;

  hotspotVisual->SetVisibilityFlags(GZ_VISIBILITY_GUI |
      GZ_VISIBILITY_SELECTABLE);
  hotspotVisual->GetSceneNode()->setInheritScale(false);

  this->joints[jointId] = _joint;
  camera->GetScene()->AddVisual(hotspotVisual);

  _joint->hotspot = hotspotVisual;
  _joint->inspector->SetJointId(_joint->hotspot->GetName());

  std::string parentName = _joint->parent->GetName();
  std::string childName = _joint->child->GetName();

  gui::model::Events::jointInserted(jointId, _joint->name,
      jointTypes[_joint->type], parentName, childName);
}

/////////////////////////////////////////////////
void JointMaker::Update()
{
  boost::recursive_mutex::scoped_lock lock(*this->updateMutex);
  if (this->newJointCreated)
  {
    this->CreateHotSpot(this->mouseJoint);
    this->mouseJoint = NULL;
    this->newJointCreated = false;
  }

  // Update each joint
  for (auto it : this->joints)
  {
    JointData *joint = it.second;
    if (joint->hotspot)
    {
      if (joint->child && joint->parent)
      {
        bool poseUpdate = false;
        if (joint->parentPose != joint->parent->GetWorldPose() ||
            joint->childPose != joint->child->GetWorldPose() ||
            joint->childScale != joint->child->GetScale())
         {
           joint->parentPose = joint->parent->GetWorldPose();
           joint->childPose = joint->child->GetWorldPose();
           joint->childScale = joint->child->GetScale();
           poseUpdate = true;
         }

        // Create / update joint visual
        if (joint->dirty || poseUpdate)
        {
          joint->Update();
        }
      }
    }
  }
}

/////////////////////////////////////////////////
void JointMaker::AddScopedLinkName(const std::string &_name)
{
  this->scopedLinkedNames.push_back(_name);
}

/////////////////////////////////////////////////
std::string JointMaker::GetScopedLinkName(const std::string &_name)
{
  for (unsigned int i = 0; i < this->scopedLinkedNames.size(); ++i)
  {
    std::string scopedName = this->scopedLinkedNames[i];
    size_t idx = scopedName.find("::" + _name);
    if (idx != std::string::npos)
      return scopedName;
  }
  return _name;
}

/////////////////////////////////////////////////
void JointMaker::GenerateSDF()
{
  this->modelSDF.reset(new sdf::Element);
  sdf::initFile("model.sdf", this->modelSDF);
  this->modelSDF->ClearElements();

  // loop through all joints
  for (auto jointsIt : this->joints)
  {
    JointData *joint = jointsIt.second;
    sdf::ElementPtr jointElem = this->modelSDF->AddElement("joint");

    msgs::JointPtr jointMsg = joint->jointMsg;
    unsigned int axisCount = GetJointAxisCount(joint->type);
    for (unsigned int i = axisCount; i < 2u; ++i)
    {
      if (i == 0u)
        jointMsg->clear_axis1();
      else if (i == 1u)
        jointMsg->clear_axis2();
    }
    jointElem = msgs::JointToSDF(*jointMsg.get(), jointElem);

    sdf::ElementPtr parentElem = jointElem->GetElement("parent");
    std::string parentName = joint->parent->GetName();
    size_t pIdx = parentName.find("::");
    if (pIdx != std::string::npos)
      parentName = parentName.substr(pIdx+2);
    parentElem->Set(parentName);

    sdf::ElementPtr childElem = jointElem->GetElement("child");
    std::string childName = joint->child->GetName();
    size_t cIdx = childName.find("::");
    if (cIdx != std::string::npos)
      childName = childName.substr(cIdx+2);
    childElem->Set(childName);
  }
}

/////////////////////////////////////////////////
sdf::ElementPtr JointMaker::GetSDF() const
{
  return this->modelSDF;
}

/////////////////////////////////////////////////
std::string JointMaker::GetTypeAsString(JointMaker::JointType _type)
{
  std::string jointTypeStr = "";

  auto iter = jointTypes.find(_type);
  if (iter != jointTypes.end())
    jointTypeStr = iter->second;

  return jointTypeStr;
}

/////////////////////////////////////////////////
unsigned int JointMaker::GetJointAxisCount(JointMaker::JointType _type)
{
  if (_type == JOINT_FIXED)
  {
    return 0;
  }
  else if (_type == JOINT_HINGE)
  {
    return 1;
  }
  else if (_type == JOINT_HINGE2)
  {
    return 2;
  }
  else if (_type == JOINT_SLIDER)
  {
    return 1;
  }
  else if (_type == JOINT_SCREW)
  {
    return 1;
  }
  else if (_type == JOINT_UNIVERSAL)
  {
    return 2;
  }
  else if (_type == JOINT_BALL)
  {
    return 0;
  }
  else if (_type == JOINT_GEARBOX)
  {
    return 2;
  }

  return 0;
}

/////////////////////////////////////////////////
JointMaker::JointType JointMaker::GetState() const
{
  return this->jointType;
}

/////////////////////////////////////////////////
math::Vector3 JointMaker::GetLinkWorldCentroid(
    const rendering::VisualPtr _visual)
{
  math::Vector3 centroid;
  int count = 0;
  for (unsigned int i = 0; i < _visual->GetChildCount(); ++i)
  {
    if (_visual->GetChild(i)->GetName().find("_JOINT_VISUAL_") ==
        std::string::npos)
    {
      centroid += _visual->GetChild(i)->GetWorldPose().pos;
      count++;
    }
  }
  centroid /= count;
  return centroid;
}

/////////////////////////////////////////////////
unsigned int JointMaker::GetJointCount()
{
  return this->joints.size();
}

/////////////////////////////////////////////////
void JointData::OnApply()
{
  // Get data from inspector
  msgs::Joint *inspectorMsg = this->inspector->GetData();
  if (!inspectorMsg)
    return;

  this->jointMsg->CopyFrom(*inspectorMsg);

  // Name
  if (this->name != this->jointMsg->name())
    gui::model::Events::jointNameChanged(this->hotspot->GetName(),
        this->jointMsg->name());
  this->name = this->jointMsg->name();

  // Type
  this->type = JointMaker::ConvertJointType(
      msgs::ConvertJointType(this->jointMsg->type()));

  // Parent
  if (this->jointMsg->parent() != this->parent->GetName())
  {
    // Get scoped name
    std::string oldName = this->parent->GetName();
    std::string scope = oldName;
    size_t idx = oldName.rfind("::");
    if (idx != std::string::npos)
      scope = oldName.substr(0, idx+2);

    rendering::VisualPtr parentVis = gui::get_active_camera()->GetScene()
        ->GetVisual(scope + this->jointMsg->parent());
    if (parentVis)
      this->parent = parentVis;
    else
      gzwarn << "Invalid parent, keeping old parent" << std::endl;
  }

  // Child
  if (this->jointMsg->child() != this->child->GetName())
  {
    // Get scoped name
    std::string oldName = this->child->GetName();
    std::string scope = oldName;
    size_t idx = oldName.rfind("::");
    if (idx != std::string::npos)
      scope = oldName.substr(0, idx+2);

    rendering::VisualPtr childVis = gui::get_active_camera()->GetScene()
        ->GetVisual(scope + this->jointMsg->child());
    if (childVis)
    {
      this->child = childVis;
      if (this->jointVisual)
        childVis->AttachVisual(this->jointVisual);
    }
    else
      gzwarn << "Invalid child, keeping old child" << std::endl;
  }

  this->dirty = true;
  gui::model::Events::modelChanged();
}

/////////////////////////////////////////////////
void JointData::OnOpenInspector()
{
  this->OpenInspector();
}

/////////////////////////////////////////////////
void JointData::OpenInspector()
{
  this->inspector->Update(this->jointMsg);
  this->inspector->Open();
}

/////////////////////////////////////////////////
void JointData::Update()
{
  // get origin of parent link visuals
  math::Vector3 parentOrigin = this->parent->GetWorldPose().pos;

  // get origin of child link visuals
  math::Vector3 childOrigin = this->child->GetWorldPose().pos;

  // set position of joint hotspot
  math::Vector3 dPos = (childOrigin - parentOrigin);
  math::Vector3 center = dPos * 0.5;
  double length = std::max(dPos.GetLength(), 0.001);
  this->hotspot->SetScale(
      math::Vector3(0.008, 0.008, length));
  this->hotspot->SetWorldPosition(parentOrigin + center);

  // set orientation of joint hotspot
  math::Vector3 u = dPos.Normalize();
  math::Vector3 v = math::Vector3::UnitZ;
  double cosTheta = v.Dot(u);
  double angle = acos(cosTheta);
  math::Vector3 w = (v.Cross(u)).Normalize();
  math::Quaternion q;
  q.SetFromAxis(w, angle);
  this->hotspot->SetWorldRotation(q);

  // set new material if joint type has changed
  std::string material = JointMaker::jointMaterials[this->type];
  if (this->hotspot->GetMaterialName() != material)
  {
    // Note: issue setting material when there is a billboard child,
    // seems to hang so detach before setting and re-attach later.
    Ogre::SceneNode *handleNode = this->handles->getParentSceneNode();
    this->handles->detachFromParent();
    this->hotspot->SetMaterial(material);
    this->hotspot->SetTransparency(0.7);
    handleNode->attachObject(this->handles);
    Ogre::MaterialPtr mat =
        Ogre::MaterialManager::getSingleton().getByName(material);
    Ogre::ColourValue color =
        mat->getTechnique(0)->getPass(0)->getDiffuse();
    color.a = 0.5;
    this->handles->getBillboard(0)->setColour(color);

    // notify joint changes
    std::string parentName = this->parent->GetName();
    std::string childName = this->child->GetName();
    gui::model::Events::jointChanged(this->hotspot->GetName(), this->name,
        JointMaker::jointTypes[this->type], parentName, childName);
  }

  // set pos of joint handle
  this->handles->getBillboard(0)->setPosition(
      rendering::Conversions::Convert(parentOrigin -
      this->hotspot->GetWorldPose().pos));
  this->handles->_updateBounds();

  // Update msg
  msgs::JointPtr jointUpdateMsg = this->jointMsg;
  unsigned int axisCount = JointMaker::GetJointAxisCount(this->type);
  for (unsigned int i = axisCount; i < 2u; ++i)
  {
    if (i == 0u)
      jointUpdateMsg->clear_axis1();
    else if (i == 1u)
      jointUpdateMsg->clear_axis2();
  }

  // Joint visual
  if (this->jointVisual)
  {
    this->jointVisual->UpdateFromMsg(jointUpdateMsg);
  }
  else
  {
    std::string childName = this->child->GetName();
    std::string jointVisName = childName;
    size_t idx = childName.find("::");
    if (idx != std::string::npos)
      jointVisName = childName.substr(0, idx+2);
    jointVisName += "_JOINT_VISUAL_";
    gazebo::rendering::JointVisualPtr jointVis(
        new gazebo::rendering::JointVisual(jointVisName, this->child));

    jointVis->Load(jointUpdateMsg);

    this->jointVisual = jointVis;
  }

  // Line now connects the child link to the joint frame
  this->line->SetPoint(0, this->child->GetWorldPose().pos
      - this->child->GetParent()->GetWorldPose().pos);
  this->line->SetPoint(1,
      this->jointVisual->GetWorldPose().pos
      - this->child->GetParent()->GetWorldPose().pos);
  this->line->setMaterial(JointMaker::jointMaterials[this->type]);
  this->dirty = false;
}

/////////////////////////////////////////////////
void JointMaker::ShowContextMenu(const std::string &_name)
{
  auto it = this->joints.find(_name);
  if (it == this->joints.end())
    return;

  QMenu menu;
  if (this->inspectAct)
    menu.addAction(this->inspectAct);

  this->inspectName = _name;
  QAction *deleteAct = new QAction(tr("Delete"), this);
  connect(deleteAct, SIGNAL(triggered()), this, SLOT(OnDelete()));
  menu.addAction(deleteAct);

  menu.exec(QCursor::pos());
}

/////////////////////////////////////////////////
void JointMaker::OnSetSelectedEntity(const std::string &/*_name*/,
    const std::string &/*_mode*/)
{
  this->DeselectAll();
}

/////////////////////////////////////////////////
void JointMaker::OnSetSelectedJoint(const std::string &_name,
    const bool _selected)
{
  this->SetSelected(_name, _selected);
}

/////////////////////////////////////////////////
void JointMaker::SetSelected(const std::string &_name,
    const bool _selected)
{
  auto it = this->joints.find(_name);
  if (it == this->joints.end())
    return;

  this->SetSelected((*it).second->hotspot, _selected);
}

/////////////////////////////////////////////////
void JointMaker::SetSelected(rendering::VisualPtr _jointVis,
    const bool _selected)
{
  if (!_jointVis)
    return;

  _jointVis->SetHighlighted(_selected);
  auto it = std::find(this->selectedJoints.begin(),
      this->selectedJoints.end(), _jointVis);
  if (_selected)
  {
    if (it == this->selectedJoints.end())
    {
      this->selectedJoints.push_back(_jointVis);
      model::Events::setSelectedJoint(_jointVis->GetName(), _selected);
    }
  }
  else
  {
    if (it != this->selectedJoints.end())
    {
      this->selectedJoints.erase(it);
      model::Events::setSelectedJoint(_jointVis->GetName(), _selected);
    }
  }
}

/////////////////////////////////////////////////
void JointMaker::DeselectAll()
{
  while (!this->selectedJoints.empty())
  {
    rendering::VisualPtr vis = this->selectedJoints[0];
    vis->SetHighlighted(false);
    this->selectedJoints.erase(this->selectedJoints.begin());
    model::Events::setSelectedJoint(vis->GetName(), false);
  }
}

/////////////////////////////////////////////////
void JointMaker::CreateJointFromSDF(sdf::ElementPtr _jointElem,
    const std::string &_modelName)
{
  msgs::Joint jointMsg = msgs::JointFromSDF(_jointElem);

  // Parent
  std::string parentName = _modelName + "::" + jointMsg.parent();
  rendering::VisualPtr parentVis =
      gui::get_active_camera()->GetScene()->GetVisual(parentName);

  // Child
  std::string childName = _modelName + "::" + jointMsg.child();
  rendering::VisualPtr childVis =
      gui::get_active_camera()->GetScene()->GetVisual(childName);

  if (!parentVis || !childVis)
  {
    gzerr << "Unable to load joint. Joint child / parent not found"
        << std::endl;
    return;
  }

  JointData *joint = new JointData();
  joint->name = jointMsg.name();
  joint->parent = parentVis;
  joint->child = childVis;
  joint->type = this->ConvertJointType(msgs::ConvertJointType(jointMsg.type()));
  std::string jointVisName = _modelName + "::" + joint->name;

  joint->jointMsg.reset(new msgs::Joint);
  joint->jointMsg->CopyFrom(jointMsg);
  joint->jointMsg->set_parent_id(joint->parent->GetId());
  joint->jointMsg->set_child_id(joint->child->GetId());

  // Inspector
  joint->inspector = new JointInspector(this);
  joint->inspector->Update(joint->jointMsg);
  joint->inspector->setModal(false);
  connect(joint->inspector, SIGNAL(Applied()), joint, SLOT(OnApply()));

  // Visuals
  rendering::VisualPtr jointVis(
      new rendering::Visual(jointVisName, parentVis->GetParent()));
  jointVis->Load();
  rendering::DynamicLines *jointLine =
      jointVis->CreateDynamicLine(rendering::RENDERING_LINE_LIST);

  math::Vector3 origin = parentVis->GetWorldPose().pos
      - parentVis->GetParent()->GetWorldPose().pos;
  jointLine->AddPoint(origin);
  jointLine->AddPoint(origin + math::Vector3(0, 0, 0.1));

  jointVis->GetSceneNode()->setInheritScale(false);
  jointVis->GetSceneNode()->setInheritOrientation(false);
  joint->visual = jointVis;
  joint->line = jointLine;
  joint->dirty = true;

  this->CreateHotSpot(joint);
}

/////////////////////////////////////////////////
void JointMaker::OnLinkInserted(const std::string &_linkName)
{
  std::string leafName = _linkName;
  size_t idx = _linkName.rfind("::");
  if (idx != std::string::npos)
    leafName = _linkName.substr(idx+2);

  this->linkList[_linkName] = leafName;

  this->EmitLinkInserted(_linkName);
}

/////////////////////////////////////////////////
void JointMaker::OnLinkRemoved(const std::string &_linkName)
{
  if (this->linkList.erase(_linkName))
    this->EmitLinkRemoved(_linkName);
}

/////////////////////////////////////////////////
std::map<std::string, std::string> JointMaker::LinkList() const
{
  return this->linkList;
}

/////////////////////////////////////////////////
void JointMaker::ShowJoints(bool _show)
{
  for (auto iter : this->joints)
  {
    rendering::VisualPtr vis = iter.second->hotspot;
    if (vis)
    {
      vis->SetVisible(_show);
      vis->SetHighlighted(false);
    }
    if (iter.second->jointVisual)
      iter.second->jointVisual->SetVisible(_show);
  }
  this->DeselectAll();
}

max_stars_repo_name: shyamalschandra/gazebo-official

max_issues_repo_name: shyamalschandra/gazebo-official

max_forks_repo_name: shyamalschandra/gazebo-official


text:
#include <string>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <boost/filesystem.hpp>

#include "res2h.h"
#include "res2hutils.hpp"

struct FileData {
	boost::filesystem::path inPath;
	boost::filesystem::path outPath;
	std::string internalName;
	std::string dataVariableName;
	std::string sizeVariableName;
	size_t size;
};

bool beVerbose = false;
bool useRecursion = false;
bool useC = false;
bool createBinary = false;
bool appendFile = false;
bool combineResults = false;
boost::filesystem::path commonHeaderFilePath;
boost::filesystem::path utilitiesFilePath;
boost::filesystem::path inFilePath;
boost::filesystem::path outFilePath;

std::ofstream badOfStream; //we need this later as a default parameter...

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

//This is based on the example code found here: https://svn.boost.org/trac/boost/ticket/1976
//but changed to not return a trailing ".." when paths only differ in their file name.
//The function still seems to be missing in boost as of 1.54.0.
boost::filesystem::path naiveUncomplete(boost::filesystem::path const path, boost::filesystem::path const base)
{
    if (path.has_root_path()) {
        if (path.root_path() != base.root_path()) {
            return path;
        } else {
            return naiveUncomplete(path.relative_path(), base.relative_path());
        }
    } else {
        if (base.has_root_path()) {
            return path;
        } else {
            auto path_it = path.begin();
            auto base_it = base.begin();
            while ( path_it != path.end() && base_it != base.end() ) {
                if (*path_it != *base_it) break;
                ++path_it; ++base_it;
            }
            boost::filesystem::path result;
			//check if we're at the filename of the base path already
            if (*base_it != base.filename()) {
				//add trailing ".." from path to base, but only if we're not already at the filename of the base path
                for (; base_it != base.end() && *base_it != base.filename(); ++base_it) {
                    result /= "..";
                }
            }
            for (; path_it != path.end(); ++path_it) {
                result /= *path_it;
            }
            return result;
        }
    }
	return path;
}

bool makeCanonical(boost::filesystem::path & result, const boost::filesystem::path & path)
{
    //if we use canonical the file must exits, else we get an exception.
    try {
        result = boost::filesystem::canonical(path);
    }
    catch(...) {
        //an error occurred. this maybe because the file is not there yet. try without the file name
        try {
            result = boost::filesystem::canonical(boost::filesystem::path(path).remove_filename());
            //ok. this worked. add file name again
            result /= path.filename();
        }
        catch (...) {
            //hmm. didn't work. tell the user. at least the path should be there...
            std::cout << "The path \"" << boost::filesystem::path(path).remove_filename().string() << "\" couldn't be found. Please create it." << std::endl;
            return false;
        }
    }
    return true;
}

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

void printVersion()
{
	std::cout << "res2h " << RES2H_VERSION_STRING << " - Load plain binary data and dump to a raw C/C++ array." << std::endl << std::endl;
}

void printUsage()
{
    std::cout << std::endl;
	std::cout << "Usage: res2h <infile/indir> <outfile/outdir> [options]" << std::endl;
	std::cout << "Valid options:" << std::endl;
	std::cout << "-s Recurse into subdirectories below indir." << std::endl;
	std::cout << "-c Use .c files and arrays for storing the data definitions, else" << std::endl << "    uses .cpp files and std::vector/std::map." << std::endl;
	std::cout << "-h <headerfile> Puts all declarations in a common \"headerfile\" using \"extern\"" << std::endl << "    and includes that header file in the source files." << std::endl;
	std::cout << "-u <sourcefile> Create utility functions and arrays in a .c/.cpp file." << std::endl << "    Only makes sense in combination with -h" << std::endl;
    std::cout << "-1 Combine all converted files into one big .c/.cpp file (use with -u)." << std::endl;
    std::cout << "-b Compile binary archive outfile containing all infile(s). For reading in your" << std::endl << "    software include res2hinterface.h/.c/.cpp (depending on -c) and consult the docs." << std::endl;
	std::cout << "-a Append infile to outfile. Can be used to append an archive to an executable." << std::endl;
	std::cout << "-v Be verbose." << std::endl;
    std::cout << "Examples:" << std::endl;
    std::cout << "res2h ./lenna.png ./resources/lenna_png.cpp (convert single file)" << std::endl;
    std::cout << "res2h ./data ./resources -s -h resources.h -u resources.cpp (convert directory)" << std::endl;
    std::cout << "res2h ./data ./resources/data.bin -b (convert directory to binary file)" << std::endl;
	std::cout << "res2h ./resources/data.bin ./program.exe -a (append archive to executable)" << std::endl;
}

bool readArguments(int argc, const char * argv[])
{
	bool pastFiles = false;
	for(int i = 1; i < argc; ++i) {
		//read argument from list
		std::string argument = argv[i];
		//check what it is
		if (argument == "-a") {
            if (!commonHeaderFilePath.empty() || !utilitiesFilePath.empty()) {
                std::cout << "Error: Option -a can not be combined with -h or -u!" << std::endl;
				return false;
            }
			else if (createBinary) {
                std::cout << "Error: Option -a can not be combined with -b!" << std::endl;
				return false;
			}
            else if (combineResults) {
                std::cout << "Error: Option -a can not be combined with -1!" << std::endl;
				return false;
			}
			appendFile = true;
			pastFiles = true;
		}
        else if (argument == "-1") {
            //-u must be used for this to work. check if specified
            for(int j = 1; j < argc; ++j) {
                //read argument from list
                std::string argument = argv[j];
                if (argument == "-u") {
                    combineResults = true;
                    pastFiles = true;
                    break;
                }
            }
            if (!combineResults) {
                //-u not specified. complain to user.
                std::cout << "Error: Option -1 has to be combined with -u!" << std::endl;
                return false;
            }
        }
        else if (argument == "-b") {
            if (!commonHeaderFilePath.empty() || !utilitiesFilePath.empty()) {
                std::cout << "Error: Option -b can not be combined with -h or -u!" << std::endl;
				return false;
            }
			else if (appendFile) {
                std::cout << "Error: Option -b can not be combined with -a!" << std::endl;
				return false;
			}
            else if (combineResults) {
                std::cout << "Warning: Creating binary archive. Option -1 ignored!" << std::endl;
				return false;
			}
            createBinary = true;
			pastFiles = true;
		}
		else if (argument == "-c") {
			useC = true;
			pastFiles = true;
		}
        else if (argument == "-s") {
			useRecursion = true;
			pastFiles = true;
		}
        else if (argument == "-v") {
			beVerbose = true;
			pastFiles = true;
		}
		else if (argument == "-h") {
            if (createBinary) {
                std::cout << "Error: Option -h can not be combined with -b!" << std::endl;
				return false;
            }
			else if (appendFile) {
                std::cout << "Error: Option -h can not be combined with -a!" << std::endl;
				return false;
			}
			//try getting next argument as header file name
			i++;
			if (i < argc && argv[i] != nullptr) {
                if (!makeCanonical(commonHeaderFilePath, boost::filesystem::path(argv[i]))) {
                    return false;
                }
			}
			else {
				std::cout << "Error: Option -h specified, but no file name found!" << std::endl;
				return false;
			}
			pastFiles = true;
		}
		else if (argument == "-u") {
            if (createBinary) {
                std::cout << "Error: Option -u can not be combined with -b!" << std::endl;
				return false;
            }
			else if (appendFile) {
                std::cout << "Error: Option -u can not be combined with -a!" << std::endl;
				return false;
			}
			//try getting next argument as utility file name
			i++;
			if (i < argc && argv[i] != nullptr) {
                if (!makeCanonical(utilitiesFilePath, boost::filesystem::path(argv[i]))) {
                    return false;
                }
			}
			else {
				std::cout << "Error: Option -u specified, but no file name found!" << std::endl;
				return false;
			}
			if (!utilitiesFilePath.empty() && commonHeaderFilePath.empty()) {
				std::cout << "Warning: -u does not make much sense without -h..." << std::endl;
			}
			pastFiles = true;
		}
		//none of the options was matched until here...
		else if (!pastFiles) {
			//if no files/directories have been found yet this is probably a file/directory
			if (inFilePath.empty()) {
                if (!makeCanonical(inFilePath, boost::filesystem::path(argument))) {
                    return false;
                }
			}
			else if (outFilePath.empty()) {
				if (!makeCanonical(outFilePath, boost::filesystem::path(argument))) {
                    return false;
                }
				pastFiles = true;
			}
		}
		else {
			std::cout << "Error: Unknown argument \"" << argument << "\"!" << std::endl;
			return false;
		}
	}
	return true;
}

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

std::vector<FileData> getFileDataFrom(const boost::filesystem::path & inPath, const boost::filesystem::path & outPath, const boost::filesystem::path & parentDir, const bool recurse)
{
	//get all files from directory
	std::vector<FileData> files;
	//check for infinite symlinks
	if(boost::filesystem::is_symlink(inPath)) {
		//check if the symlink points somewhere in the path. this would recurse
		if(inPath.string().find(boost::filesystem::canonical(inPath).string()) == 0) {
			std::cout << "Warning: Path " << inPath << " contains recursive symlink! Skipping." << std::endl;
			return files;
		}
	}
	//iterate through source directory searching for files
	const boost::filesystem::directory_iterator dirEnd;
	for (boost::filesystem::directory_iterator fileIt(inPath); fileIt != dirEnd; ++fileIt) {
		boost::filesystem::path filePath = (*fileIt).path();
		if (!boost::filesystem::is_directory(filePath)) {
			if (beVerbose) {
				std::cout << "Found input file " << filePath << std::endl;
			}
			//add file to list
			FileData temp;
			temp.inPath = filePath;
			//replace dots in file name with '_' and add a .c/.cpp extension
			std::string newFileName = filePath.filename().generic_string();
			std::replace(newFileName.begin(), newFileName.end(), '.', '_');
			if (useC) {
				newFileName.append(".c");
			}
			else {
				newFileName.append(".cpp");
			}
            //remove parent directory of file from path for internal name. This could surely be done in a safer way
            boost::filesystem::path subPath(filePath.generic_string().substr(parentDir.generic_string().size() + 1));
            //add a ":/" before the name to mark internal resources (Yes. Hello Qt!)
            temp.internalName = ":/" + subPath.generic_string();
            //add subdir below parent path to name to enable multiple files with the same name
            std::string subDirString(subPath.remove_filename().generic_string());
            if (!subDirString.empty()) {
                //replace dir separators by underscores
                std::replace(subDirString.begin(), subDirString.end(), '/', '_');
                //add in front of file name
                newFileName = subDirString + "_" + newFileName;
            }
            //build new output file name
            temp.outPath = outPath / newFileName;
			if (beVerbose) {
				std::cout << "Internal name will be \"" << temp.internalName << "\"" << std::endl;
				std::cout << "Output path is " << temp.outPath << std::endl;
			}
			//get file size
			try {
				temp.size = (size_t)boost::filesystem::file_size(filePath);
				if (beVerbose) {
					std::cout << "Size is " << temp.size << " bytes." << std::endl;
				}
			}
			catch(...) {
				std::cout << "Error: Failed to get size of " << filePath << "!" << std::endl;
				temp.size = 0;
			}
			//add file to list
			files.push_back(temp);
		}
	}
	//does the user want subdirectories?
	if (recurse) {
		//iterate through source directory again searching for directories
		for (boost::filesystem::directory_iterator dirIt(inPath); dirIt != dirEnd; ++dirIt) {
			boost::filesystem::path dirPath = (*dirIt).path();
			if (boost::filesystem::is_directory(dirPath)) {
				if (beVerbose) {
					std::cout << "Found subdirectory " << dirPath << std::endl;
				}
				//subdirectory found. recurse.
				std::vector<FileData> subFiles = getFileDataFrom(dirPath, outPath, parentDir, recurse);
				//add returned result to file list
				files.insert(files.end(), subFiles.cbegin(), subFiles.cend());
			}
		}
	}
	//return result
	return files;
}

bool convertFile(FileData & fileData, const boost::filesystem::path & commonHeaderPath, std::ofstream & outStream = badOfStream, bool addHeader = true)
{
	if (boost::filesystem::exists(fileData.inPath)) {
		//try to open the input file
		std::ifstream inStream;
		inStream.open(fileData.inPath.string(), std::ifstream::in | std::ifstream::binary);
		if (inStream.is_open() && inStream.good()) {
			if (beVerbose) {
				std::cout << "Converting input file " << fileData.inPath;
			}
			//try getting size of data
			inStream.seekg(0, std::ios::end);
			fileData.size = (size_t)inStream.tellg();
			inStream.seekg(0);
            //check if the caller passed and output stream and use that
            bool closeOutStream = false;
            if (!outStream.is_open() || !outStream.good()) {
                if (!fileData.outPath.empty()) {
                    //try opening the output stream. truncate it when it exists
                    outStream.open(fileData.outPath.string(), std::ofstream::out | std::ofstream::trunc);
                }
                else {
                    std::cout << "Error: No output stream passed, but output path for \"" << fileData.inPath.filename().string() << "\" is empty! Skipping." << std::endl;
                    return false;
                }
                closeOutStream = true;
            }
            //now write to stream
			if (outStream.is_open() && outStream.good()) {
                //check if caller want to add a header
                if (addHeader) {
                    //add message
                    outStream << "//this file was auto-generated from \"" << fileData.inPath.filename().string() << "\" by res2h" << std::endl << std::endl;
                    //add header include
                    if (!commonHeaderPath.empty()) {
                        //common header path must be relative to destination directory
                        boost::filesystem::path relativeHeaderPath = naiveUncomplete(commonHeaderPath, fileData.outPath);
                        outStream << "#include \"" << relativeHeaderPath.generic_string() << "\"" << std::endl << std::endl;
                    }
                }
				//create names for variables
				fileData.dataVariableName = fileData.outPath.filename().stem().string() + "_data";
				fileData.sizeVariableName = fileData.outPath.filename().stem().string() + "_size";
				//add size and data variable
				outStream << "const size_t " << fileData.sizeVariableName << " = " << std::dec << fileData.size << ";" << std::endl;
				outStream << "const unsigned char " << fileData.dataVariableName << "[" << std::dec << fileData.size << "] = {" << std::endl;
				outStream << "    "; //first indent
				//now add content
				size_t breakCounter = 0;
				while (!inStream.eof()) {
					//read byte from source
					unsigned char dataByte;
					inStream.read((char *)&dataByte, 1);
					//check if we have actually read something
					if (inStream.gcount() != 1 || inStream.eof()) {
						//we failed to read. break the read loop and close the file.
						break;
					}
					//write to destination in hex with a width of 2 and '0' as padding
                    //we do not use showbase as it doesn't work with zero values
                    outStream << "0x" << std::setw(2) << std::setfill('0') << std::hex << (unsigned int)dataByte;
					//was this the last character?
					if (!inStream.eof() && fileData.size > (size_t)inStream.tellg()) {
						//no. add comma.
						outStream << ",";
						//add break after 10 bytes and add indent again
						if (++breakCounter % 10 == 0) {
							outStream << std::endl << "    ";
						}
					}
				}
				//close curly braces
				outStream << std::endl << "};" << std::endl << std::endl;
				//close files
                if (closeOutStream) {
				    outStream.close();
                }
				inStream.close();
				if (beVerbose) {
					std::cout << " - succeeded." << std::endl;
				}
				return true;
			}
			else {
				std::cout << "Error: Failed to open file \"" << fileData.outPath.string() << "\" for writing!" << std::endl;
				return false;
			}
		}
		else {
			std::cout << "Error: Failed to open file \"" << fileData.inPath.string() << "\" for reading!" << std::endl;
			return false;
		}
	}
	else {
		std::cout << "Error: File \"" << fileData.inPath.string() << "\" does not exist!" << std::endl;
	}
	return false;
}

bool createCommonHeader(const std::vector<FileData> & fileList, const boost::filesystem::path & commonHeaderPath, bool addUtilityFunctions = false, bool useCConstructs = false)
{
	//try opening the output file. truncate it when it exists
	std::ofstream outStream;
    outStream.open(commonHeaderPath.generic_string(), std::ofstream::out | std::ofstream::trunc);
	if (outStream.is_open() && outStream.good()) {
		if (beVerbose) {
			std::cout << std::endl << "Creating common header " << commonHeaderPath;
		}
		//add message
		outStream << "//this file was auto-generated by res2h" << std::endl << std::endl;
		//add #pragma to only include once
		outStream << "#pragma once" << std::endl << std::endl;
		//add includes for C++
		if (!useCConstructs) {
			outStream << "#include <string>" << std::endl;
			if (addUtilityFunctions) {
			    outStream << "#include <map>" << std::endl;
            }
            outStream << std::endl;
		}
		//add all files
		for (auto fdIt = fileList.cbegin(); fdIt != fileList.cend(); ++fdIt) {
			//add size and data variable
			outStream << "extern const size_t " << fdIt->sizeVariableName << ";" << std::endl;
			outStream << "extern const unsigned char " << fdIt->dataVariableName << "[];" << std::endl << std::endl;
		}
		//if we want utilities, add array
		if (addUtilityFunctions) {
			//add resource struct
			outStream << "struct Res2hEntry {" << std::endl;
			if (useCConstructs) {
				outStream << "    const char * relativeFileName;" << std::endl;
			}
			else {
				outStream << "    const std::string relativeFileName;" << std::endl;
			}
			outStream << "    const size_t size;" << std::endl;
			outStream << "    const unsigned char * data;" << std::endl;
			outStream << "};" << std::endl << std::endl;
			//add list holding files
            outStream << "extern const size_t res2hNrOfFiles;" << std::endl;
			outStream << "extern const Res2hEntry res2hFiles[];" << std::endl << std::endl;
			if (!useCConstructs) {
                //add additional std::map if C++
                outStream << "typedef const std::map<const std::string, const Res2hEntry> res2hMapType;" << std::endl;
				outStream << "extern res2hMapType res2hMap;" << std::endl;
			}
		}
		//close file
		outStream.close();
		if (beVerbose) {
			std::cout << " - succeeded." << std::endl;
		}
		return true;
	}
	else {
		std::cout << "Error: Failed to open file \"" << commonHeaderPath << "\" for writing!" << std::endl;
	}
	return true;
}

bool createUtilities(std::vector<FileData> & fileList, const boost::filesystem::path & utilitiesPath, const boost::filesystem::path & commonHeaderPath, bool useCConstructs = false, bool addFileData = false)
{
	//try opening the output file. truncate it when it exists
	std::ofstream outStream;
	outStream.open(utilitiesPath.generic_string(), std::ofstream::out | std::ofstream::trunc);
	if (outStream.is_open() && outStream.good()) {
		if (beVerbose) {
			std::cout << std::endl << "Creating utilities file " << utilitiesPath;
		}
		//add message
		outStream << "//this file was auto-generated by res2h" << std::endl << std::endl;
		//create path to include file RELATIVE to this file
		boost::filesystem::path relativePath = naiveUncomplete(commonHeaderPath, utilitiesPath);
		//include header file
		outStream << "#include \"" << relativePath.string() << "\"" << std::endl << std::endl;
        //if the data should go to this file too, add it
        if (addFileData) {
            for (auto fdIt = fileList.begin(); fdIt != fileList.cend(); ++fdIt) {
                if (!convertFile(*fdIt, commonHeaderFilePath, outStream, false)) {
                    std::cout << "Error: Failed to convert all files. Aborting!" << std::endl;
                    outStream.close();
                    return false;
                }
            }
        }
		//begin data arrays. switch depending wether C or C++
        outStream << "const size_t res2hNrOfFiles = " << fileList.size() << ";" << std::endl;
        //add files
        outStream << "const Res2hEntry res2hFiles[res2hNrOfFiles] = {" << std::endl;
        outStream << "    "; //first indent
        for (auto fdIt = fileList.cbegin(); fdIt != fileList.cend();) {
            outStream << "{\"" << fdIt->internalName << "\", " << fdIt->sizeVariableName << ", " << fdIt->dataVariableName << "}";
            //was this the last entry?
            ++fdIt;
            if (fdIt != fileList.cend()) {
                //no. add comma.
                outStream << ",";
                //add break after every entry and add indent again
                outStream << std::endl << "    ";
            }
        }
        outStream << std::endl << "};" << std::endl;
		if (!useCConstructs) {
			//add files to map
			outStream << std::endl << "res2hMapType::value_type mapTemp[] = {" << std::endl;
			outStream << "    ";
			for (auto fdIt = fileList.cbegin(); fdIt != fileList.cend();) {
				outStream << "std::make_pair(\"" << fdIt->internalName << "\", res2hFiles[" << (fdIt - fileList.cbegin()) << "])";
				//was this the last entry?
				++fdIt;
				if (fdIt != fileList.cend()) {
					//no. add comma.
					outStream << ",";
					//add break after every entry and add indent again
					outStream << std::endl << "    ";
				}
			}
			outStream << std::endl << "};" << std::endl << std::endl;
            //create map
            outStream << "res2hMapType res2hMap(mapTemp, mapTemp + sizeof mapTemp / sizeof mapTemp[0]);" << std::endl;
		}
		//close file
		outStream.close();
		if (beVerbose) {
			std::cout << " - succeeded." << std::endl;
		}
		return true;
	}
	else {
		std::cout << "Error: Failed to open file \"" << utilitiesPath << "\" for writing!" << std::endl;
	}
	return true;
}

//Blob file format:
//Offset         | Type     | Description
//---------------+----------+-------------------------------------------
//START          | char[8]  | magic number string "res2hbin"
//08             | uint32_t | file format version number (currently 1)
//12             | uint32_t | format flags or other crap for file (currently 0)
//16             | uint32_t | size of whole archive including checksum in bytes
//20             | uint32_t | number of directory and file entries following
//Then follows the directory:
//24 + 00        | uint32_t | file entry #0, size of internal name INCLUDING null-terminating character
//24 + 04        | char[]   | file entry #0, internal name (null-terminated)
//24 + 04 + name | uint32_t | file entry #0, format flags for entry (currently 0)
//24 + 08 + name | uint32_t | file entry #0, size of data
//24 + 12 + name | uint32_t | file entry #0, absolute offset of data in file
//24 + 16 + name | uint32_t | file entry #0, Adler-32 (RFC1950) checksum of data
//Then follow the other directory entries.
//Directly after the directory the data blocks begin.
//END - 04       | uint32_t | Adler-32 (RFC1950) checksum of whole file up to this point
//Obviously this limits you to ~4GB for the whole binary file and ~4GB per data entry. Go cry about it...
//There is some redundant information here, but that's for reading stuff faster.
//Also the version and dummy fields might be needed in later versions...
bool createBlob(const std::vector<FileData> & fileList, const boost::filesystem::path & filePath)
{
    //try opening the output file. truncate it when it exists
    std::fstream outStream;
    outStream.open(filePath.string(), std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);
    if (outStream.is_open() && outStream.good()) {
		if (beVerbose) {
			std::cout << std::endl << "Creating binary archive " << filePath << std::endl;
		}
        //add magic number
        const unsigned char magicBytes[9] = RES2H_MAGIC_BYTES;
        outStream.write(reinterpret_cast<const char *>(&magicBytes), sizeof(magicBytes) - 1);
		//add version and format flag
		const uint32_t fileVersion = RES2H_ARCHIVE_VERSION;
		const uint32_t fileFlags = 0;
		outStream.write(reinterpret_cast<const char *>(&fileVersion), sizeof(uint32_t));
		outStream.write(reinterpret_cast<const char *>(&fileFlags), sizeof(uint32_t));
		//add dummy archive size
		uint32_t archiveSize = 0;
		outStream.write(reinterpret_cast<const char *>(&archiveSize), sizeof(uint32_t));
		//add number of directory entries
		const uint32_t nrOfEntries = fileList.size();
		outStream.write(reinterpret_cast<const char *>(&nrOfEntries), sizeof(uint32_t));
		//skip through files calculating data start offset behind directory
		size_t dataStart = RES2H_OFFSET_DIR_START;
		for (auto fdIt = fileList.cbegin(); fdIt != fileList.cend(); ++fdIt) {
			//calculate size of entry and to entry start adress
			dataStart += 20 + fdIt->internalName.size() + 1;
		}
        //add directory for all files
		for (auto fdIt = fileList.cbegin(); fdIt != fileList.cend(); ++fdIt) {
			//add size of name
			const uint32_t nameSize = fdIt->internalName.size() + 1;
			outStream.write(reinterpret_cast<const char *>(&nameSize), sizeof(uint32_t));
			//add name and null-termination
			outStream << fdIt->internalName << '\0';
			//add flags
			const uint32_t entryFlags = 0;
			outStream.write(reinterpret_cast<const char *>(&entryFlags), sizeof(uint32_t));
			//add data size
			outStream.write(reinterpret_cast<const char *>(&fdIt->size), sizeof(uint32_t));
			//add offset from file start to start of data
			outStream.write(reinterpret_cast<const char *>(&dataStart), sizeof(uint32_t));
			//add checksum of data
			const uint32_t checksum = calculateAdler32(fdIt->inPath.string());
			outStream.write(reinterpret_cast<const char *>(&checksum), sizeof(uint32_t));
			if (beVerbose) {
				std::cout << "Creating directory entry for \"" << fdIt->internalName << "\"" << std::endl;
				std::cout << "Size is " << fdIt->size << " bytes." << std::endl;
				std::cout << "Data starts at " << std::hex << std::showbase << dataStart << std::endl;
				std::cout << "Adler-32 checksum is " << std::hex << std::showbase << checksum << std::endl;
			}
			//now add size of this entrys data to start offset for next data block
			dataStart += fdIt->size;
		}
		//add data for all files
		for (auto fdIt = fileList.cbegin(); fdIt != fileList.cend(); ++fdIt) {
			//try to open file
			std::ifstream inStream;
			inStream.open(fdIt->inPath.string(), std::ifstream::in | std::ifstream::binary);
			if (inStream.is_open() && inStream.good()) {
				if (beVerbose) {
					std::cout << "Adding data for \"" << fdIt->internalName << "\"" << std::endl;
				}
				std::streamsize overallDataSize = 0;
				//copy data from input to output file
				while (!inStream.eof() && inStream.good()) {
					unsigned char buffer[1024];
					std::streamsize readSize = sizeof(buffer);
					try {
						//try reading data from input file
						inStream.read(reinterpret_cast<char *>(&buffer), sizeof(buffer));
					}
					catch (std::ios_base::failure) { /*ignore read failure. salvage what we can.*/ }
					//store how many bytes were actually read
					readSize = inStream.gcount();
					//write to output file
					outStream.write(reinterpret_cast<const char *>(&buffer), readSize);
					//increate size of overall data read
					overallDataSize += readSize;
				}
				//close input file
				inStream.close();
				//check if the file was completely read
				if (overallDataSize != fdIt->size) {
					std::cout << "Error: Failed to completely copy file \"" << fdIt->inPath.string() << "\" to binary data!" << std::endl;
					outStream.close();
					return false;
				}
			}
			else {
				std::cout << "Error: Failed to open file \"" << fdIt->inPath.string() << "\" for reading!" << std::endl;
				outStream.close();
				return false;
			}
		}
		//final archive size is current size + checksum. write size to the header now
		archiveSize = (uint32_t)outStream.tellg() + sizeof(uint32_t);
		outStream.seekg(RES2H_OFFSET_ARCHIVE_SIZE);
		outStream.write(reinterpret_cast<const char *>(&archiveSize), sizeof(uint32_t));
        //close file
        outStream.close();
		if (beVerbose) {
			std::cout << "Binary archive creation succeeded." << std::endl;
		}
		//calculate checksum of whole file
		const uint32_t adler32 = calculateAdler32(filePath.string());
		//open file again, move to end of file and append checksum
		outStream.open(filePath.string(), std::ofstream::out | std::ofstream::binary | std::ofstream::app);
		if (outStream.is_open() && outStream.good()) {
			outStream.seekg(0, std::ios::end);
			outStream.write(reinterpret_cast<const char *>(&adler32), sizeof(uint32_t));
			//close file
			outStream.close();
		}
		else {
			std::cout << "Error: Failed to open file \"" << filePath.string() << "\" for writing!" << std::endl;
			return false;
		}
		if (beVerbose) {
			std::cout << "Archive checksum is " << std::hex << std::showbase << adler32 << "." << std::endl;
		}
        return true;
    }
    else {
        std::cout << "Error: Failed to open file \"" << filePath.string() << "\" for writing!" << std::endl;
        return false;
    }
	return false;
}

bool appendAtoB(const boost::filesystem::path & destinationPath, const boost::filesystem::path & sourcePath)
{
	//try opening the output file.
    std::fstream outStream;
    outStream.open(destinationPath.string(), std::ofstream::out | std::ofstream::binary | std::ofstream::app);
    if (outStream.is_open() && outStream.good()) {
		if (beVerbose) {
			std::cout << std::endl << "Opened output file " << destinationPath << std::endl;
		}
		//seek to the end
		outStream.seekg(0, std::ios::end);
		//open input file
		std::ifstream inStream;
		inStream.open(sourcePath.string(), std::ifstream::in | std::ifstream::binary);
		if (inStream.is_open() && inStream.good()) {
			if (beVerbose) {
				std::cout << "Opened input file \"" << sourcePath << "\". Appending data to output." << std::endl;
			}
			//copy data from input to output file
			while (!inStream.eof() && inStream.good()) {
				unsigned char buffer[1024];
				std::streamsize readSize = sizeof(buffer);
				try {
					//try reading data from input file
					inStream.read(reinterpret_cast<char *>(&buffer), sizeof(buffer));
				}
				catch (std::ios_base::failure) { /*ignore read failure. salvage what we can.*/ }
				//store how many bytes were actually read
				readSize = inStream.gcount();
				//write to output file
				outStream.write(reinterpret_cast<const char *>(&buffer), readSize);
			}
			//close input file
			inStream.close();
		}
		else {
			std::cout << "Error: Failed to open input file \"" << sourcePath.string() << "\" for reading!" << std::endl;
			outStream.close();
			return false;
		}
		//close output file
		outStream.close();
		return true;
	}
	else {
		std::cout << "Error: Failed to open output file \"" << destinationPath.string() << "\" for writing!" << std::endl;
	}
	return false;
}

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

int main(int argc, const char * argv[])
{
	printVersion();

	//check number of arguments and if all arguments can be read
	if(argc < 3 || !readArguments(argc, argv)) {
		printUsage();
		return -1;
	}

	//check if the input path exist
	if (!boost::filesystem::exists(inFilePath)) {
		std::cout << "Error: Invalid input file/directory \"" << inFilePath.string() << "\"!" << std::endl;
		return -2;
	}

    if (createBinary) {
        //check if argument 2 is a file
        if (boost::filesystem::is_directory(outFilePath)) {
            std::cout << "Error: Output must be a file if -b is used!" << std::endl;
            return -2;
        }
    }
	else if (appendFile) {
		//check if argument 2 is a file
        if (boost::filesystem::is_directory(outFilePath)) {
            std::cout << "Error: Output must be a file if -a is used!" << std::endl;
            return -2;
        }
	}
    else if (boost::filesystem::is_directory(inFilePath) != boost::filesystem::is_directory(outFilePath)) {
        //check if output directory exists
        if (boost::filesystem::is_directory(outFilePath) && !boost::filesystem::exists(outFilePath)) {
            std::cout << "Error: Invalid output directory \"" << outFilePath.string() << "\"!" << std::endl;
            return -2;
        }
        //check if arguments 1 and 2 are both files or both directories
		std::cout << "Error: Input and output file must be both either a file or a directory!" << std::endl;
		return -2;
	}

	if (appendFile) {
		//append file a to b
		if (!appendAtoB(outFilePath, inFilePath)) {
			std::cout << "Error: Failed to append data to executable!" << std::endl;
			return -3;
		}
	}
	else {
		//build list of files to process
		std::vector<FileData> fileList;
		if (boost::filesystem::is_directory(inFilePath) && boost::filesystem::is_directory(inFilePath)) {
			//both files are directories, build file ist
			fileList = getFileDataFrom(inFilePath, outFilePath, inFilePath, useRecursion);
			if (fileList.empty()) {
				std::cout << "Error: No files to convert!" << std::endl;
				return -3;
			}
		}
		else {
			//just add single input/output file
			FileData temp;
			temp.inPath = inFilePath;
			temp.outPath = outFilePath;
			temp.internalName = inFilePath.filename().string(); //remove all, but the file name and extension
			if (beVerbose) {
				std::cout << "Found input file " << inFilePath << std::endl;
				std::cout << "Internal name will be \"" << temp.internalName << "\"" << std::endl;
				std::cout << "Output path is " << temp.outPath << std::endl;
			}
			//get file size
			try {
				temp.size = (size_t)boost::filesystem::file_size(inFilePath);
				if (beVerbose) {
					std::cout << "Size is " << temp.size << " bytes." << std::endl;
				}
			}
			catch(...) {
				std::cout << "Error: Failed to get size of " << inFilePath << "!" << std::endl;
				temp.size = 0;
			}
			fileList.push_back(temp);
		}

		//does the user want an binary file?
		if (createBinary) {
			//yes. build it.
			if (!createBlob(fileList, outFilePath)) {
				std::cout << "Error: Failed to convert to binary file!" << std::endl;
				return -4;
			}
		}
		else {
			//no. convert files to .c/.cpp. loop through list, converting files
			for (auto fdIt = fileList.begin(); fdIt != fileList.cend(); ++fdIt) {
				if (!convertFile(*fdIt, commonHeaderFilePath)) {
					std::cout << "Error: Failed to convert all files. Aborting!" << std::endl;
					return -4;
				}
			}
			//do we need to write a header file?
			if (!commonHeaderFilePath.empty()) {
				if (!createCommonHeader(fileList, commonHeaderFilePath, !utilitiesFilePath.empty(), useC)) {
					return -5;
				}
				//do we need to create utilities?
				if (!utilitiesFilePath.empty()) {
                    if (!createUtilities(fileList, utilitiesFilePath, commonHeaderFilePath, useC, combineResults)) {
						return -6;
					}
				}
			}
		}
	} //if (!appendFile) {

	//profit!!!
	std::cout << "res2h succeeded." << std::endl;

	return 0;
}

ext: cpp

max_stars_repo_name: tlanks/esbusyness

max_issues_repo_name: tlanks/esbusyness

max_forks_repo_name: tlanks/esbusyness


text:
// Copyright 2015, 2017 Peter Dimov.
//
// Distributed under the Boost Software License, Version 1.0.
//
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt

#include <boost/mp11/tuple.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
#include <tuple>
#include <memory>
#include <utility>
#include <array>

struct T1
{
    int x, y, z;

    T1( int x = 0, int y = 0, int z = 0 ): x(x), y(y), z(z) {}
};

struct T2
{
    std::unique_ptr<int> x, y, z;

    T2( std::unique_ptr<int> x, std::unique_ptr<int> y, std::unique_ptr<int> z ): x(std::move(x)), y(std::move(y)), z(std::move(z)) {}

#if BOOST_WORKAROUND( BOOST_MSVC, <= 1800 )

    T2( T2&& r ): x( std::move(r.x) ), y( std::move(r.y) ), z( std::move(r.z) ) {}

#endif
};

int main()
{
    using boost::mp11::construct_from_tuple;

    {
        std::tuple<int, short, char> tp{ 1, 2, 3 };

        {
            T1 t1 = construct_from_tuple<T1>( tp );

            BOOST_TEST_EQ( t1.x, 1 );
            BOOST_TEST_EQ( t1.y, 2 );
            BOOST_TEST_EQ( t1.z, 3 );
        }

        {
            T1 t1 = construct_from_tuple<T1>( std::move(tp) );

            BOOST_TEST_EQ( t1.x, 1 );
            BOOST_TEST_EQ( t1.y, 2 );
            BOOST_TEST_EQ( t1.z, 3 );
        }
    }

    {
        std::tuple<int, short, char> const tp{ 1, 2, 3 };

        {
            T1 t1 = construct_from_tuple<T1>( tp );

            BOOST_TEST_EQ( t1.x, 1 );
            BOOST_TEST_EQ( t1.y, 2 );
            BOOST_TEST_EQ( t1.z, 3 );
        }

        {
            T1 t1 = construct_from_tuple<T1>( std::move(tp) );

            BOOST_TEST_EQ( t1.x, 1 );
            BOOST_TEST_EQ( t1.y, 2 );
            BOOST_TEST_EQ( t1.z, 3 );
        }
    }

#if defined( __clang_major__ ) && __clang_major__ == 3 && __clang_minor__ < 8
#else

    {
        std::tuple<std::unique_ptr<int>, std::unique_ptr<int>, std::unique_ptr<int>> tp{ std::unique_ptr<int>(new int(1)), std::unique_ptr<int>(new int(2)), std::unique_ptr<int>(new int(3)) };

            T2 t2 = construct_from_tuple<T2>( std::move(tp) );

            BOOST_TEST_EQ( *t2.x, 1 );
            BOOST_TEST_EQ( *t2.y, 2 );
            BOOST_TEST_EQ( *t2.z, 3 );
    }

#endif

    {
        std::pair<int, short> tp{ 1, 2 };

        {
            T1 t1 = construct_from_tuple<T1>( tp );

            BOOST_TEST_EQ( t1.x, 1 );
            BOOST_TEST_EQ( t1.y, 2 );
            BOOST_TEST_EQ( t1.z, 0 );
        }

        {
            T1 t1 = construct_from_tuple<T1>( std::move(tp) );

            BOOST_TEST_EQ( t1.x, 1 );
            BOOST_TEST_EQ( t1.y, 2 );
            BOOST_TEST_EQ( t1.z, 0 );
        }
    }

    {
        std::pair<int, short> const tp{ 1, 2 };

        {
            T1 t1 = construct_from_tuple<T1>( tp );

            BOOST_TEST_EQ( t1.x, 1 );
            BOOST_TEST_EQ( t1.y, 2 );
            BOOST_TEST_EQ( t1.z, 0 );
        }

        {
            T1 t1 = construct_from_tuple<T1>( std::move(tp) );

            BOOST_TEST_EQ( t1.x, 1 );
            BOOST_TEST_EQ( t1.y, 2 );
            BOOST_TEST_EQ( t1.z, 0 );
        }
    }

    {
        std::array<int, 3> tp{{ 1, 2, 3 }};

        {
            T1 t1 = construct_from_tuple<T1>( tp );

            BOOST_TEST_EQ( t1.x, 1 );
            BOOST_TEST_EQ( t1.y, 2 );
            BOOST_TEST_EQ( t1.z, 3 );
        }

        {
            T1 t1 = construct_from_tuple<T1>( std::move(tp) );

            BOOST_TEST_EQ( t1.x, 1 );
            BOOST_TEST_EQ( t1.y, 2 );
            BOOST_TEST_EQ( t1.z, 3 );
        }
    }

    {
        std::array<int, 3> const tp{{ 1, 2, 3 }};

        {
            T1 t1 = construct_from_tuple<T1>( tp );

            BOOST_TEST_EQ( t1.x, 1 );
            BOOST_TEST_EQ( t1.y, 2 );
            BOOST_TEST_EQ( t1.z, 3 );
        }

        {
            T1 t1 = construct_from_tuple<T1>( std::move(tp) );

            BOOST_TEST_EQ( t1.x, 1 );
            BOOST_TEST_EQ( t1.y, 2 );
            BOOST_TEST_EQ( t1.z, 3 );
        }
    }

    {
        std::tuple<> tp;

        {
            T1 t1 = construct_from_tuple<T1>( tp );

            BOOST_TEST_EQ( t1.x, 0 );
            BOOST_TEST_EQ( t1.y, 0 );
            BOOST_TEST_EQ( t1.z, 0 );
        }

        {
            T1 t1 = construct_from_tuple<T1>( std::move(tp) );

            BOOST_TEST_EQ( t1.x, 0 );
            BOOST_TEST_EQ( t1.y, 0 );
            BOOST_TEST_EQ( t1.z, 0 );
        }
    }

    {
        std::array<int, 0> tp;

        {
            T1 t1 = construct_from_tuple<T1>( tp );

            BOOST_TEST_EQ( t1.x, 0 );
            BOOST_TEST_EQ( t1.y, 0 );
            BOOST_TEST_EQ( t1.z, 0 );
        }

        {
            T1 t1 = construct_from_tuple<T1>( std::move(tp) );

            BOOST_TEST_EQ( t1.x, 0 );
            BOOST_TEST_EQ( t1.y, 0 );
            BOOST_TEST_EQ( t1.z, 0 );
        }
    }

    return boost::report_errors();
}

max_stars_repo_name: yinhangfeng/react-native

max_issues_repo_name: yinhangfeng/react-native

max_forks_repo_name: yinhangfeng/react-native


text:
/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2012, Willow Garage, 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 Willow Garage, Inc. 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 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.
 *
 *  File:    MatlabIOContainer.hpp
 *  Author:  Hilton Bristow
 *  Created: Jun 27, 2012
 */
#ifndef MATLABIOCONTAINER_HPP_
#define MATLABIOCONTAINER_HPP_
#include <string>
#include <typeinfo>
#include <boost/any.hpp>
#include "typetraits.hpp"
typedef std::vector<MatlabIOContainer> vectorMatlabIOContainer;
typedef std::vector<std::vector<MatlabIOContainer> > vector2DMatlabIOContainer;

/*! @class MatlabIOContainer
 *  @brief A container class for storing type agnostic variables
 *
 *  MatlabIOContainer stores variables of any type using the boost::any type.
 *  This allows multiple MatlabIOContainers to be stored in a single vector
 *  when reading multiple variables from a file or constructing a Matlab struct.
 */
class MatlabIOContainer {
private:
    std::string name_;
    boost::any data_;

public:
    // constructors
    MatlabIOContainer() {}
    /*! @brief Constructor to initalize the container with data and an associated name
     *
     * @param name the string name of the variable
     * @param data the associated data, of any type
     */
    MatlabIOContainer(const std::string name, const boost::any data) : name_(name), data_(data) {}
    // destructor
    ~MatlabIOContainer() {}
    // set methods
    void setName(const std::string name) { name_ = name; }
    void setData(const boost::any data) { data_ = data; }
    // get methods
    /*! @brief Check if the stored type is equal to the templated type
     *
     * This method uses typeid(T) internally, so child classes may return true
     * if compared with their parent.
     * @return true if the types are equal (premised on the above conditions), false otherwise
     */
    template<class T> bool typeEquals(void) const { return data_.type() == typeid(T); }
    /*! @brief The type of the variable
     *
     * Returns a string containing the type of the variable. This may or may not be
     * human readable (Microsoft compilers will produce human readable outputs, GCC
     * compilers will not) but are guaranteed to be unique for unique types
     * @return the variable type as a string
     */
    std::string type(void) const {
    	const std::type_info& tp = data_.type();
		if (tp == typeid(uint8_t)) return TypeName<uint8_t>::toString();
		if (tp == typeid(int8_t))  return TypeName<int8_t>::toString();
		if (tp == typeid(uint16_t)) return TypeName<uint16_t>::toString();
		if (tp == typeid(int16_t)) return TypeName<int16_t>::toString();
		if (tp == typeid(int32_t)) return TypeName<int32_t>::toString();
		if (tp == typeid(float)) return TypeName<float>::toString();
		if (tp == typeid(double)) return TypeName<double>::toString();
		if (tp == typeid(cv::Mat)) return TypeName<cv::Mat>::toString();
		if (tp == typeid(MatlabIOContainer)) return TypeName<MatlabIOContainer>::toString();
		if (tp == typeid(std::vector<MatlabIOContainer>)) return TypeName<std::vector<MatlabIOContainer> >::toString();
		if (tp == typeid(std::vector<std::vector<MatlabIOContainer> >)) return TypeName<std::vector<std::vector<MatlabIOContainer> > >::toString();
		if (tp == typeid(std::vector<cv::Mat>)) return TypeName<std::vector<cv::Mat> >::toString();
		if (tp == typeid(void)) return TypeName<void>::toString();
		return std::string(tp.name());
	}
    std::string name(void) const { return name_; }
    /*! @brief The stored data
     *
     * Returns the stored data, cast to the templated type
     * @throw boost::bad_any_cast if the requested type is not the stored data type
     * @return the data
     */
    template<class T> T data(void) const { return boost::any_cast<T>(data_); }

    // --------------------------------------------------------------------------------------
    // OPENCV FILENODE METHODS
    // --------------------------------------------------------------------------------------

};

#endif

ext: hpp

max_stars_repo_name: StevenHickson/cvmatio

max_issues_repo_name: liangfu/compvis

max_forks_repo_name: liangfu/compvis


text:
// This file is part of the dune-gdt project:
//   https://github.com/dune-community/dune-gdt
// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved.
// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
//          with "runtime exception" (http://www.dune-project.org/license.html)
// Authors:
//   Felix Schindler (2014 - 2018)
//   Rene Milk       (2014, 2016 - 2018)
//   Tobias Leibner  (2014, 2016)

#ifndef DUNE_GDT_SPACES_CG_INTERFACE_HH
#define DUNE_GDT_SPACES_CG_INTERFACE_HH

#include <boost/numeric/conversion/cast.hpp>

#include <dune/common/dynvector.hh>
#include <dune/common/version.hh>
#include <dune/common/typetraits.hh>

#include <dune/geometry/referenceelements.hh>

#include <dune/xt/common/exceptions.hh>
#include <dune/xt/common/type_traits.hh>
#include <dune/xt/common/ranges.hh>
#include <dune/xt/grid/boundaryinfo.hh>
#include <dune/xt/grid/intersection.hh>

#include "../interface.hh"

namespace Dune {
namespace GDT {

static constexpr Backends default_cg_backend = default_space_backend;

template <class ImpTraits, size_t domainDim, size_t rangeDim, size_t rangeDimCols = 1>
class CgSpaceInterface : public SpaceInterface<ImpTraits, domainDim, rangeDim, rangeDimCols>
{
  typedef SpaceInterface<ImpTraits, domainDim, rangeDim, rangeDimCols> BaseType;
  typedef CgSpaceInterface<ImpTraits, domainDim, rangeDim, rangeDimCols> ThisType;

public:
  typedef ImpTraits Traits;

  using BaseType::polOrder;

  using typename BaseType::DomainFieldType;
  using BaseType::dimDomain;
  using typename BaseType::DomainType;

  using typename BaseType::RangeFieldType;
  using BaseType::dimRange;
  using BaseType::dimRangeCols;

  using typename BaseType::GridLayerType;
  using typename BaseType::EntityType;
  using typename BaseType::PatternType;

private:
  static const constexpr RangeFieldType compare_tolerance_ = 1e-13;

public:
  virtual ~CgSpaceInterface() = default;

  /**
   * \defgroup interface ´´These methods have to be implemented!''
   * @{
   **/
  std::vector<DomainType> lagrange_points(const EntityType& entity) const
  {
    CHECK_CRTP(this->as_imp().lagrange_points(entity));
    return this->as_imp().lagrange_points(entity);
  }
  /** @} */

  /**
   * \defgroup provided ´´These methods are provided by the interface for convenience.''
   * @{
   **/
  virtual std::set<size_t> local_dirichlet_DoFs(
      const EntityType& entity,
      const XT::Grid::BoundaryInfo<XT::Grid::extract_intersection_t<GridLayerType>>& boundary_info) const
  {
    std::set<size_t> ret;
    static const XT::Grid::DirichletBoundary dirichlet{};
    const auto lps = lagrange_points(entity);
    const auto intersection_it_end = this->grid_layer().iend(entity);
    for (auto intersection_it = this->grid_layer().ibegin(entity); intersection_it != intersection_it_end;
         ++intersection_it) {
      // only work on dirichlet ones
      const auto& intersection = *intersection_it;
      // actual dirichlet intersections + process boundaries for parallel runs
      if (boundary_info.type(intersection) == dirichlet || (!intersection.neighbor() && !intersection.boundary()))
        for (size_t ii = 0; ii < lps.size(); ++ii) {
          const auto& local_lagrange_point = lps[ii];
          if (XT::Grid::contains(intersection, entity.geometry().global(local_lagrange_point)))
            ret.insert(ii);
        }
    }
    return ret;
  } // ... local_dirichlet_DoFs(...)

  using BaseType::compute_pattern;

  template <class GL, class S, size_t d, size_t r, size_t rC>
  typename std::enable_if<XT::Grid::is_layer<GL>::value, PatternType>::type
  compute_pattern(const GL& grd_layr, const SpaceInterface<S, d, r, rC>& ansatz_space) const
  {
    return BaseType::compute_volume_pattern(grd_layr, ansatz_space);
  }

  using BaseType::local_constraints;

  template <class S, size_t d, size_t r, size_t rC, class ConstraintsType>
  void local_constraints(const SpaceInterface<S, d, r, rC>& /*other*/,
                         const EntityType& /*entity*/,
                         ConstraintsType& /*ret*/) const
  {
    static_assert(AlwaysFalse<S>::value, "Not implemented for these constraints!");
  }

  template <class S, size_t d, size_t r, size_t rC>
  void local_constraints(const SpaceInterface<S, d, r, rC>& /*other*/,
                         const EntityType& entity,
                         DirichletConstraints<XT::Grid::extract_intersection_t<GridLayerType>>& ret) const
  {
    const auto local_DoFs = this->local_dirichlet_DoFs(entity, ret.boundary_info());
    if (local_DoFs.size() > 0) {
      const auto global_indices = this->mapper().globalIndices(entity);
      for (const auto& local_DoF : local_DoFs) {
        ret.insert(global_indices[local_DoF]);
      }
    }
  } // ... local_constraints(..., Constraints::Dirichlet<...> ...)
  /** @} */

  static constexpr bool associates_data_with(int codim, std::integral_constant<int, 1>)
  {
    return codim == dimDomain;
  }

  static constexpr bool associates_data_with(int codim, std::integral_constant<int, 2>)
  {
    return dimDomain == 1 ? codim >= 0 : codim > 0;
  }

  static constexpr bool associates_data_with(int codim)
  {
    // actually: return polOrder > 2 ? true : associates_data_with(codim, std::integral_constant<int, polOrder>());
    return codim == 0;
  }

protected:
  std::vector<DomainType> lagrange_points_order_1(const EntityType& entity) const
  {
    // check
    static_assert(polOrder == 1, "Not tested for higher polynomial orders!");
    if (dimRange != 1)
      DUNE_THROW(NotImplemented, "Does not work for higher dimensions");
    assert(this->grid_layer().indexSet().contains(entity));
    // get the basis and reference element
    const auto basis = this->base_function_set(entity);
    typedef typename BaseType::BaseFunctionSetType::RangeType RangeType;
    std::vector<RangeType> tmp_basis_values(basis.size(), RangeType(0));
    const auto& reference_element = ReferenceElements<DomainFieldType, dimDomain>::general(entity.type());
    const auto num_vertices = reference_element.size(dimDomain);
    assert(num_vertices >= 0);
    assert(boost::numeric_cast<size_t>(num_vertices) == basis.size() && "This should not happen with polOrder 1!");
    // prepare return vector
    std::vector<DomainType> local_vertices(num_vertices, DomainType(0));
    // loop over all vertices
    for (auto ii : Dune::XT::Common::value_range(num_vertices)) {
      // get the local coordinate of the iith vertex
      const auto local_vertex = reference_element.position(ii, dimDomain);
      // evaluate the basefunctionset
      basis.evaluate(local_vertex, tmp_basis_values);
      // find the basis function that evaluates to one here (has to be only one!)
      size_t ones = 0;
      size_t zeros = 0;
      size_t failures = 0;
      for (size_t jj = 0; jj < basis.size(); ++jj) {
        if (std::abs((tmp_basis_values)[jj][0] - RangeFieldType(1)) < compare_tolerance_) {
          local_vertices[jj] = local_vertex;
          ++ones;
        } else if (std::abs((tmp_basis_values)[jj][0]) < compare_tolerance_)
          ++zeros;
        else
          ++failures;
      }
      assert(ones == 1 && zeros == (basis.size() - 1) && failures == 0 && "This must not happen for polOrder 1!");
    }
    return local_vertices;
  } // ... lagrange_points_order_1(...)
}; // class CgSpaceInterface

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_SPACES_CG_INTERFACE_HH

ext: hh

max_stars_repo_name: TiKeil/dune-gdt

max_issues_repo_name: TiKeil/dune-gdt

max_forks_repo_name: TiKeil/dune-gdt