// Copyright (C) 2018 T. Zachary Laine
//
// 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/parser/parser.hpp>

#include <gtest/gtest.h>

using namespace boost::parser;

TEST(parser, symbols_empty)
{
    symbols<int> roman_numerals;
    symbols<std::string> named_strings;

    std::string const str = "I";
    EXPECT_FALSE(parse(str, roman_numerals));
    EXPECT_FALSE(parse(str, named_strings));
}

TEST(parser, symbols_simple)
{
    symbols<int> const roman_numerals = {
        {"I", 1}, {"V", 5}, {"X", 10}, {"L", 50}, {"C", 100}};
    symbols<std::string> const named_strings = {
        {"I", "1"}, {"V", "5"}, {"X", "10"}, {"L", "50"}, {"C", "100"}};

    {
        auto const result = parse("I", roman_numerals);
        EXPECT_TRUE(result);
        EXPECT_EQ(*result, 1);
    }
    {
        auto const result = parse("I", named_strings);
        EXPECT_TRUE(result);
        EXPECT_EQ(*result, "1");
    }

    {
        auto const result = parse("L", roman_numerals);
        EXPECT_TRUE(result);
        EXPECT_EQ(*result, 50);
    }
    {
        auto const result = parse("L", named_strings);
        EXPECT_TRUE(result);
        EXPECT_EQ(*result, "50");
    }
}

TEST(parser, symbols_max_munch)
{
    symbols<int> const roman_numerals = {
        {"I", 1},
        {"II", 2},
        {"III", 3},
        {"IV", 4},
        {"V", 5},
        {"VI", 6},
        {"VII", 7},
        {"VIII", 8},
        {"IX", 9},

        {"X", 10},
        {"XX", 20},
        {"XXX", 30},
        {"XL", 40},
        {"L", 50},
        {"LX", 60},
        {"LXX", 70},
        {"LXXX", 80},
        {"XC", 90},

        {"C", 100},
        {"CC", 200},
        {"CCC", 300},
        {"CD", 400},
        {"D", 500},
        {"DC", 600},
        {"DCC", 700},
        {"DCCC", 800},
        {"CM", 900},

        {"M", 1000}};

    {
        auto const result = parse("I", roman_numerals);
        EXPECT_TRUE(result);
        EXPECT_EQ(*result, 1);
    }
    {
        auto const result = parse("II", roman_numerals);
        EXPECT_TRUE(result);
        EXPECT_EQ(*result, 2);
    }
    {
        auto const result = parse("III", roman_numerals);
        EXPECT_TRUE(result);
        EXPECT_EQ(*result, 3);
    }
    {
        auto const result = parse("IV", roman_numerals);
        EXPECT_TRUE(result);
        EXPECT_EQ(*result, 4);
    }
    {
        auto const result = parse("V", roman_numerals);
        EXPECT_TRUE(result);
        EXPECT_EQ(*result, 5);
    }
    {
        auto const result = parse("VI", roman_numerals);
        EXPECT_TRUE(result);
        EXPECT_EQ(*result, 6);
    }
    {
        auto const result = parse("VII", roman_numerals);
        EXPECT_TRUE(result);
        EXPECT_EQ(*result, 7);
    }
    {
        auto const result = parse("VIII", roman_numerals);
        EXPECT_TRUE(result);
        EXPECT_EQ(*result, 8);
    }
    {
        auto const result = parse("IX", roman_numerals);
        EXPECT_TRUE(result);
        EXPECT_EQ(*result, 9);
    }
}

TEST(parser, symbols_mutating)
{
    symbols<int> roman_numerals;
    roman_numerals.add("I", 1)("V", 5)("X", 10);
    auto const add_numeral = [&roman_numerals](auto & context) {
        using namespace boost::parser::literals;
        char chars[2] = {get(_attr(context), 0_c), 0};
        roman_numerals.insert(context, chars, get(_attr(context), 1_c));
    };
    auto const numerals_parser = (char_ >> int_)[add_numeral] >> roman_numerals;

    {
        auto const result = parse("L50L", numerals_parser);
        EXPECT_TRUE(result);
        EXPECT_EQ(*result, 50);
        EXPECT_FALSE(parse("L", roman_numerals));
    }
    {
        auto const result = parse("C100C", numerals_parser);
        EXPECT_TRUE(result);
        EXPECT_EQ(*result, 100);
        EXPECT_FALSE(parse("C", roman_numerals));
    }
    {
        auto const result = parse("L50C", numerals_parser);
        EXPECT_FALSE(result);
    }
}


#include <boost/ut.hpp>
#include <libembeddedhal/temperature/interface.hpp>

namespace embed {
namespace {
constexpr auto expected_temperature = nK(1'000'000'000);
class test_temperature_sensor : public embed::temperature_sensor
{
private:
  virtual boost::leaf::result<temperature> driver_read() noexcept
  {
    return expected_temperature;
  }
};
}  // namespace

boost::ut::suite temperature_test = []() {
  using namespace boost::ut;
  // Setup
  test_temperature_sensor test;

  // Exercise
  auto sample = test.read().value();

  // Verify
  expect(expected_temperature == sample);
};
}  // namespace embed


/********************************************************************************
 * Copyright 2009 The Robotics Group, The Maersk Mc-Kinney Moller Institute,
 * Faculty of Engineering, University of Southern Denmark
 *
 * 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.
 ********************************************************************************/

#ifndef RW_LOADERS_XML_XML_HPP
#define RW_LOADERS_XML_XML_HPP

/**
   @file XML.hpp
*/

#include <rw/math/Rotation3D.hpp>
#include <rw/math/Transform3D.hpp>
#include <rw/math/Vector3D.hpp>

#include <boost/property_tree/ptree.hpp>

namespace rw { namespace math {
    class Q;
}}    // namespace rw::math
namespace rw { namespace core {
    class PropertyMap;
}}    // namespace rw::core

namespace rw { namespace loaders {

    /** @addtogroup loaders */
    /*@{*/

    /**
       @brief XML is a collection of procedures for reading RobWork data
       structures stored in an XML format.

       The data structures are read from an XML file loaded into a Boost
       property tree.

       Eventually this parsing of XML structures should be shared between
       workcell and task files.

       The parser assumes that the node with the relevant name has been entered.
       For example:

\code
const Vector3D<> pos = XML::readVector3D(tree.get_child("Vector3D"));
\endcode
    */
    class XML
    {
      public:
        //! @brief type of property tree
        typedef boost::property_tree::ptree PTree;

        /**
\verbatim
<vector3d> ::= Vector3D <number> <number> <number>
\endverbatim
         */
        static math::Vector3D<> readVector3D (const PTree& tree);

        /**
\verbatim
<rotation3d> ::=
    RPY <number> <number> <number> |
    Rotation3D
        <number> <number> <number>
        <number> <number> <number>
        <number> <number> <number>
\endverbatim
         */
        static math::Rotation3D<> readRotation3D (const PTree& tree);

        /**
\verbatim
<transform3d> ::= Transform3D <vector3d> <rotation3d>
\endverbatim
        */
        static math::Transform3D<> readTransform3D (const PTree& tree);

        /**
\verbatim
<q> ::= Q <number> ... <number>
\endverbatim
        */
        static math::Q readQ (const PTree& tree);

        /**
\verbatim
<property-map> ::= PropertyMap <property> ...
<property> ::=
    Property
        (Key <string>)
        <description>?
        (<string> | <number> | <vector3d> | <rotation3d> | <transform3d> | <q>)
\endverbatim
        */
        static void readPropertyMap (const PTree& tree, core::PropertyMap& properties);

        /**
           @brief Print a formatted version of the tree to \b out.

           This utility is useful for figuring out how the XML representation
           corresponds to the property tree.
        */
        static void printTree (const PTree& tree, std::ostream& out);

      private:
        XML ();
    };

    /**@}*/
}}    // namespace rw::loaders

#endif    // end include guard


//==============================================================================
//         Copyright 2003 - 2011   LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2011   LRI    UMR 8623 CNRS/Univ Paris Sud XI
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
#ifndef BOOST_SIMD_CONSTANT_CONSTANTS_SIGNMASK_HPP_INCLUDED
#define BOOST_SIMD_CONSTANT_CONSTANTS_SIGNMASK_HPP_INCLUDED

#include <boost/simd/include/functor.hpp>
#include <boost/simd/meta/float.hpp>
#include <boost/simd/meta/int_c.hpp>
#include <boost/simd/meta/double.hpp>
#include <boost/simd/constant/hierarchy.hpp>

namespace boost { namespace simd
{
  namespace tag
  {
   /*!
     @brief Signmask generic tag

     Represents the Signmask constant in generic contexts.

     @par Models:
        Hierarchy
   **/
    struct Signmask : ext::pure_constant_<Signmask>
    {
      typedef double default_type;
      typedef ext::pure_constant_<Signmask> parent;

      /// INTERNAL ONLY
      template<class Target, class Dummy=void>
      struct apply : meta::int_c<typename Target::type,0> {};
      template<class... Args>
      static BOOST_FORCEINLINE BOOST_AUTO_DECLTYPE dispatch(Args&&... args)
      BOOST_AUTO_DECLTYPE_BODY( dispatching_Signmask( ext::adl_helper(), static_cast<Args&&>(args)... ) )
    };

    /// INTERNAL ONLY
    template<class T, class Dummy>
    struct  Signmask::apply<boost::dispatch::meta::single_<T>,Dummy>
          : meta::single_<0x80000000UL> {};

    /// INTERNAL ONLY
    template<class T, class Dummy>
    struct  Signmask::apply<boost::dispatch::meta::double_<T>,Dummy>
          : meta::double_<0x8000000000000000ULL> {};

    /// INTERNAL ONLY
    template<class T, class Dummy>
    struct  Signmask::apply<boost::dispatch::meta::int8_<T>,Dummy>
          : meta::int_c<T, boost::simd::int8_t(0x80U)> {};

    /// INTERNAL ONLY
    template<class T, class Dummy>
    struct  Signmask::apply<boost::dispatch::meta::int16_<T>,Dummy>
          : meta::int_c<T, boost::simd::int16_t(0x8000U)> {};

    /// INTERNAL ONLY
    template<class T, class Dummy>
    struct  Signmask::apply<boost::dispatch::meta::int32_<T>,Dummy>
          : meta::int_c<T, boost::simd::int32_t(0x80000000UL)> {};

    /// INTERNAL ONLY
    template<class T, class Dummy>
    struct  Signmask::apply<boost::dispatch::meta::int64_<T>,Dummy>
          : meta::int_c < T
                        , boost::simd::int64_t(0x8000000000000000ULL)
                        > {};
  }
  namespace ext
  {
   template<class Site>
   BOOST_FORCEINLINE generic_dispatcher<tag::Signmask, Site> dispatching_Signmask(adl_helper, boost::dispatch::meta::unknown_<Site>, ...)
   {
     return generic_dispatcher<tag::Signmask, Site>();
   }
   template<class... Args>
   struct impl_Signmask;
  }
  /*!
    Generate a mask with the lone most significand bit set to one
    (even if the type is unsigned).

    @par Semantic:

    @code
    T r = Signmask<T>();
    @endcode

    is similar to:

    @code
    T r = bitwise_cast<T>(1 << sizeof(T)*8-1);
    @endcode
  **/
  BOOST_SIMD_CONSTANT_IMPLEMENTATION(boost::simd::tag::Signmask, Signmask)
} }

#include <boost/simd/constant/common.hpp>

#endif


#include <boost/hana/unique.hpp>


#include <boost/hana/sort.hpp>


//=========================================================================
//
// Copyright 2012,2013,2014 Kitware, Inc.
//
// 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 "vtkProcessingSample.h"

#include "vtkFloatArray.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkNew.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPolyData.h"
#include "vtkSmartPointer.h"
#include "vtkSphereSource.h"
#include "vtkStreamingDemandDrivenPipeline.h"

#include <Eigen/Dense>

#include <limits>

//----------------------------------------------------------------------------
vtkStandardNewMacro(vtkProcessingSample)

//----------------------------------------------------------------------------
vtkProcessingSample::vtkProcessingSample()
{
  this->SetNumberOfInputPorts(1);
  this->SetNumberOfOutputPorts(1);
}

//----------------------------------------------------------------------------
vtkProcessingSample::~vtkProcessingSample()
{
}

//----------------------------------------------------------------------------
int vtkProcessingSample::RequestData(vtkInformation* vtkNotUsed(request),
  vtkInformationVector** inputVector, vtkInformationVector* outputVector)
{
  vtkInformation* inInfo = inputVector[0]->GetInformationObject(0);
  vtkPolyData* input = vtkPolyData::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT()));

  vtkInformation* outInfo = outputVector->GetInformationObject(0);
  vtkPolyData* output = vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));

  vtkPoints* points = input->GetPoints();
  if (!points || !points->GetNumberOfPoints())
  {
    return 1;
  }

  Eigen::Vector3d meanpoints;
  for (vtkIdType i = 0; i < points->GetNumberOfPoints(); ++i)
  {
    Eigen::Vector3d point;
    points->GetPoint(i, point.data());
    meanpoints += point;
  }
  meanpoints /= points->GetNumberOfPoints();

  // Create a sphere at the center location
  vtkNew<vtkSphereSource> spheresource;
  spheresource->SetCenter(meanpoints.data());
  spheresource->SetRadius(0.5);
  spheresource->Update();

  // Get the intensities and laser ids for points
  vtkUnsignedCharArray* intensities =
    vtkUnsignedCharArray::SafeDownCast(input->GetPointData()->GetArray("intensity"));
  vtkUnsignedCharArray* laserid =
    vtkUnsignedCharArray::SafeDownCast(input->GetPointData()->GetArray("laser_id"));

  // Compute the max, min intensity for laser 3
  int minimum_intensity = std::numeric_limits<int>::max();
  int maximum_intensity = 0;
  for (vtkIdType i = 0; i < points->GetNumberOfPoints(); ++i)
  {
    int laser = laserid->GetValue(i);
    if (laser == 3)
    {
      int point_intensity = intensities->GetValue(i);
      if (point_intensity < minimum_intensity)
      {
        minimum_intensity = point_intensity;
      }
      if (point_intensity > maximum_intensity)
      {
        maximum_intensity = point_intensity;
      }
    }
  }

  // Add field data with some numbers
  vtkSmartPointer<vtkFloatArray> fielddata = vtkSmartPointer<vtkFloatArray>::New();
  fielddata->SetName("Values");
  fielddata->SetNumberOfComponents(1);
  fielddata->InsertNextValue(minimum_intensity);
  fielddata->InsertNextValue(maximum_intensity);

  vtkSmartPointer<vtkPolyData> outputPolyData = vtkSmartPointer<vtkPolyData>::New();
  outputPolyData->DeepCopy(spheresource->GetOutput());
  outputPolyData->GetFieldData()->AddArray(fielddata);

  output->ShallowCopy(outputPolyData);

  return 1;
}

//----------------------------------------------------------------------------
void vtkProcessingSample::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}


#pragma once

// C++ standard library
#include <unordered_map>

// Armadillo
#include <armadillo>

// Mantella
#include "mantella_bits/armadillo.hpp"
// IWYU pragma: no_forward_declare mant::Hash
// IWYU pragma: no_forward_declare mant::IsEqual

namespace mant {
  std::unordered_map<arma::vec, double, Hash, IsEqual> elitists(
      const std::unordered_map<arma::vec, double, Hash, IsEqual>& samples,
      const arma::uword numberOfSamplesToSelect);
}


#include "aslam/calibration/target-base.h"

#include <utility>

#include <Eigen/Core>
#include <glog/logging.h>

namespace aslam {
namespace calibration {

TargetBase::TargetBase(size_t rows, size_t cols, const Eigen::Matrix3Xd& points_target_frame)
    : rows_(rows),
      cols_(cols),
      points_target_frame_(points_target_frame) {
  CHECK_GT(rows, 0u);
  CHECK_GT(cols, 0u);
  CHECK_EQ(static_cast<int>(size()), points_target_frame_.cols());
}

Eigen::Matrix3Xd TargetBase::points() const {
  return points_target_frame_;
}

Eigen::Vector3d TargetBase::point(size_t point_idx) const {
  CHECK_LT(point_idx, size());
  return points_target_frame_.col(point_idx);
}

std::pair<size_t, size_t> TargetBase::pointToGridCoordinates(size_t point_idx) const {
  return std::pair<size_t, size_t>(point_idx % cols(), static_cast<int>(point_idx / cols()));
}

size_t TargetBase::gridCoordinatesToPoint(size_t row_idx, size_t col_idx) const {
  CHECK_LT(row_idx, rows());
  CHECK_LT(col_idx, cols());
  const size_t point_idx = cols() * row_idx + col_idx;
  CHECK_LT(point_idx, size());
  return point_idx;
}

Eigen::Vector3d TargetBase::gridPoint(size_t row_idx, size_t col_idx) const {
  return points_target_frame_.col(gridCoordinatesToPoint(row_idx, col_idx));
}

double* TargetBase::pointMutable(size_t point_idx) {
  CHECK_LT(point_idx, size());
  return &points_target_frame_.coeffRef(0, point_idx);
}

}  // namespace calibration
}  // namespace aslam


/**************************************************************************
 * Copyright (c) 2017-2019 by the mfmg authors                            *
 * All rights reserved.                                                   *
 *                                                                        *
 * This file is part of the mfmg library. mfmg is distributed under a BSD *
 * 3-clause license. For the licensing terms see the LICENSE file in the  *
 * top-level directory                                                    *
 *                                                                        *
 * SPDX-License-Identifier: BSD-3-Clause                                  *
 *************************************************************************/

#ifndef MFMG_LANCZOS_LANCZOS_HPP
#define MFMG_LANCZOS_LANCZOS_HPP

#include <boost/property_tree/ptree.hpp>

#include <memory>
#include <vector>

namespace mfmg
{

//-----------------------------------------------------------------------------
/// \brief Lanczos solver

template <typename OperatorType, typename VectorType>
class Lanczos
{
public:
  Lanczos(OperatorType const &op);

  Lanczos(Lanczos<OperatorType, VectorType> const &) = delete;
  Lanczos<OperatorType, VectorType> &
  operator=(Lanczos<OperatorType, VectorType> const &) = delete;

  // Operations
  std::tuple<std::vector<double>, std::vector<VectorType>>
  solve(boost::property_tree::ptree const &params,
        VectorType initial_guess) const;

private:
  OperatorType const &_op; // reference to operator object to use

  template <typename FullOperatorType>
  static std::tuple<std::vector<double>, std::vector<VectorType>>
  details_solve_lanczos(FullOperatorType const &op, int const num_requested,
                        boost::property_tree::ptree const &params,
                        VectorType const &initial_guess);

  static std::tuple<std::vector<double>, std::vector<double>>
  details_calc_tridiag_epairs(std::vector<double> const &main_diagonal,
                              std::vector<double> const &sub_diagonal,
                              int const num_requested);

  static bool details_check_convergence(double beta, int const num_evecs,
                                        int const num_requested, double tol,
                                        std::vector<double> const &evecs);

  static std::vector<VectorType>
  details_calc_evecs(int const num_requested, int const n,
                     std::vector<VectorType> const &lanc_vectors,
                     std::vector<double> const &evecs_tridiag);
};

} // namespace mfmg

#endif


// Boost.Geometry (aka GGL, Generic Geometry Library)

// Copyright (c) 2017-2018 Oracle and/or its affiliates.
// Contributed and/or modified by Vissarion Fisikopoulos, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle

// Use, modification and distribution is subject to 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)

#ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_ENVELOPE_SEGMENT_HPP
#define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_ENVELOPE_SEGMENT_HPP

#include <cstddef>

#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/tags.hpp>

#include <boost/geometry/strategies/cartesian/envelope_point.hpp>
#include <boost/geometry/strategies/cartesian/expand_point.hpp>
#include <boost/geometry/strategies/envelope.hpp>

namespace boost { namespace geometry { namespace strategy { namespace envelope
{

#ifndef DOXYGEN_NO_DETAIL
namespace detail
{

template <std::size_t Dimension, std::size_t DimensionCount>
struct envelope_one_segment
{
    template<typename Point, typename Box>
    static inline void apply(Point const& p1,
                             Point const& p2,
                             Box& mbr)
    {
        geometry::detail::envelope::envelope_one_point
            <
                Dimension, DimensionCount
            >::apply(p1, mbr);

        strategy::expand::detail::point_loop
            <
                Dimension, DimensionCount
            >::apply(mbr, p2);
    }
};

} // namespace detail
#endif // DOXYGEN_NO_DETAIL

template
<
    typename CalculationType = void
>
class cartesian_segment
{
public:
    template <typename Point, typename Box>
    static inline void apply(Point const& point1, Point const& point2, Box& box)
    {
        strategy::envelope::detail::envelope_one_segment
            <
                0,
                dimension<Point>::value
            >::apply(point1, point2, box);
    }

};

#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS

namespace services
{

template <typename CalculationType>
struct default_strategy<segment_tag, cartesian_tag, CalculationType>
{
    typedef strategy::envelope::cartesian_segment<CalculationType> type;
};

}

#endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS

}} // namespace strategy::envelope

}} //namepsace boost::geometry

#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_ENVELOPE_SEGMENT_HPP


#ifndef CANNON_PHYSICS_EULER_INTEGRATOR_H
#define CANNON_PHYSICS_EULER_INTEGRATOR_H

/*!
 * \file cannon/physics/euler_integrator.hpp
 * \brief File containing EulerIntegrator class definition.
 */

/*!
 * \namespace cannon::physics
 * \brief Namespace containing physics utilities.
 */

#include <Eigen/Dense>
#include <boost/numeric/odeint.hpp>
#include <boost/numeric/odeint/external/eigen/eigen_algebra.hpp>

using namespace Eigen;
using namespace boost::numeric::odeint;

namespace cannon {
  namespace physics {

    // TODO Refactor to use std::function
    /*!
     * \brief Class representing an Euler Integrator. Essentially just wraps
     * boost::odeint functionality.
     */
    template <typename F>
    class EulerIntegrator {
      public:
        EulerIntegrator() = delete;

        /*!
         * \brief Constructor taking an ODE, the state dimension, and the
         * integration timestep.
         */
        EulerIntegrator(F system, unsigned int state_dim, double dt) :
            system_(system), state_dim_(state_dim), dt_(dt) {
          state_ = VectorXd::Zero(state_dim_);
        }

        /*!
         * \brief Step this integrator by a single timestep.
         *
         * \returns The new state, post-step.
         */
        const VectorXd& step() {
          stepper_.do_step(system_, state_, t_, dt_);
          t_ += dt_;

          return state_;
        }

        /*!
         * \brief Set the state of this integrator.
         *
         * \param state The new state.
         */
        void set_state(const VectorXd& state) {
          state_ = state;
        }

        /*!
         * \brief Get the current state of this integrator.
         *
         * \returns Current state of this integrator.
         */
        VectorXd get_state() const {
          return state_;
        }

        /*!
         * \brief Set the current time for this integrator.
         *
         * \param t The new time.
         */
        void set_time(double t) {
          t_ = t;
        }

        /*!
         * \brief Get the current time for this integrator.
         *
         * \returns The current time.
         */
        double get_time() {
          return t_;
        }

      private:
        using stepper_type = euler<VectorXd, double, VectorXd, double, vector_space_algebra>;
        // System should take a state, a vector in which to place its gradient, and a time
        F system_; //!< ODE to be integrated. Should take a state, gradient vector, and time
        stepper_type stepper_; //!< Stepper for integration

        unsigned int state_dim_; //!< Dimension of state vector.
        VectorXd state_; //!< Current state of system

        double dt_; //!< System integration timestep
        double t_ = 0.0; //!< Overall time
    };

    /*!
     * \brief Make an EulerIntegrator, inferring the function pointer type
     * automatically.
     *
     * \param system The system ODE to integrate.
     * \param state_dim Dimensionality of real vector state.
     * \param dt Time step for integration.
     *
     * \returns Constructed EulerIntegrator.
     */
    template <typename F>
    EulerIntegrator<F> make_euler_integrator(F system, unsigned int state_dim, double dt) {
      return EulerIntegrator<F>(system, state_dim, dt);
    }

  } // namespace physics
} // namespace cannon

#endif /* ifndef CANNON_PHYSICS_EULER_INTEGRATOR_H */


#ifdef STAN_OPENCL

#include <stan/math/opencl/kernel_generator.hpp>
#include <stan/math/opencl/matrix_cl.hpp>
#include <stan/math/opencl/copy.hpp>
#include <test/unit/util.hpp>
#include <Eigen/Dense>
#include <gtest/gtest.h>
#include <exception>

using Eigen::MatrixXd;
using Eigen::MatrixXi;
using stan::math::matrix_cl;

TEST(KernelGenerator, operation_cl_errors) {
  EXPECT_THROW(matrix_cl<double> a = stan::math::as_operation_cl(3.5),
               std::invalid_argument);
  EXPECT_THROW(stan::math::as_operation_cl(3.5).eval(), std::invalid_argument);
}

TEST(KernelGenerator, kernel_caching) {
  MatrixXd m1(3, 3);
  m1 << 1, 2, 3, 4, 5, 6, 7, 8, 9;
  MatrixXd m2(3, 3);
  m2 << 10, 100, 1000, 0, -10, -12, 2, 4, 8;

  matrix_cl<double> m1_cl(m1);
  matrix_cl<double> m2_cl(m2);
  auto tmp = m1_cl + 0.1234 * m2_cl;

  using cache = stan::math::internal::multi_result_kernel_internal<
      0, stan::math::load_<matrix_cl<double>&>>::inner<const decltype(tmp)&>;
  using unused_cache = stan::math::internal::multi_result_kernel_internal<
      0, stan::math::load_<matrix_cl<int>&>>::inner<const decltype(tmp)&>;
  size_t cache_size = cache::kernel_cache_.size();
  size_t unused_cache_size = unused_cache::kernel_cache_.size();
  std::vector<int> uid = {0, 1, 2};

  EXPECT_EQ(cache::kernel_cache_.count(uid), 0);
  EXPECT_EQ(cache::kernel_cache_.size(), cache_size);
  matrix_cl<double> res_cl = tmp;
  EXPECT_EQ(cache::kernel_cache_.size(), cache_size + 1);
  cl_kernel cached_kernel = cache::kernel_cache_.at(uid)();
  EXPECT_NE(cached_kernel, nullptr);

  auto tmp2 = m1_cl + 0.1234 * m2_cl;
  matrix_cl<double> res2_cl = tmp2;
  EXPECT_EQ(cache::kernel_cache_.at(uid)(), cached_kernel);
  EXPECT_EQ(cache::kernel_cache_.size(), cache_size + 1);

  matrix_cl<double> res3_cl = res_cl + 0.1234 * res2_cl;
  EXPECT_EQ(cache::kernel_cache_.at(uid)(), cached_kernel);
  EXPECT_EQ(cache::kernel_cache_.size(), cache_size + 1);

  EXPECT_EQ(unused_cache::kernel_cache_.size(), unused_cache_size);
}

TEST(MathMatrixCL, events_write_after_write) {
  using stan::math::matrix_cl;
  matrix_cl<double> zero_cl = stan::math::constant(0, 3, 3);
  zero_cl.wait_for_read_write_events();

  for (int j = 0; j < 3000; j++) {
    matrix_cl<double> m_cl(3, 3);

    for (int i = 0; i < 4; i++) {
      m_cl = zero_cl + i;
    }

    Eigen::MatrixXd res = stan::math::from_matrix_cl(m_cl);
    Eigen::MatrixXd correct = Eigen::MatrixXd::Constant(3, 3, 3);

    EXPECT_MATRIX_NEAR(res, correct, 1e-13);
  }
}

TEST(MathMatrixCL, events_read_after_write_and_write_after_read) {
  using stan::math::matrix_cl;
  int iters = 3000;

  matrix_cl<double> m1_cl = stan::math::constant(0, 3, 3);
  matrix_cl<double> m2_cl(3, 3);

  for (int j = 0; j < iters; j++) {
    m2_cl = m1_cl + 1;
    m1_cl = m2_cl + 1;
  }
  Eigen::MatrixXd res = stan::math::from_matrix_cl(m1_cl);
  Eigen::MatrixXd correct = Eigen::MatrixXd::Constant(3, 3, 2 * iters);

  EXPECT_MATRIX_NEAR(res, correct, 1e-13);
}

TEST(MathMatrixCL, same_operations_different_inputs) {
  MatrixXd m1(3, 3);
  m1 << 1, 2, 3, 4, 5, 6, 7, 8, 9;
  MatrixXd m2(3, 3);
  m2 << 10, 100, 1000, 0, -10, -12, 2, 4, 8;

  matrix_cl<double> m1_cl(m1);
  matrix_cl<double> m2_cl(m2);

  auto m1_op = stan::math::as_operation_cl(m1_cl);
  auto m2_op = stan::math::as_operation_cl(m2_cl);

  matrix_cl<double> res1_cl = m1_op + m1_op;
  matrix_cl<double> res2_cl = m2_op + m1_op;

  EXPECT_MATRIX_EQ(stan::math::from_matrix_cl(res1_cl), m1 + m1);
  EXPECT_MATRIX_EQ(stan::math::from_matrix_cl(res2_cl), m2 + m1);
}

#endif


#define BOOST_TEST_MODULE
#include <boost/test/unit_test.hpp>
#include <util/test_macros.hpp>
#include <string>
#include <random>
#include <set>
#include <sstream>
#include <vector>
#include <algorithm>
#include <util/cityhash_tc.hpp>

// Constraints
#include <optimization/constraints-inl.hpp>
#include <numerics/armadillo.hpp>

using namespace turi;
typedef arma::vec  DenseVector;
typedef sparse_vector<double> SparseVector;

struct constraint_interface_test  {

  size_t variables;
  DenseVector init_point;
  DenseVector solution_orthant;
  DenseVector solution_box;
  double lb_dbl;
  double ub_dbl;
  DenseVector lb;
  DenseVector ub;

  public:

    constraint_interface_test() {
      size_t variables = 10;

      DenseVector init_point(variables);
      DenseVector solution_orthant(variables);
      DenseVector solution_box(variables);
      double lb_dbl = 0;
      double ub_dbl = 1;
      DenseVector lb(variables);
      DenseVector ub(variables);
      lb.zeros(variables);
      ub.ones(variables);
      srand(1);
      init_point = {1 , -1 , 2 , -2 , 3 , -3 , 4 , -4 , 5 , -5};
      solution_orthant = {1 ,  0 , 2 ,  0 , 3 ,  0 , 4 ,  0 , 5 ,  0};
      solution_box = {1 ,  0 , 1 ,  0 , 1 ,  0 , 1 ,  0 , 1 , 0};

      std::shared_ptr<optimization::non_negative_orthant> non_negative;
      non_negative.reset(new optimization::non_negative_orthant(variables));

      this->variables = variables;
      this->init_point = init_point;
      this->solution_box = solution_box;
      this->solution_orthant = solution_orthant;
      this->lb = lb;
      this->ub = ub;
      this->lb_dbl = lb_dbl;
      this->ub_dbl = ub_dbl;
    }

    void test_non_negative(){
      std::shared_ptr<optimization::non_negative_orthant> non_negative;
      non_negative.reset(new optimization::non_negative_orthant(variables));
      DenseVector projected_point(variables);

      // Projection
      projected_point = init_point;
      non_negative->project(projected_point);
      TS_ASSERT(arma::approx_equal(solution_orthant, projected_point,"absdiff", 1e-10));

      // Not satisfied
      TS_ASSERT(not(non_negative->is_satisfied(init_point)));

      // Satisfied
      DenseVector test_point(variables);
      test_point.zeros(variables);
      TS_ASSERT(non_negative->is_satisfied(test_point));

    }

    void test_box(){

      // Vector init
      // -------------------------------------------------------
      std::shared_ptr<optimization::box_constraints> box;
      box.reset(new optimization::box_constraints(lb, ub));
      DenseVector projected_point(variables);

      // Projection
      projected_point = init_point;
      box->project(projected_point);
      TS_ASSERT(arma::approx_equal(solution_box, projected_point,"absdiff", 1e-10));

      // Not satisfied
      TS_ASSERT(not(box->is_satisfied(init_point)));
      DenseVector test_point(variables);
      test_point.zeros(variables);

      // Satisfied
      TS_ASSERT(box->is_satisfied(test_point));

      // Double init
      // -------------------------------------------------------
      box.reset(new optimization::box_constraints(lb_dbl, ub_dbl, variables));

      // Projection
      projected_point = init_point;
      box->project(projected_point);
      TS_ASSERT(arma::approx_equal(solution_box, projected_point,"absdiff", 1e-10));

      // Not satisfied
      TS_ASSERT(not(box->is_satisfied(init_point)));
      test_point.zeros(variables);

      // Satisfied
      TS_ASSERT(box->is_satisfied(test_point));

    }

};

BOOST_FIXTURE_TEST_SUITE(_constraint_interface_test, constraint_interface_test)
BOOST_AUTO_TEST_CASE(test_non_negative) {
  constraint_interface_test::test_non_negative();
}
BOOST_AUTO_TEST_CASE(test_box) {
  constraint_interface_test::test_box();
}
BOOST_AUTO_TEST_SUITE_END()


/* pcmsolver_copyright_start */
/*
 *     PCMSolver, an API for the Polarizable Continuum Model
 *     Copyright (C) 2013-2016 Roberto Di Remigio, Luca Frediani and contributors
 *
 *     This file is part of PCMSolver.
 *
 *     PCMSolver is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Lesser General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     PCMSolver is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Lesser General Public License for more details.
 *
 *     You should have received a copy of the GNU Lesser General Public License
 *     along with PCMSolver.  If not, see <http://www.gnu.org/licenses/>.
 *
 *     For information on the complete list of contributors to the
 *     PCMSolver API, see: <http://pcmsolver.readthedocs.io/>
 */
/* pcmsolver_copyright_end */

#include <catch.hpp>

#include <vector>
#include <cmath>

#include <Eigen/Core>

#include "cavity/GePolCavity.hpp"

TEST_CASE("Restart GePol cavity for an ammonia molecule", "[gepol][gepol_NH3_from-file]")
{
    GePolCavity cavity;
    cavity.loadCavity("nh3.npz");

    /*! \class GePolCavity
     *  \test \b GePolCavityNH3RestartTest_size tests GePol cavity size for ammonia loading the cavity from a .npz file
     */
    SECTION("Test size")
    {
        int size = 230;
        int actualSize = cavity.size();
        REQUIRE(size == actualSize);
    }

    /*! \class GePolCavity
     *  \test \b GePolCavityNH3RestartTest_area tests GePol cavity surface area for ammonia loading the cavity from from a .npz file
     */
    SECTION("Test area")
    {
        double area = 147.13247859942391;
        double actualArea = cavity.elementArea().sum();
        REQUIRE(area == Approx(actualArea));
    }

    /*! \class GePolCavity
     *  \test \b GePolCavityNH3RestartTest_volume tests GePol cavity volume for ammonia loading the cavity from from a .npz file
     */
    SECTION("Test volume")
    {
        double volume = 153.12929788519045;
        Eigen::Matrix3Xd elementCenter = cavity.elementCenter();
        Eigen::Matrix3Xd elementNormal = cavity.elementNormal();
        double actualVolume = 0;
        for ( int i = 0; i < cavity.size(); ++i ) {
            actualVolume += cavity.elementArea(i) * elementCenter.col(i).dot(elementNormal.col(
                        i));
        }
        actualVolume /= 3;
        REQUIRE(volume == Approx(actualVolume));
    }
}


#include <iostream>
#include <boost/asio.hpp>

using boost::asio::ip::tcp;

class WebServer{
    boost::asio::io_service io_service;
    tcp::endpoint endpoint;
    tcp::acceptor acceptor;

    void accept_request(){
        auto socket = std::make_shared<tcp::socket>(io_service);
        acceptor.async_accept(*socket, [this, socket](const boost::system::error_code &ec){
            accept_request();

            if(!ec){
                std::cout << "boop" << std::endl;
                handle_request(socket);
            }

        });
    }

    void handle_request(const std::shared_ptr<tcp::socket> &socket){
        auto read_buffer = std::make_shared<boost::asio::streambuf>();
        boost::asio::async_read_until(*socket, *read_buffer, "\r\n", [=](const boost::system::error_code &ec, size_t){
            if(!ec){
                std::string message;
                std::string failmessage;
                std::istream read_stream(read_buffer.get());
                std::getline(read_stream, message);
                message.pop_back();
                if(message == "exit") return;
                std::cout << message << std::endl;
                double a,b;
                bool isPlus = true;
                auto sep = message.find('+');
                if(sep == std::string::npos) {
                    sep = message.find('-');
                    if(sep == std::string::npos){
                        failmessage = "Couldn't find a + or -";
                    };
                    isPlus = false;
                }
                std::string s;
                try {
                    s = message.substr(0, sep);
                    a = std::stod(s);
                } catch(std::invalid_argument const &e){
                    failmessage = "Invalid argument " + s;
                } catch(std::out_of_range) {
                    failmessage = "First number too big/small";
                } catch (std::exception const& e) {
                    std::cout << typeid(e).name() << " from " << e.what() << std::endl;
                    return;
                }
                try {
                    s = message.substr(sep + 1);
                    b = std::stod(s);
                } catch(std::invalid_argument const &e) {
                    failmessage = "Invalid argument " + s;
                } catch(std::out_of_range) {
                    failmessage = "Second number too big/small";
                } catch (std::exception const& e) {
                    std::cout << typeid(e).name() << " from " << e.what() << std::endl;
                    return;
                }

                auto write_buffer = std::make_shared<boost::asio::streambuf>();
                std::ostream write_stream(write_buffer.get());
                if(failmessage.length()) write_stream << failmessage << "\r\n";
                else write_stream << (isPlus ? a+b : a-b) << "\r\n";

                // Write to client
                boost::asio::async_write(*socket, *write_buffer, [this, socket, write_buffer](const boost::system::error_code &ec, size_t) {
                    // If not error:
                    if (!ec) {
                        std::cout << "server: reply sent to client" << std::endl;
                        handle_request(socket);
                    }
                });

            }
        });
    }

public:
    WebServer() : endpoint(tcp::v4(), 8081), acceptor(io_service, endpoint){}

    void start(){
        accept_request();
        io_service.run();
    }

};

int main() {

    WebServer server;
    server.start();

    return 0;
}


//  (C) Copyright John Maddock 2000.
//  Use, modification and distribution are subject to 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/type_traits/is_void.hpp>

template <class T>
int dispatch_test_imp(const boost::mpl::bool_<true>&)
{
   return 0;
}
template <class T>
int dispatch_test_imp(const boost::mpl::bool_<false>&)
{
   return 1;
}

template <class T>
int dispatch_test()
{
   return dispatch_test_imp<T>(boost::is_void<T>());
}

int main()
{
   return (dispatch_test<int>() == 1) && (dispatch_test<void>() == 0) ? 0 : 1;
}


/**************************************************************************\
|
|    Copyright (C) 2009 Marc Stevens
|
|    This program is free software: you can redistribute it and/or modify
|    it under the terms of the GNU General Public License as published by
|    the Free Software Foundation, either version 3 of the License, or
|    (at your option) any later version.
|
|    This program is distributed in the hope that it will be useful,
|    but WITHOUT ANY WARRANTY; without even the implied warranty of
|    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
|    GNU General Public License for more details.
|
|    You should have received a copy of the GNU General Public License
|    along with this program.  If not, see <http://www.gnu.org/licenses/>.
|
\**************************************************************************/

#include <stdexcept>
#include <iostream>
#include <fstream>
#include <vector>
#include <string>

#include <boost/lexical_cast.hpp>
#include <boost/program_options.hpp>

#include "main.hpp"

#include <hashclash/sdr.hpp>
#include <hashclash/timer.hpp>

using namespace hashclash;
using namespace std;
namespace po = boost::program_options;
namespace fs = boost::filesystem;

std::string workdir;

int main(int argc, char** argv)
{
	hashclash::timer runtime(true);

	try {
		parameters_type parameters;
		vector< vector<unsigned> > msgmask(16);
		unsigned msgoffset = 0;
		bool msglcext = false;

		// Define program options
		po::options_description
			cmds("Allowed commands"),
			desc("Allowed options"),
			msg("Define message differences (as +bitnr and -bitnr, bitnr=1-32)"),
			all("Allowed options");

		cmds.add_options()
			("help,h",				"Show options\n")
			("convert",				"Convert files between binary and text\n")

			("split", po::value<unsigned>(&parameters.split),
									"Split inputfile1 in given # files\n")
			("join,j", po::value<vector<string> >(&parameters.files),
									"Join files and save to outputfile1\n"
									"Each filename has to be proceeded by -j\n")
			("pathfromtext",		"Load path in text form from inputfile1\n"
									"   and save as paths set to outputfile1\n")
			("showmespaceconditions", "Load me space from inputfile1\n   and show bitconditions\n")
			("filterfeasible", "Filter non-feasible differential paths")
			("select,s", "Select i-th path from set.")
			;
		desc.add_options()
			("workdir,w"
				, po::value<string>(&workdir)->default_value("./data")
				, "Set working directory.")

			("inputfile1"
				, po::value<string>(&parameters.infile1)->default_value("")
				, "Set inputfile 1.")
			("inputfile2"
				, po::value<string>(&parameters.infile2)->default_value("")
				, "Set inputfile 1.")
			("outputfile1"
				, po::value<string>(&parameters.outfile1)->default_value("")
				, "Set outputfile 1.")
			("outputfile2"
				, po::value<string>(&parameters.outfile2)->default_value("")
				, "Set outputfile 2.")
			("cpuaffinity"
				, po::value<int>(&parameters.cpuaffinity)->default_value(-1)
				, "Limit findcoll. to use only given cpu")
			("unique"
				, po::bool_switch(&parameters.unique)
				, "Only keep unique paths when joining or splitting.")
			("filtert"
				, po::value<int>(&parameters.filtert)->default_value(-4)
				, "Filter paths by having solutions up to Q_filtert.")
			("seli"
				, po::value<int>(&parameters.seli)->default_value(0)
				, "Select i-th path.")
			("invert"
				, po::bool_switch(&parameters.invert)
				, "Inverted selected path")
			("mod,m"
				, po::value<unsigned>(&parameters.mod)->default_value(1)
				, "Number of processes to split over.")
			("index,i"
				, po::value<unsigned>(&parameters.index)->default_value(0)
				, "Index of this process (icm --mod).")
			;

		msg.add_options()
			("diffm0", po::value< vector<unsigned> >(&msgmask[0]), "mask m0")
			("diffm1", po::value< vector<unsigned> >(&msgmask[1]), "mask m1")
			("diffm2", po::value< vector<unsigned> >(&msgmask[2]), "mask m2")
			("diffm3", po::value< vector<unsigned> >(&msgmask[3]), "mask m3")
			("diffm4", po::value< vector<unsigned> >(&msgmask[4]), "mask m4")
			("diffm5", po::value< vector<unsigned> >(&msgmask[5]), "mask m5")
			("diffm6", po::value< vector<unsigned> >(&msgmask[6]), "mask m6")
			("diffm7", po::value< vector<unsigned> >(&msgmask[7]), "mask m7")
			("diffm8", po::value< vector<unsigned> >(&msgmask[8]), "mask m8")
			("diffm9", po::value< vector<unsigned> >(&msgmask[9]), "mask m9")
			("diffm10", po::value< vector<unsigned> >(&msgmask[10]), "mask m10")
			("diffm11", po::value< vector<unsigned> >(&msgmask[11]), "mask m11")
			("diffm12", po::value< vector<unsigned> >(&msgmask[12]), "mask m12")
			("diffm13", po::value< vector<unsigned> >(&msgmask[13]), "mask m13")
			("diffm14", po::value< vector<unsigned> >(&msgmask[14]), "mask m14")
			("diffm15", po::value< vector<unsigned> >(&msgmask[15]), "mask m15")
			("diffoffset", po::value< unsigned >(&msgoffset), "mask offset")
			("difflcext", po::bool_switch(&msglcext), "extend to local coll.")
			;
		all.add(cmds).add(desc).add(msg);

		// Parse program options
		po::positional_options_description p;
		p.add("inputfile1", 1);
		p.add("inputfile2", 1);
		p.add("outputfile1", 1);
		p.add("outputfile2", 1);
		po::variables_map vm;
		po::store(po::command_line_parser(argc, argv)
			.options(all).positional(p).run(), vm);
		{
			std::ifstream ifs("sha1diffpathhelper.cfg");
			if (ifs) po::store(po::parse_config_file(ifs, all), vm);
		}
		po::notify(vm);

		// Process program options
		if (vm.count("help")
			|| 0 == 0
					+vm.count("convert")
					+vm.count("split")
					+vm.count("join")
					+vm.count("pathfromtext")
					+vm.count("showmespaceconditions")
					+vm.count("filterfeasible")
					+vm.count("select")
					) {
			cout << cmds << desc << endl;
			return 0;
		}

		uint32 me[16];
		for (unsigned k = 0; k < 16; ++k) {
			me[k] = 0;
			for (unsigned j = 0; j < msgmask[k].size(); ++j)
				me[k] |= 1<<msgmask[k][j];
		}
		sha1_me_generalised(parameters.m_mask, me, msgoffset);
		if (msglcext) {
			uint32 met[16];
			uint32 mex[80];
			for (unsigned i = 0; i < 16; ++i)
				met[i] = rotate_left(me[i],5);
			sha1_me_generalised(mex, met, msgoffset+1);
			for (unsigned i = 0; i < 80; ++i)
				parameters.m_mask[i] ^= mex[i];

			sha1_me_generalised(mex, me, msgoffset+2);
			for (unsigned i = 0; i < 80; ++i)
				parameters.m_mask[i] ^= mex[i];

			for (unsigned i = 0; i < 16; ++i)
				met[i] = rotate_left(me[i],30);
			for (unsigned j = 3; j < 6; ++j) {
				sha1_me_generalised(mex, met, msgoffset+j);
				for (unsigned i = 0; i < 80; ++i)
					parameters.m_mask[i] ^= mex[i];
			}
		}
		if (vm.count("convert"))
			return convert(parameters);
		if (vm.count("split"))
			return split(parameters);
		if (vm.count("join"))
			return join(parameters);
		if (vm.count("pathfromtext"))
			return pathfromtext(parameters);
		if (vm.count("showmespaceconditions"))
			return showmespaceconditions(parameters);
		if (vm.count("filterfeasible"))
			return filterfeasible(parameters);
		if (vm.count("select"))
			return selectpath(parameters);
		cout << "huh?!?" << endl;
	} catch (exception& e) {
		cout << "Runtime: " << runtime.time() << endl;
		cerr << "Caught exception!!:" << endl << e.what() << endl;
		throw;
	} catch (...) {
		cout << "Runtime: " << runtime.time() << endl;
		cerr << "Unknown exception caught!!" << endl;
		throw;
	}
	cout << "Runtime: " << runtime.time() << endl;
	return 0;
}

unsigned load_block(istream& i, uint32 block[])
{
	for (unsigned k = 0; k < 16; ++k)
		block[k] = 0;

	unsigned len = 0;
	char uc;
	for (unsigned k = 0; k < 16; ++k)
		for (unsigned c = 0; c < 4; ++c)
		{
			i.get(uc);
			if (i) {
				++len;
				block[k] += uint32((unsigned char)(uc)) << ((3-c)*8);
			} else {
				i.putback(uc);
				i.setstate(ios::failbit);
				return len;
			}
		}
	return len;
}

void save_block(ostream& o, uint32 block[])
{
	for (unsigned k = 0; k < 16; ++k)
		for (unsigned c = 0; c < 4; ++c)
			o << (unsigned char)((block[k]>>((3-c)*8))&0xFF);
}


/******************************************************************************
 *
 * Copyright (c) 2017, the Perspective Authors.
 *
 * This file is part of the Perspective library, distributed under the terms of
 * the Apache License 2.0.  The full license can be found in the LICENSE file.
 *
 */

#include <perspective/first.h>
#include <boost/math/special_functions/fpclassify.hpp>
#include <perspective/base.h>
#include <perspective/multi_sort.h>
#include <perspective/scalar.h>
#include <vector>

namespace perspective {

t_mselem::t_mselem()
    : m_pkey(mknone())
    , m_order(0)
    , m_deleted(false) {}

t_mselem::t_mselem(const t_tscalvec& row)
    : m_row(row)
    , m_pkey(mknone())
    , m_order(0)
    , m_deleted(false) {}

t_mselem::t_mselem(const t_tscalvec& row, t_uindex order)
    : m_row(row)
    , m_pkey(mknone())
    , m_order(order)
    , m_deleted(false) {}

t_mselem::t_mselem(const t_tscalar& pkey, const t_tscalvec& row)
    : m_row(row)
    , m_pkey(pkey)
    , m_order(0)
    , m_deleted(false) {}

t_mselem::t_mselem(const t_mselem& other) {
    m_pkey = other.m_pkey;
    m_row = other.m_row;
    m_deleted = other.m_deleted;
    m_order = other.m_order;
}

t_mselem::t_mselem(t_mselem&& other) {
    m_pkey = other.m_pkey;
    m_row = std::move(other.m_row);
    m_deleted = other.m_deleted;
    m_order = other.m_order;
}

t_mselem&
t_mselem::operator=(const t_mselem& other) {
    m_pkey = other.m_pkey;
    m_row = other.m_row;
    m_deleted = other.m_deleted;
    m_order = other.m_order;
    return *this;
}

t_mselem&
t_mselem::operator=(t_mselem&& other) {
    m_pkey = other.m_pkey;
    m_row = std::move(other.m_row);
    m_deleted = other.m_deleted;
    m_order = other.m_order;
    return *this;
}

t_minmax_idx::t_minmax_idx(t_index mn, t_index mx)
    : m_min(mn)
    , m_max(mx) {}

// Given a vector return the indices of the
// minimum and maximum elements in it.
t_minmax_idx
get_minmax_idx(const t_tscalvec& vec, t_sorttype stype) {
    t_minmax_idx rval(-1, -1);

    if (vec.empty())
        return rval;

    // min, max
    std::pair<t_tscalar, t_tscalar> min_max;
    min_max.first = *(vec.begin());
    min_max.second = *(vec.begin());

    switch (stype) {
        case SORTTYPE_DESCENDING:
        case SORTTYPE_ASCENDING: {
            for (t_index idx = 0, loop_end = vec.size(); idx < loop_end; ++idx) {
                const t_tscalar& val = vec[idx];
                if (val <= min_max.first) {
                    min_max.first = val;
                    rval.m_min = idx;
                }

                if (val >= min_max.second) {
                    min_max.second = val;
                    rval.m_max = idx;
                }
            }
            return rval;
        } break;
        case SORTTYPE_ASCENDING_ABS:
        case SORTTYPE_DESCENDING_ABS: {
            for (t_index idx = 0, loop_end = vec.size(); idx < loop_end; ++idx) {
                t_float64 val = std::abs(vec[idx].to_double());
                t_float64 mindbl = std::abs(t_float64(min_max.first));
                t_float64 maxdbl = std::abs(t_float64(min_max.second));

                if (val <= mindbl) {
                    min_max.first.set(val);
                    rval.m_min = idx;
                }

                if (val >= maxdbl) {
                    min_max.second.set(val);
                    rval.m_max = idx;
                }
            }
            return rval;
        } break;
        case SORTTYPE_NONE: {
            rval.m_min = 0;
            rval.m_max = 0;
            return rval;
        } break;
        default: { return rval; }
    }

    return rval;
}

t_float64
to_double(const t_tscalar& c) {
    return c.to_double();
}

t_nancmp::t_nancmp()
    : m_active(false)
    , m_cmpval(CMP_OP_EQ) {}

t_nancmp
nan_compare(t_sorttype order, const t_tscalar& a, const t_tscalar& b) {
    t_nancmp rval;
    t_bool a_fp = a.is_floating_point();
    t_bool b_fp = b.is_floating_point();

    if (!a_fp && !b_fp)
        return rval;

    t_float64 a_dbl = a.to_double();
    t_float64 b_dbl = b.to_double();

    t_bool a_nan = boost::math::isnan(a_dbl);
    t_bool b_nan = boost::math::isnan(b_dbl);

    rval.m_active = a_nan || b_nan;

    if (!rval.m_active)
        return rval;

    if (a_nan && b_nan) {
        rval.m_cmpval = CMP_OP_EQ;
        return rval;
    }

    if (a_nan) {
        switch (order) {
            case SORTTYPE_NONE:
            case SORTTYPE_ASCENDING:
            case SORTTYPE_ASCENDING_ABS: {
                rval.m_cmpval = CMP_OP_LT;
            } break;
            case SORTTYPE_DESCENDING_ABS:
            case SORTTYPE_DESCENDING: {
                rval.m_cmpval = CMP_OP_GT;
            } break;
        }
        return rval;
    }

    switch (order) {
        case SORTTYPE_NONE:
        case SORTTYPE_ASCENDING:
        case SORTTYPE_ASCENDING_ABS: {
            rval.m_cmpval = CMP_OP_GT;
        } break;
        case SORTTYPE_DESCENDING_ABS:
        case SORTTYPE_DESCENDING: {
            rval.m_cmpval = CMP_OP_LT;
        } break;
    }

    return rval;
}

t_multisorter::t_multisorter(const t_sorttvec& order, t_bool handle_nans)
    : m_sort_order(order)
    , m_handle_nans(handle_nans) {}

t_multisorter::t_multisorter(
    t_mselemvec_csptr elems, const t_sorttvec& order, t_bool handle_nans)
    : m_sort_order(order)
    , m_elems(elems)
    , m_handle_nans(handle_nans) {}

t_bool
t_multisorter::operator()(const t_mselem& a, const t_mselem& b) const {
    return cmp_mselem(a, b, m_sort_order, m_handle_nans);
}

t_bool
t_multisorter::operator()(t_index a, t_index b) const {
    return this->operator()((*m_elems)[a], (*m_elems)[b]);
}

} // end namespace perspective


#ifndef __TRIAL_HPP__
#define __TRIAL_HPP__

#include <armadillo>
#include <random>
#include <cmath>
#include <vector>
#include <initializer_list>
#include "seed.hpp"

namespace pauth {

/*! \brief Trial move for continuous degrees of freedom e.g. positions in space
 */
class continuous_trial_move {
public:
  /*! \brief Trial move generator for a continuous monte carlo phase space
   *
   * \param     delta_max     Maximum step size
   * \param     sg            Seed generator
   * \return                  Trial move generator
   */
  continuous_trial_move(const double delta_max, seed_gen sg = _default_seed_gen)
    : _delta_dist(-delta_max, delta_max) { _rng.seed(sg()); }

  /*! \brief Copy constructor for continuous trial move generator
   *
   * \param     ctm           Continuous trial move generator
   * \param     sg            Seed generator
   * \return                  Copy
   */
  continuous_trial_move(const continuous_trial_move &ctm,
                        seed_gen sg = _default_seed_gen)
    : _delta_dist(ctm._delta_dist.param()) { _rng.seed(sg()); }

  /*! \brief Generators trial moves for a continuous phase space
   *
   * \param     positions     Molecular positions
   * \param     j             Index of molecule to move
   * \return                  Trial move
   */
  arma::vec operator()(const arma::mat &positions, const size_t) {
    arma::vec dx(positions.n_rows);
    for (size_t i = 0; i < positions.n_rows; ++i) dx(i) = _delta_dist(_rng);
    return dx;
  }

private:
  std::uniform_real_distribution<double> _delta_dist;
  std::default_random_engine _rng;
};

/*! \brief Trial move for discrete states as opposed to continuous positions
 */
class state_trial_move {
public:
  /*! \brief Trial move generator for a phase space that consists of "states"
   *
   * \param     num_states     Number of available states
   * \param     sg             Seed generator
   * \return                   Trial move generator
   */
  state_trial_move(const unsigned num_states = 2,
                   seed_gen sg = _default_seed_gen)
    : _state_dist(0, num_states-1) { _rng.seed(sg()); }

  /*! \brief Copy constructor for state trial move generator
   *
   * \param     stm           State trial move generator
   * \param     sg            Seed generator
   * \return                  Copy
   */
  state_trial_move(const state_trial_move &stm, seed_gen sg = _default_seed_gen)
    : _state_dist(stm._state_dist.param()) { _rng.seed(sg()); }

  /*! \brief Generates trial move for a two-state system
   *
   * \param     positions     Molecular positions
   * \param     j             Index of molecule to move
   * \return                  Trial move
   */
  arma::vec operator()(const arma::mat &positions, const size_t j) {
    arma::vec dx(1);
    dx(0) = _state_dist(_rng);
    return dx - positions(0, j);
  }

private:
  std::uniform_int_distribution<unsigned> _state_dist;
  std::default_random_engine _rng;
};

/*! \brief Direct sampling trial move generator
 */
template <class T> class direct_sample {
public:
  /*! \brief Trial move generator for direct sampling by distributions
   *
   * \param     dists          Sampling distributions
   * \param     sg             Seed generator
   * \return                   Trial move generator
   */
  direct_sample<T>(std::initializer_list<T> dists,
                   seed_gen sg = _default_seed_gen) : _dof_dists(dists),
    _choice_dist(0, _dof_dists.size()-1) {
    _rng.seed(sg());
  }

  /*! \brief Trial move generator for direct sampling by a distribution
   *
   * \param     dist           Sampling distribution
   * \param     N              Degrees of freedom per particle
   * \param     sg             Seed generator
   * \return                   Trial move generator
   */
  direct_sample<T>(T dist, size_t N, seed_gen sg = _default_seed_gen) :
    _dof_dists(dist, N), _choice_dist(0, _dof_dists.size()-1) {
    _rng.seed(sg());
  }

  /*! \brief Generates trial move for a two-state system
   *
   * \param     positions     Molecular positions
   * \param     j             Index of molecule to move
   * \return                  Trial move
   */
  arma::vec operator()(const arma::mat &positions, const size_t j) {
    auto dx = arma::zeros<arma::vec>(_dof_dists.size());
    auto choice = _rng(_choice_dist); // choose a degree of freedom
    // directly sample a degree of freedom from its associated distribution
    dx(choice) = _rng(_dof_dists(choice)) - positions(choice, j);
    return dx;
  }

private:
  std::vector<T> _dof_dists;
  std::uniform_int_distribution<size_t> _choice_dist;
  std::default_random_engine _rng;
};

}

#endif


// ======================================================================
/*!
 * \brief SmartMet download service plugin implementation
 */
// ======================================================================

#include "Plugin.h"
#include "DataStreamer.h"
#include "GribStreamer.h"
#include "NetCdfStreamer.h"
#include "Query.h"
#include "QueryDataStreamer.h"
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/scoped_ptr.hpp>
#include <cmath>
#include <cpl_conv.h>
#include <iostream>
#include <limits>
#include <macgyver/Exception.h>
#include <macgyver/HelmertTransformation.h>
#include <macgyver/StringConversion.h>
#include <macgyver/TimeFormatter.h>
#include <macgyver/TimeParser.h>
#include <macgyver/TimeZoneFactory.h>
#include <newbase/NFmiQueryData.h>
#include <spine/Convenience.h>
#include <spine/Reactor.h>
#include <spine/SmartMet.h>
#include <spine/Table.h>
#include <stdexcept>

#include <cpl_conv.h>

using namespace std;
using namespace boost::posix_time;
using namespace boost::gregorian;
using namespace boost::local_time;

namespace SmartMet
{
namespace Plugin
{
namespace Download
{
// ----------------------------------------------------------------------
/*!
 * \brief Can the plugin handle the parameter?
 */
// ----------------------------------------------------------------------

bool special(const Spine::Parameter &theParam)
{
  try
  {
    switch (theParam.type())
    {
      case Spine::Parameter::Type::Data:
      case Spine::Parameter::Type::Landscaped:
        return false;
      case Spine::Parameter::Type::DataDerived:
      case Spine::Parameter::Type::DataIndependent:
        return true;
    }
    // ** NOT REACHED **
    return true;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Get projection type
 */
// ----------------------------------------------------------------------

static ProjType getProjectionType(ReqParams &reqParams)
{
  try
  {
    typedef struct
    {
      const char *proj;
      AreaClassId acid;
    } projareas;

    static projareas projections[] = {{"epsg:", A_Native},
                                      {"latlon", A_LatLon},
                                      {"rotlatlon", A_RotLatLon},
                                      {"stereographic", A_PolarStereoGraphic},
                                      {"mercator", A_Mercator},
                                      {nullptr, A_Native}};

    // If request datum is 'epsg', check epsg projection for implied datum shift to wgs84.

    bool checkDatum = (reqParams.datumShift == Datum::DatumShift::Epsg);

    if (checkDatum)
      reqParams.datumShift = Datum::DatumShift::None;

    reqParams.areaClassId = A_Native;

    if (reqParams.projection.empty())
      return P_Native;

    string proj(Fmi::ascii_tolower_copy(reqParams.projection));
    unsigned int i = 0;

    for (; projections[i].proj; i++)
      if (proj.find(projections[i].proj) == 0)
      {
        if (i == 0)
        {
          try
          {
            // epsg:n. Latlon is handled as newbase projection to enable cropping.
            //
            // We do not check other/projected coordsystem's projection parameters to
            // detect if they match querydata's native projection; cropping is not possible.
            //
            OGRSpatialReference srs;
            OGRErr err;

            reqParams.epsgCode =
                boost::lexical_cast<EpsgCode>(proj.substr(strlen(projections[i].proj)));

            if ((err = srs.importFromEPSG(reqParams.epsgCode)) != OGRERR_NONE)
              throw Fmi::Exception(BCP,
                                     "srs.importFromEPSG(" +
                                         boost::lexical_cast<string>(reqParams.epsgCode) +
                                         ") error " + boost::lexical_cast<string>(err));

            if (checkDatum)
            {
              const char *datum = srs.GetAttrValue("DATUM");

              if (Fmi::ascii_toupper_copy(string(datum ? datum : "")) == Datum::epsgWGS84DatumName)
                reqParams.datumShift = Datum::DatumShift::Wgs84;
            }

            if (!srs.IsProjected())
            {
              reqParams.projection = "latlon";
              return getProjectionType(reqParams);
            }

            return P_Epsg;
          }
          catch (...)
          {
            break;
          }
        }
        else
        {
          reqParams.areaClassId = projections[i].acid;
          return ProjType(P_Native + i);
        }
      }

    throw Fmi::Exception(BCP, "Unsupported projection '" + reqParams.projection + "'");
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Get request parameters.
 */
// ----------------------------------------------------------------------

string getRequestParam(const Spine::HTTP::Request &req,
                       const Producer &producer,
                       const char *urlParam,
                       string defaultValue)
{
  try
  {
    string str = (producer.disabledReqParam(urlParam)
                      ? defaultValue
                      : Spine::optional_string(req.getParameter(urlParam), defaultValue));
    boost::trim(str);
    return str;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

int getRequestInt(const Spine::HTTP::Request &req,
                  const Producer &producer,
                  const char *urlParam,
                  int defaultValue)
{
  try
  {
    return (producer.disabledReqParam(urlParam)
                ? defaultValue
                : Spine::optional_int(req.getParameter(urlParam), defaultValue));
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

unsigned long getRequestUInt(const Spine::HTTP::Request &req,
                             const Producer &producer,
                             const char *urlParam,
                             uint defaultValue)
{
  try
  {
    return (producer.disabledReqParam(urlParam)
                ? defaultValue
                : Spine::optional_unsigned_long(req.getParameter(urlParam), defaultValue));
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

static const Producer &getRequestParams(const Spine::HTTP::Request &req,
                                        ReqParams &reqParams,
                                        Config &config,
                                        const Engine::Querydata::Engine &qEngine,
                                        const Engine::Grid::Engine *gridEngine)
{
  try
  {
    // Data source

    static Producer dummyProducer;
    reqParams.source = getRequestParam(req, dummyProducer, "source", "querydata");

    if (reqParams.source == "querydata")
      reqParams.dataSource = QueryData;
    else if (reqParams.source == "grid")
      reqParams.dataSource = Grid;
    else
      throw Fmi::Exception(BCP, "Unknown source '" + reqParams.source +
                             "', 'querydata' or 'grid' expected");

    if (reqParams.dataSource == Grid)
    {
      if (!gridEngine)
        throw Fmi::Exception(BCP, "Grid data is not available");
      else if (!(gridEngine->isEnabled()))
        throw Fmi::Exception(BCP, "Grid data is disabled");
    }

    // Producer is speficied using 'model' or 'producer' keyword.

    string model = getRequestParam(req, config.defaultProducer(), "model", "");
    reqParams.producer = getRequestParam(req, config.defaultProducer(), "producer", "");

    if (!reqParams.producer.empty())
    {
      if ((!model.empty()) && (model != reqParams.producer))
        throw Fmi::Exception(BCP, "Cannot specify model and producer simultaneously");
    }
    else
      reqParams.producer = (model.empty() ? config.defaultProducerName() : model);

    const Producer &producer = config.getProducer(reqParams.producer, qEngine);

    /*
    TODO: no qEngine dependency with grid data

    const Producer &producer = (reqParams.dataSource == QueryData)
      ? config.getProducer(reqParams.producer, qEngine)
      : config.getProducer(reqParams.producer, qEngine);
//    : dummyProducer;
    */

    if (reqParams.producer.empty())
      throw Fmi::Exception(BCP, "No producer");

    // Time related parameters. Detect special value 'data'.

    reqParams.startTime = getRequestParam(req, producer, "starttime", "");
    reqParams.endTime = getRequestParam(req, producer, "endtime", "");
    reqParams.originTime = getRequestParam(req, producer, "origintime", "");
    reqParams.timeSteps = getRequestUInt(req, producer, "timesteps", 0);
    reqParams.maxTimeSteps = getRequestUInt(req, producer, "maxtimesteps", 0);

    string timeStepStr = getRequestParam(req, producer, "timestep", "");
    reqParams.timeStep =
        ((timeStepStr != "data") ? getRequestUInt(req, producer, "timestep", 0) : 0);

    if (reqParams.startTime == "data")
      reqParams.startTime.clear();
    if (reqParams.endTime == "data")
      reqParams.endTime.clear();
    if (reqParams.originTime == "data")
      reqParams.originTime.clear();

    // Level (pressure/hPa or hybrid or height level) and height (meters) ranges/limits
    //
    // Note: height (meters) range query currently not implemented

    reqParams.minLevel = getRequestInt(req, producer, "minlevel", -1);
    reqParams.maxLevel = getRequestInt(req, producer, "maxlevel", -1);

    reqParams.minHeight = reqParams.maxHeight = -1;

    // Datum handling

    reqParams.datum = getRequestParam(req, producer, "datum", "");

    if (!Datum::parseDatumShift(reqParams.datum, reqParams.datumShift))
      throw Fmi::Exception(BCP, "Invalid datum selected");

    // Projection, bounding and grid size/step

    reqParams.projection = getRequestParam(req, producer, "projection", "");
    if (reqParams.dataSource == QueryData)
      reqParams.projType = getProjectionType(reqParams);

    if ((reqParams.projType == P_Epsg) && (reqParams.datumShift == Datum::DatumShift::None))
      // gdal/proj4 needed for projection
      //
      reqParams.datumShift = Datum::DatumShift::Fmi;

    reqParams.bbox = reqParams.origBBox = getRequestParam(req, producer, "bbox", "");
    reqParams.gridCenter = getRequestParam(req, producer, "gridcenter", "");
    reqParams.gridSize = getRequestParam(req, producer, "gridsize", "");
    reqParams.gridResolution = getRequestParam(req, producer, "gridresolution", "");
    reqParams.gridStep = getRequestParam(req, producer, "gridstep", "");

    if (!reqParams.bbox.empty())
      // Bottom left lon,lat and top right lon,lat; bllon,bllat,trlon,trlat
      //
      reqParams.bboxRect = nPairsOfValues<double>(reqParams.bbox, "bbox", 2);

    if (!reqParams.gridCenter.empty())
    {
      // Grid center lon,lat and width and height in km; lon,lat,width,height
      //
      if (reqParams.bboxRect)
        throw Fmi::Exception(BCP, "Cannot specify gridcenter and bbox simultaneously");

      reqParams.gridCenterLL = nPairsOfValues<double>(reqParams.gridCenter, "gridcenter", 2);
    }

    if (!reqParams.gridSize.empty())
      // Absolute grid size; nx,ny
      //
      reqParams.gridSizeXY = nPairsOfValues<unsigned int>(reqParams.gridSize, "gridsize", 1);

    if (!reqParams.gridResolution.empty())
    {
      // Grid cell size; width,height in km
      //
      if (reqParams.gridSizeXY)
        throw Fmi::Exception(BCP, "Cannot specify gridsize and gridresolution simultaneously");

      reqParams.gridResolutionXY =
          nPairsOfValues<double>(reqParams.gridResolution, "gridresolution", 1);
    }

    if (!reqParams.gridStep.empty())
      // Grid step to extract every dx'th/dy'th value; dx,dy
      //
      reqParams.gridStepXY = nPairsOfValues<unsigned int>(reqParams.gridStep, "gridstep", 1);

    // Output format

    reqParams.format = getRequestParam(req, producer, "format", "");
    Fmi::ascii_toupper(reqParams.format);

    if (reqParams.format == "GRIB1")
      reqParams.outputFormat = Grib1;
    else if (reqParams.format == "GRIB2")
      reqParams.outputFormat = Grib2;
    else if (reqParams.format == "NETCDF")
      reqParams.outputFormat = NetCdf;
    else if (reqParams.format == "QD")
    {
      if (reqParams.dataSource == Grid)
        throw Fmi::Exception(BCP, "Querydata format not supported with grid data");

      reqParams.outputFormat = QD;
    }
    else if (reqParams.format.empty())
      throw Fmi::Exception(BCP, "No format selected");
    else
      throw Fmi::Exception(BCP, "Invalid format selected");

    if ((reqParams.outputFormat == QD) && (!reqParams.gridStep.empty()))
      throw Fmi::Exception(BCP, "Cannot specify gridstep when using qd format");

    // Packing type for grib. Set to grib as given (converted to lowercase only)

    reqParams.packing = getRequestParam(req, producer, "packing", "");
    Fmi::ascii_tolower(reqParams.packing);

    if (!reqParams.packing.empty())
    {
      if ((reqParams.outputFormat != Grib1) && (reqParams.outputFormat != Grib2))
        throw Fmi::Exception(BCP, "Packing can be specified with grib format only")
            .addParameter("packing", reqParams.packing);

      auto msg = config.packingErrorMessage(reqParams.packing);
      if (!msg.empty())
        throw Fmi::Exception(BCP, msg).addParameter("packing", reqParams.packing);
    }

    // Tables version for grib2

    reqParams.grib2TablesVersion =
        ((reqParams.outputFormat == Grib2) ? getRequestUInt(req, producer, "tablesversion", 0) : 0);

    if (reqParams.grib2TablesVersion > 0)
    {
      // Check against valid range. The default range is [0-0] letting all values thru
      //
      auto range = config.getGrib2TablesVersionRange();
      auto grib2TablesVersionMin = range.first, grib2TablesVersionMax = range.second;

      if ((grib2TablesVersionMax > 0) && ((reqParams.grib2TablesVersion < grib2TablesVersionMin) ||
                                          (reqParams.grib2TablesVersion > grib2TablesVersionMax)))
        throw Fmi::Exception(BCP,
                               "'tablesversion' must be between " +
                                   Fmi::to_string(grib2TablesVersionMin) + " and " +
                                   Fmi::to_string(grib2TablesVersionMax));
    }

    // For misc testing
    //

    reqParams.test = getRequestUInt(req, producer, "test", 0);

    return producer;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Get parameter scale factor and offset
 */
// ----------------------------------------------------------------------

static bool getScaleFactorAndOffset(signed long id,
                                    float *scale,
                                    float *offset,
                                    const ParamChangeTable &ptable)
{
  try
  {
    for (size_t i = 0; i < ptable.size(); ++i)
    {
      // Note: conversion in reverse direction!
      if (id == ptable[i].itsWantedParam.GetIdent())
      {
        *scale = ptable[i].itsConversionScale;
        *offset = ptable[i].itsConversionBase;
        return true;
      }
    }

    return false;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Check that configuration exists for the requested parameters
 *		and get scale and offset for grib output.
 *
 * 		Unknown (and special) parameters are ignored.
 *
 * 		Returns true if all parameters are known. The known
 * 		parameters are set to knownParams.
 */
// ----------------------------------------------------------------------

static bool getParamConfig(const ParamChangeTable &pTable,
                           const Spine::OptionParsers::ParameterList &reqParams,
                           Spine::OptionParsers::ParameterList &knownParams,
                           Scaling &scaling)
{
  try
  {
    knownParams.clear();

    if (pTable.empty())
      return false;

    std::list<unsigned int> missingParams;
    float scale = 1.0, offset = 0.0;
    unsigned int i = 0;

    BOOST_FOREACH (Spine::Parameter param, reqParams)
    {
      // We allow special params too if they have a number (WindUMS and WindVMS)
      bool ok = (param.number() > 0);

      if (ok)
      {
        int id = param.number();
        unsigned long lid = boost::numeric_cast<unsigned long>(id);
        ok = getScaleFactorAndOffset(lid, &scale, &offset, pTable);
      }

      if (!ok)
        missingParams.push_back(i);
      else
        scaling.push_back(Scaling::value_type(scale, offset));

      i++;
    }

    std::list<unsigned int>::const_iterator itm = missingParams.begin();
    i = 0;

    BOOST_FOREACH (Spine::Parameter param, reqParams)
    {
      if ((itm != missingParams.end()) && (i == *itm))
        itm++;
      else
        knownParams.push_back(param);

      i++;
    }

    return (missingParams.size() == 0);
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Get download file name.
 *
 */
// ----------------------------------------------------------------------

static string getDownloadFileName(const string &producer,
                                  const ptime &originTime,
                                  const ptime &startTime,
                                  const ptime &endTime,
                                  const string &projection,
                                  OutputFormat outputFormat)
{
  try
  {
    string sTime, eTime;

    if (startTime.is_not_a_date_time())
      sTime = "start";
    else
      sTime = Fmi::to_iso_string(startTime);

    if (endTime.is_not_a_date_time())
      eTime = "end";
    else
      eTime = Fmi::to_iso_string(endTime);

    const char *extn;

    if (outputFormat == Grib1)
      extn = ".grb";
    else if (outputFormat == Grib2)
      extn = ".grb2";
    else if (outputFormat == NetCdf)
      extn = ".nc";
    else
      extn = ".sqd";

    return producer + "_" + Fmi::to_iso_string(originTime) + "_" + sTime + "_" + eTime +
           (!projection.empty() ? ("_" + projection) : "") + extn;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Initialize data streamer for chunking
 *
 */
// ----------------------------------------------------------------------

static boost::shared_ptr<DataStreamer> initializeStreamer(const Spine::HTTP::Request &req,
                                                          const Engine::Querydata::Engine &qEngine,
                                                          const Engine::Grid::Engine *gridEngine,
                                                          const Engine::Geonames::Engine *geoEngine,
                                                          Query &query,
                                                          Config &config,
                                                          string &fileName)
{
  try
  {
    // Get request parameters.

    ReqParams reqParams;
    const auto &producer = getRequestParams(req, reqParams, config, qEngine, gridEngine);

    // Create format specific streamer and get scaling information for the requested parameters.
    // Unknown (and special) parameters are ignored.

    boost::shared_ptr<DataStreamer> ds;
    Spine::OptionParsers::ParameterList knownParams;
    Scaling scaling;

    if ((reqParams.outputFormat == Grib1) || (reqParams.outputFormat == Grib2))
    {
      ds = boost::shared_ptr<DataStreamer>(new GribStreamer(req, config, producer, reqParams));
      getParamConfig(
          config.getParamChangeTable(), query.pOptions.parameters(), knownParams, scaling);
    }
    else if (reqParams.outputFormat == NetCdf)
    {
      ds = boost::shared_ptr<DataStreamer>(new NetCdfStreamer(req, config, producer, reqParams));
      getParamConfig(
          config.getParamChangeTable(false), query.pOptions.parameters(), knownParams, scaling);
    }
    else
    {
      ds = boost::shared_ptr<DataStreamer>(new QDStreamer(req, config, producer, reqParams));

      BOOST_FOREACH (Spine::Parameter param, query.pOptions.parameters())
      {
        knownParams.push_back(param);
      }
    }

    if (knownParams.empty())
      throw Fmi::Exception(
          BCP,
          "initStreamer: No known parameters available for producer '" + reqParams.producer + "'");

    if ((reqParams.outputFormat != QD) && (scaling.size() != knownParams.size()))
      throw Fmi::Exception(BCP, "initStreamer: internal: Parameter/scaling data mismatch");

    ds->setParams(knownParams, scaling);

    // Set engines

    ds->setEngines(&qEngine, gridEngine, geoEngine);

    // Get Q object for the producer/origintime

    ptime originTime, startTime, endTime;

    Engine::Querydata::Q q;

    if (reqParams.dataSource == QueryData)
    {
      ds->setMultiFile(qEngine.getProducerConfig(reqParams.producer).ismultifile);

      if (!reqParams.originTime.empty())
      {
        if (reqParams.originTime == "latest" || reqParams.originTime == "newest")
          originTime = boost::posix_time::ptime(boost::date_time::pos_infin);
        else if (reqParams.originTime == "oldest")
          originTime = boost::posix_time::ptime(boost::date_time::neg_infin);
        else
          originTime = Fmi::TimeParser::parse(reqParams.originTime);
        q = qEngine.get(reqParams.producer, originTime);
        originTime = q->originTime();
      }
      else
      {
        q = qEngine.get(reqParams.producer);
      }
    }
    else
      ds->setMultiFile(producer.multiFile);

    // Overwrite timeparsers's starttime (now --> data), endtime (starttime + 24h --> data) and
    // timestep (60m --> data) defaults.
    // However, if 'now' request parameter is set, use the parsed starttime.

    auto now = getRequestParam(req, producer, "now", "");

    if ((!reqParams.startTime.empty()) || (!now.empty()))
      startTime = query.tOptions.startTime;

    if (!reqParams.endTime.empty())
      endTime = query.tOptions.endTime;

    query.tOptions.startTimeData = startTime.is_not_a_date_time();
    query.tOptions.timeStep = reqParams.timeStep;
    query.tOptions.endTimeData = (reqParams.endTime.empty() && (reqParams.timeStep == 0));

    if (reqParams.dataSource == QueryData)
    {
      // Generate list of validtimes for the data to be loaded.
      // For grid data validtimes are generated after checking data availability

      ds->generateValidTimeList(q, query, originTime, startTime, endTime);

      // Set request levels.
      // For grid data levels are set after checking data availability

      ds->setLevels(query);
    }

    // In order to set response status check if (any) data is available for the requested
    // levels, parameters and time range

    if (!ds->hasRequestedData(producer, query, originTime, startTime, endTime))
      throw Fmi::Exception(
          BCP, "initStreamer: No data available for producer '" + reqParams.producer + "'");

    // Download file name

    string projection = boost::algorithm::replace_all_copy(reqParams.projection, " ", "_");
    boost::algorithm::replace_all(projection, ",", ":");

    fileName = getDownloadFileName(reqParams.producer,
                                   originTime,
                                   startTime,
                                   endTime,
                                   projection,
                                   reqParams.outputFormat);

    // Set parameter and level iterators etc. to their start positions

    ds->resetDataSet();

    return ds;
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Perform a download service query
 */
// ----------------------------------------------------------------------

void Plugin::query(const Spine::HTTP::Request &req, Spine::HTTP::Response &response)
{
  try
  {
    // asm volatile ("int3;");

    // Options

    Query query(req, itsConfig, itsQEngine);

    // Initialize streamer.

    string filename;
    response.setContent(
        initializeStreamer(req, *itsQEngine, itsGridEngine, itsGeoEngine, query, itsConfig, filename));

    string mime = "application/octet-stream";
    response.setHeader("Content-type", mime.c_str());
    response.setHeader("Content-Disposition",
                       (string("attachement; filename=") + filename).c_str());
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Main content handler
 */
// ----------------------------------------------------------------------

void Plugin::requestHandler(Spine::Reactor & /* theReactor */,
                            const Spine::HTTP::Request &theRequest,
                            Spine::HTTP::Response &theResponse)
{
  try
  {
    bool isdebug = false;

    try
    {
      const int expires_seconds = 60;
      ptime t_now = second_clock::universal_time();

      // Excecuting the query

      query(theRequest, theResponse);
      theResponse.setStatus(Spine::HTTP::Status::ok);

      // Defining the response header information

      ptime t_expires = t_now + seconds(expires_seconds);
      boost::shared_ptr<Fmi::TimeFormatter> tformat(Fmi::TimeFormatter::create("http"));
      std::string cachecontrol =
          "public, max-age=" + boost::lexical_cast<std::string>(expires_seconds);
      std::string expiration = tformat->format(t_expires);
      std::string modification = tformat->format(t_now);

      theResponse.setHeader("Cache-Control", cachecontrol.c_str());
      theResponse.setHeader("Expires", expiration.c_str());
      theResponse.setHeader("Last-Modified", modification.c_str());

      /* This will need some thought
      if(response.first.size() == 0)
      {
              std::cerr << "Warning: Empty input for request "
                                << theRequest.getOriginalQueryString()
                                << " from "
                                << theRequest.getClientIP()
                                << std::endl;
      }
      */
    }
    catch (...)
    {
      // Catching all exceptions

      Fmi::Exception exception(BCP, "Request processing exception!", nullptr);
      exception.addParameter("URI", theRequest.getURI());
      exception.addParameter("ClientIP", theRequest.getClientIP());
      exception.printError();

      if (isdebug)
      {
        // Delivering the exception information as HTTP content
        std::string fullMessage = exception.getHtmlStackTrace();
        theResponse.setContent(fullMessage);
        theResponse.setStatus(Spine::HTTP::Status::ok);
      }
      else
      {
        theResponse.setStatus(Spine::HTTP::Status::bad_request);
      }

      // Adding the first exception information into the response header

      std::string msg = exception.what();
      boost::algorithm::replace_all(msg, "\n", " ");
      msg = msg.substr(0, 300);
      theResponse.setHeader("X-Download-Error", msg.c_str());
    }
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Plugin constructor
 */
// ----------------------------------------------------------------------

Plugin::Plugin(Spine::Reactor *theReactor, const char *theConfig)
    : SmartMetPlugin(), itsModuleName("Download"), itsConfig(theConfig), itsReactor(theReactor)
{
  try
  {
    if (theReactor->getRequiredAPIVersion() != SMARTMET_API_VERSION)
    {
      std::cerr << "*** Download Plugin and Server SmartMet API version mismatch ***" << std::endl;
      return;
    }
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Initializator
 */
// ----------------------------------------------------------------------
void Plugin::init()
{
  try
  {
    /* Dont't let the NetCDF library crash the server */
    ncopts = NC_VERBOSE;

    /* QEngine */

    auto *engine = itsReactor->getSingleton("Querydata", nullptr);
    if (!engine)
      throw Fmi::Exception(BCP, "Querydata engine unavailable");
    itsQEngine = reinterpret_cast<Engine::Querydata::Engine *>(engine);

    /* GridEngine */

    engine = itsReactor->getSingleton("grid", nullptr);
    itsGridEngine = reinterpret_cast<Engine::Grid::Engine *>(engine);

    /* GeoEngine */

    engine = itsReactor->getSingleton("Geonames", nullptr);
    if (!engine)
      throw Fmi::Exception(BCP, "Geonames engine unavailable");
    itsGeoEngine = reinterpret_cast<Engine::Geonames::Engine *>(engine);

    itsConfig.init(itsQEngine);

    if (!itsReactor->addContentHandler(
            this, "/download", boost::bind(&Plugin::callRequestHandler, this, _1, _2, _3)))
      throw Fmi::Exception(BCP, "Failed to register download content handler");
  }
  catch (...)
  {
    throw Fmi::Exception::Trace(BCP, "Operation failed!");
  }
}

// ----------------------------------------------------------------------
/*!
 * \brief Shutdown the plugin
 */
// ----------------------------------------------------------------------

void Plugin::shutdown()
{
  std::cout << "  -- Shutdown requested (dls)\n";
}

// ----------------------------------------------------------------------
/*!
 * \brief Destructor
 */
// ----------------------------------------------------------------------

Plugin::~Plugin() {}

// ----------------------------------------------------------------------
/*!
 * \brief Return the plugin name
 */
// ----------------------------------------------------------------------

const std::string &Plugin::getPluginName() const
{
  return itsModuleName;
}

// ----------------------------------------------------------------------
/*!
 * \brief Return the required version
 */
// ----------------------------------------------------------------------

int Plugin::getRequiredAPIVersion() const
{
  return SMARTMET_API_VERSION;
}

// ----------------------------------------------------------------------
/*!
 * \brief Performance query implementation.
 */
// ----------------------------------------------------------------------

bool Plugin::queryIsFast(const Spine::HTTP::Request & /* theRequest */) const
{
  return false;
}

}  // namespace Download
}  // namespace Plugin
}  // namespace SmartMet

/*
 * Server knows us through the 'SmartMetPlugin' virtual interface, which
 * the 'Plugin' class implements.
 */

extern "C" SmartMetPlugin *create(SmartMet::Spine::Reactor *them, const char *config)
{
  return new SmartMet::Plugin::Download::Plugin(them, config);
}

extern "C" void destroy(SmartMetPlugin *us)
{
  // This will call 'Plugin::~Plugin()' since the destructor is virtual
  delete us;
}

// ======================================================================