//==================================================================================================
/*!
  @file

  @copyright 2016 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#ifndef BOOST_SIMD_FUNCTION_IS_NLTZ_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_IS_NLTZ_HPP_INCLUDED

#if defined(DOXYGEN_ONLY)
namespace boost { namespace simd
{

 /*!

    @ingroup group-predicates
    Function object implementing is_nltz capabilities

    Returns @ref True if x is not less than @ref Zero else returns @ref False.

    @par Semantic:

    @code
    auto r = is_nltz(x);
    @endcode

    is similar to:

    @code
    auto r = !(x < 0);
    @endcode

    @par Note:

    Due to existence of nan, this is not equivalent to is_gez(x)
    for floating types

  **/
  as_logical_t<Value> is_nltz(Value const& x);
} }
#endif

#include <boost/simd/function/scalar/is_nltz.hpp>
#include <boost/simd/function/simd/is_nltz.hpp>

#endif


#include <set>
#include <list>

#include <util/timer.h>
#include <mve/image_tools.h>
#include <Eigen/SparseCore>
#include <Eigen/SparseLU>

#include "texturing.h"
#include "rect.h"

TEX_NAMESPACE_BEGIN

/**
 * 候选纹理块, 最终的纹理块由多个候选纹理块构成
 */
struct TexturePatchCandidate {
    Rect<int> bounding_box;
    TexturePatch::Ptr texture_patch;
};

/**
 * @param label: 候选纹理块的标签
 * @param texture_view: 使用的视角
 * @param subgraph: 使用了label标签的连通的面片的向量
 * @param mesh: 网格
 */
TexturePatchCandidate generate_candidate(int label, TextureView const & texture_view,
    std::vector<std::size_t> const & subgraph, mve::TriangleMesh::ConstPtr mesh,
    Settings const & settings){
    mve::ByteImage::Ptr view_image = texture_view.get_image();
    int min_x = view_image->width(), min_y = view_image->height();
    int max_x = 0, max_y = 0;

    mve::TriangleMesh::FaceList const & mesh_faces = mesh->get_faces();
    mve::TriangleMesh::VertexList const & vertices = mesh->get_vertices();

    std::vector<math::Vec2f> texcoords;  // 所有面片的三个顶点投影到视角的二维图片上的二维坐标
    for (std::size_t i = 0; i < subgraph.size(); ++i){  // 遍历用了相同标签的连通的面片
        for (std::size_t j = 0; j < 3; ++j){
            math::Vec3f vertex = vertices[mesh_faces[subgraph[i] * 3 + j]];
            math::Vec2f pixel = texture_view.get_pixel_coords(vertex);

            texcoords.push_back(pixel);  // 面片的顶点投影到视角的二维图片上的二维坐标

            min_x = std::min(static_cast<int>(std::floor(pixel[0])), min_x);
            min_y = std::min(static_cast<int>(std::floor(pixel[1])), min_y);
            max_x = std::max(static_cast<int>(std::ceil(pixel[0])), max_x);
            max_y = std::max(static_cast<int>(std::ceil(pixel[1])), max_y);
        }
    }

    // 检查是否超过视角的成像图片的宽高
    assert(min_x >= 0);
    assert(min_y >= 0);
    assert(max_x < view_image->width());
    assert(max_y < view_image->height());

    //
    int width  = max_x - min_x + 1;  width += 2 * texture_patch_border;
    int height = max_y - min_y + 1; height += 2 * texture_patch_border;
    min_x -= texture_patch_border;
    min_y -= texture_patch_border;

    // 将所有顶点 在视角的图片的位置 转为 在aabb中的相对位置, aabb被视角的图片所包含
    math::Vec2f min(min_x, min_y);
    for (std::size_t i = 0; i < texcoords.size(); ++i) {
        texcoords[i] = texcoords[i] - min;
    }

    mve::ByteImage::Ptr byte_image;
    byte_image = mve::image::crop(view_image, width, height, min_x, min_y, *math::Vec3uc(255, 0, 255));  // 裁剪图片, Region may exceed the input image dimensions, new pixel values are initialized with the given color(255,0,255).
    mve::FloatImage::Ptr image = mve::image::byte_to_float_image(byte_image);  // scaling from [0, 255] to [0, 1]

    // gamma矫正
    if (settings.tone_mapping == TONE_MAPPING_GAMMA) {
        mve::image::gamma_correct(image, 2.2f);
    }

    TexturePatchCandidate texture_patch_candidate = {
        Rect<int>(min_x, min_y, max_x, max_y), TexturePatch::create(label, subgraph, texcoords, image)
    };

    return texture_patch_candidate;
}

/**
 * @brief merge用了相同纹理块的顶点的面片信息, 顶点的投影信息不需要合并
 */
void merge_vertex_projection_infos(std::vector<std::vector<VertexProjectionInfo> > * vertex_projection_infos) {
    #pragma omp parallel for
    for (std::size_t i = 0; i < vertex_projection_infos->size(); ++i) {  // 遍历每个有投影信息的顶点
        std::vector<VertexProjectionInfo> & infos = vertex_projection_infos->at(i);

        std::map<std::size_t, VertexProjectionInfo> info_map;  // 纹理块的id:面片的信息
        std::map<std::size_t, VertexProjectionInfo>::iterator it;

        for (VertexProjectionInfo const & info : infos) {  // 遍历一个顶点的所有投影信息
            std::size_t texture_patch_id = info.texture_patch_id;
            if((it = info_map.find(texture_patch_id)) == info_map.end()) {
                info_map[texture_patch_id] = info;
            }
            else{
                it->second.faces.insert(it->second.faces.end(), info.faces.begin(), info.faces.end());  // 合并顶点的面片信息
            }
        }

        infos.clear();
        infos.reserve(info_map.size());
        for(it=info_map.begin(); it!=info_map.end(); ++it){
            infos.push_back(it->second);
        }
    }
}

/**
 * @param texture_patches:
 */
void generate_texture_patches(UniGraph const & graph, mve::TriangleMesh::ConstPtr mesh,
    mve::MeshInfo const & mesh_info,
    std::vector<TextureView> * texture_views, Settings const & settings,
    std::vector<std::vector<VertexProjectionInfo> > * vertex_projection_infos,
    std::vector<TexturePatch::Ptr> * texture_patches) {

    mve::TriangleMesh::FaceList const & mesh_faces = mesh->get_faces();
    mve::TriangleMesh::VertexList const & vertices = mesh->get_vertices();
    vertex_projection_infos->resize(vertices.size());

    std::size_t num_patches = 0;

    std::cout << "\t执行中... " << std::flush;

    #pragma omp parallel for schedule(dynamic)
    for (std::size_t i = 0; i < texture_views->size(); ++i) {  // 遍历每一个视角
        std::vector<std::vector<std::size_t> > subgraphs;  // 保存有相同标签的面片, 每一片连通的面片一个集合

        int const label = i + 1;
        graph.get_subgraphs(label, &subgraphs);

        TextureView * texture_view = &texture_views->at(i);
        texture_view->load_image();
        std::list<TexturePatchCandidate> candidates;  // 每个subgraph为一个候选纹理块, 所有的subgraph构成最终的纹理块

        for (std::size_t j = 0; j < subgraphs.size(); ++j) {  // 遍历每个连通的subgraph
            candidates.push_back(generate_candidate(label, *texture_view, subgraphs[j], mesh, settings));
        }
        texture_view->release_image();

        // 合并包含相同图像的candidate, 也就是这个视角中被用于纹理映射的图片部分
        std::list<TexturePatchCandidate>::iterator it, sit;
        for (it = candidates.begin(); it != candidates.end(); ++it) {
            for (sit = candidates.begin(); sit != candidates.end();) {
                Rect<int> bounding_box = sit->bounding_box;
                if (it != sit && bounding_box.is_inside(&it->bounding_box)) {  // 如果一个candicate的aabb包含另一个的aabb(但是两个candicate肯定是不连通的), 合并
                    // 合并面片
                    TexturePatch::Faces & faces = it->texture_patch->get_faces();
                    TexturePatch::Faces & ofaces = sit->texture_patch->get_faces();
                    faces.insert(faces.end(), ofaces.begin(), ofaces.end());

                    // 合并顶点在二维图片上的相对坐标
                    TexturePatch::Texcoords & texcoords = it->texture_patch->get_texcoords();
                    TexturePatch::Texcoords & otexcoords = sit->texture_patch->get_texcoords();
                    math::Vec2f offset;
                    offset[0] = sit->bounding_box.min_x - it->bounding_box.min_x;
                    offset[1] = sit->bounding_box.min_y - it->bounding_box.min_y;
                    for (std::size_t i = 0; i < otexcoords.size(); ++i) {
                        texcoords.push_back(otexcoords[i] + offset);
                    }

                    sit = candidates.erase(sit);
                }
                else{
                    ++sit;
                }
            }
        }

        for (it = candidates.begin(); it != candidates.end(); ++it) {
            std::size_t texture_patch_id;

            #pragma omp critical
            {
                texture_patches->push_back(it->texture_patch);
                texture_patch_id = num_patches++;
            }

            std::vector<std::size_t> const & faces = it->texture_patch->get_faces();
            std::vector<math::Vec2f> const & texcoords = it->texture_patch->get_texcoords();
            for (std::size_t i = 0; i < faces.size(); ++i) {  // 遍历patch里的每个面
                std::size_t const face_id = faces[i];
                std::size_t const face_pos = face_id * 3;
                for (std::size_t j = 0; j < 3; ++j) {  // 遍历每个顶点
                    std::size_t const vertex_id = mesh_faces[face_pos  + j];
                    math::Vec2f const projection = texcoords[i * 3 + j];

                    VertexProjectionInfo info = {texture_patch_id, projection, {face_id}};

                    #pragma omp critical
                    vertex_projection_infos->at(vertex_id).push_back(info);  // 一个顶点会被多个面用到
                }
            }
        }
    }

    merge_vertex_projection_infos(vertex_projection_infos);

    // hole_filling

    std::cout<<" 生成"<<num_patches<<"块纹理块."<<std::endl;
}

TEX_NAMESPACE_END


// Software License for MTL
//
// Copyright (c) 2007 The Trustees of Indiana University.
//               2008 Dresden University of Technology and the Trustees of Indiana University.
//               2010 SimuNova UG (haftungsbeschränkt), www.simunova.com.
// All rights reserved.
// Authors: Peter Gottschling and Andrew Lumsdaine
//
// This file is part of the Matrix Template Library
//
// See also license.mtl.txt in the distribution.

#include <iostream>
#include <complex>
#include <boost/numeric/mtl/mtl.hpp>

using namespace std;

template <typename Vector>
void test(Vector& v, const char* name)
{
    std::cout << name << "\n";

    using mtl::Collection;
    typedef typename Collection<Vector>::value_type   value_type;

    v= 7.;
    std::cout << "After v= 7; v == " << v << "\n";
    MTL_THROW_IF(v[2] != value_type(7.), mtl::runtime_error("Constant assignment wrong"));

    v= 8., 45u, -3;
    std::cout << "After v= 8., 45., -3.; v == " << v << "\n";
    MTL_THROW_IF(v[2] != value_type(-3), mtl::runtime_error("Comma assignment wrong"));

    v= 6.;
    std::cout << "After v= 6; v == " << v << "\n";
    MTL_THROW_IF(v[2] != value_type(6.), mtl::runtime_error("Constant reassignment wrong"));

    Vector w(3);
    v= w= 5.;
    std::cout << "After v= w= 5; v == " << v << ", w == " << w << "\n\n";
    MTL_THROW_IF(w[2] != value_type(5.), mtl::runtime_error("Constant assignment (of w) wrong"));
    MTL_THROW_IF(v[2] != value_type(5.), mtl::runtime_error("Constant reassignment wrong"));

#if 0
    v+= 8., 45u, -3;
    std::cout << "After v+= 8., 45., -3.; v == " << v << "\n";
    if (v[0] != value_type(13))
	throw "Comma assignment wrong";
    if (v[2] != value_type(2))
	throw "Comma assignment wrong";
#endif

}

int main(int, char**)
{
    mtl::dense_vector<float>                  v(3);
    mtl::dense_vector<std::complex<float> >   w(3);

    test(v, "dense_vector<float>");
    test(w, "dense_vector<std::complex<float> >");

    return 0;
}


//
// Copyright © 2017 Arm Ltd. All rights reserved.
// See LICENSE file in the project root for full license information.
//
#include <boost/test/unit_test.hpp>
#include "armnnCaffeParser/ICaffeParser.hpp"
#include "ParserPrototxtFixture.hpp"

BOOST_AUTO_TEST_SUITE(CaffeParser)

struct GlobalPoolingFixture : public armnnUtils::ParserPrototxtFixture<armnnCaffeParser::ICaffeParser>
{
    GlobalPoolingFixture()
    {
        m_Prototext = "name: \"GlobalPooling\"\n"
            "layer {\n"
            "  name: \"data\"\n"
            "  type: \"Input\"\n"
            "  top: \"data\"\n"
            "  input_param { shape: { dim: 1 dim: 3 dim: 2 dim: 2 } }\n"
            "}\n"
            "layer {\n"
            "    bottom: \"data\"\n"
            "    top: \"pool1\"\n"
            "    name: \"pool1\"\n"
            "    type: \"Pooling\"\n"
            "    pooling_param {\n"
            "        pool: AVE\n"
            "        global_pooling: true\n"
            "    }\n"
            "}\n";
        SetupSingleInputSingleOutput("data", "pool1");
    }
};

BOOST_FIXTURE_TEST_CASE(GlobalPooling, GlobalPoolingFixture)
{
    RunTest<4>(
        {
            1,3,
            5,7,

            2,2,
            2,2,

            4,4,
            6,6
        },
        {
            4, 2, 5
        });
}

BOOST_AUTO_TEST_SUITE_END()


#ifndef STAN_MATH_PRIM_PROB_LOGLOGISTIC_RNG_HPP
#define STAN_MATH_PRIM_PROB_LOGLOGISTIC_RNG_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/scalar_seq_view.hpp>
#include <stan/math/prim/fun/max_size.hpp>
#include <boost/random/uniform_01.hpp>
#include <boost/random/variate_generator.hpp>

namespace stan {
namespace math {

/** \ingroup prob_dists
 * Return a loglogistic random variate for the given scale and
 * shape parameters using the specified random number generator.
 *
 * alpha and beta can each be a scalar or a one-dimensional container. Any
 * non-scalar inputs must be the same size.
 *
 * @tparam T_scale type of scale parameter
 * @tparam T_shape type of shape parameter
 * @tparam RNG type of random number generator
 * @param alpha (Sequence of) positive scale parameter(s)
 * @param beta (Sequence of) positive shape parameter(s)
 * @param rng random number generator
 * @return (Sequence of) loglogistic random variate(s)
 * @throw std::domain_error if alpha or beta are nonpositive
 * @throw std::invalid_argument if non-scalar arguments are of different
 * sizes
 */
template <typename T_scale, typename T_shape, class RNG>
inline typename VectorBuilder<true, double, T_scale, T_shape>::type
loglogistic_rng(const T_scale& alpha, const T_shape& beta, RNG& rng) {
  using boost::uniform_01;
  using boost::variate_generator;
  using std::pow;
  using T_alpha_ref = ref_type_t<T_scale>;
  using T_beta_ref = ref_type_t<T_shape>;
  static const char* function = "loglogistic_rng";
  check_consistent_sizes(function, "Scale parameter", alpha, "Shape Parameter",
                         beta);
  T_alpha_ref alpha_ref = alpha;
  T_beta_ref beta_ref = beta;
  check_positive_finite(function, "Scale parameter", alpha_ref);
  check_positive_finite(function, "Shape parameter", beta_ref);

  scalar_seq_view<T_alpha_ref> alpha_vec(alpha_ref);
  scalar_seq_view<T_beta_ref> beta_vec(beta_ref);
  size_t N = max_size(alpha, beta);
  VectorBuilder<true, double, T_scale, T_shape> output(N);

  for (size_t n = 0; n < N; ++n) {
    variate_generator<RNG&, uniform_01<> > uniform01_rng(rng, uniform_01<>());
    const double tmp = uniform01_rng();
    output[n] = alpha_vec[n] * pow(tmp / (1 - tmp), 1 / beta_vec[n]);
  }
  return output.data();
}

}  // namespace math
}  // namespace stan
#endif


#include <pnp/learning_plan/exp/Exploit.h>

#include <boost/bind.hpp>
#include <iterator>

namespace learnpnp {

int Exploit::makeChoice(Learner *learner,const Marking &current, const std::vector<Marking> &states) {

    std::vector<double> values;
    std::transform(states.begin(),
                   states.end(),
                   std::back_inserter(values),
                   boost::bind(&Learner::valueOf,learner,_1));

    std::vector<double>::iterator elem = std::max_element(values.begin(), values.end());

    int c = std::count(values.begin(),values.end(),*elem);

    if (c > 1) {

        //choose randomly among the equal ones
        std::vector<int> maxElementsPos;

        for (int i=0, s = values.size(); i < s; ++i) {
            if (values[i] == *elem)
                maxElementsPos.push_back(i);
        }

        int chosen = ( rand() / ( RAND_MAX / maxElementsPos.size() ) );

        return maxElementsPos[chosen];

    }
    else
        return std::distance(values.begin(), elem);
}

}


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

// Copyright (c) 2010-2012 Barend Gehrels, Amsterdam, the Netherlands.

// 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_EXTENSIONS_ALGORITHMS_MARK_SPIKES_HPP
#define BOOST_GEOMETRY_EXTENSIONS_ALGORITHMS_MARK_SPIKES_HPP

#include <algorithm>

#include <boost/range.hpp>

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

#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/strategies/cartesian/distance_pythagoras.hpp>
#include <boost/geometry/strategies/cartesian/area_surveyor.hpp>
#include <boost/geometry/util/math.hpp>

#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>

#include <boost/geometry/algorithms/area.hpp>
#include <boost/geometry/algorithms/buffer.hpp>
#include <boost/geometry/algorithms/distance.hpp>
#include <boost/geometry/algorithms/perimeter.hpp>

#include <boost/geometry/geometries/box.hpp>

/*
Mark spikes in a ring/polygon.
Ring
+---------+
|         |
|         |
|   +=====  ^this "indentation" or "intrusion" or "spikey feature" is marked
|   ||    |
|   ||    |
|   ++    |
+---------+
(the actualy determination if it is marked is done by a policy)
(things are only marked, removal is done afterwards)

*/

namespace boost { namespace geometry
{

#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace mark_spikes
{

template <typename Range, typename Iterator>
inline Iterator circular_next(Range const& range, Iterator it)
{
    ++it;
    if (it == boost::end(range))
    {
        it = boost::begin(range);
    }
    return it;
}

inline std::size_t circular_next_i(std::size_t i, std::size_t const n)
{
    if (++i == n)
    {
        i = 0;
    }
    return i;
}

// Calculate the distance over the ring, in the range [it1 .. it2]
// if it1 < it2: walk from it1 .. it2
// if it1 > it2: walk from it1 .. end(ring) and from begin(ring) to it2
// Do NOT call this using begin(ring), end(ring) or 0.0 will be returned
template
<
    typename Range,
    typename Iterator,
    typename AreaStrategy,
    typename DistanceStrategy
>
inline void part_area_and_perimeter(Range const& range,
            Iterator it1, Iterator it2,
            AreaStrategy const& area_strategy,
            DistanceStrategy const& distance_strategy,
            double& area, double& perimeter, int& count)
{
    perimeter = 0;
    area = 0;
    count = 0;
    if (it1 == boost::end(range) || it2 == boost::end(range) || it1 == it2)
    {
        return;
    }

    typename AreaStrategy::state_type area_state;
    Iterator it = circular_next(range, it1), previous = it1;
    Iterator end = circular_next(range, it2);
    while (it != end)
    {
        area_strategy.apply(*previous, *it, area_state);
        perimeter += distance_strategy.apply(*previous, *it);
        previous = it;
        it = circular_next(range, it);
        count++;
    }

    // Close the ring, for area
    area_strategy.apply(*it2, *it1, area_state);
    // Do the same for distance to get correct ratio (though this might be discussed)
    perimeter += distance_strategy.apply(*it2, *it1);

    area = geometry::math::abs(area_strategy.result(area_state));
}

template <typename Iterator>
struct helper
{
    helper(int i1, int i2, Iterator t1, Iterator t2,
        double g, double a, double p, int c)
        : index1(i1)
        , index2(i2)
        , it1(t1)
        , it2(t2)
        , gap_distance(g)
        , area(a)
        , perimeter(p)
        , count(c)
    {
    }

    int index1, index2;
    Iterator it1, it2;
    double area, perimeter, gap_distance;
    int count;

    inline bool operator<(helper<Iterator> const& other) const
    {
        return this->count > other.count;
    }
};

template <typename Range, typename MarkMap, typename Policy>
struct range_mark_spikes
{
    typedef typename point_type<Range>::type point_type;

    typedef typename strategy::side::services::default_strategy
    <
        typename cs_tag<Range>::type
    >::type side_strategy_type;

    typedef typename strategy::area::services::default_strategy
        <
            typename cs_tag<point_type>::type,
            point_type
        >::type area_strategy_type;

    typedef typename strategy::distance::services::default_strategy
        <
            point_tag,
            point_type,
            point_type
        >::type distance_strategy_type;

    static inline void apply(Range const& range, ring_identifier id,
                    MarkMap& mark_map, Policy const& policy)
    {
        std::size_t const n = boost::size(range);
        if (n < 5)
        {
            return;
        }

        typedef typename boost::range_iterator<Range const>::type iterator_type;

        // Divide polygon in monotonic sections (in two directions)
        typedef model::box<point_type> box_type;
        typedef geometry::sections<box_type, 2> sections_type;
        sections_type sections;
        geometry::sectionalize<false>(range, sections);

        for (typename boost::range_iterator<sections_type>::type it = boost::begin(sections);
            it != boost::end(sections);
            ++it)
        {
            // Enlarge each box with the wished max with of the gap to be sure that
            // when walking through sections all point-pairs are considered
            geometry::buffer(it->bounding_box, it->bounding_box, policy.gap_width() * 1.001);
        }

        double const whole_area = geometry::area(range);

        typedef typename boost::range_iterator<sections_type>::type section_iterator_type;

        // Find pair-of-points lying the most close to each other,
        // where:
        // - it is in another section
        // - the distance over the ring-part is larger than X
        // - the area of the polygon formed by that ring-part smaller than X

        typedef helper<iterator_type> helper_type;
        typedef std::vector<helper_type> helper_vector_type;
        helper_vector_type candidates;

        // Quadratic loop over all sections (note this normally does not result in a quadratic loop
        // over all points).
        for(section_iterator_type sit1 = boost::begin(sections); sit1 != boost::end(sections); ++sit1)
        {
            // Note, even though combination sit1/sit2 is handled, the combination sit2/sit1 travels
            // another part over the ring and should be handled as well
            for(section_iterator_type sit2 = boost::begin(sections); sit2 != boost::end(sections); ++sit2)
            {
                if (sit1->id != sit2->id
                    && ! geometry::disjoint(sit1->bounding_box, sit2->bounding_box))
                {
                    // Check all point combinations in these boxes
                    int index1 = sit1->begin_index;
                    iterator_type it1 = boost::begin(range) + sit1->begin_index;
                    for (unsigned int i = 0; i < sit1->count; i++, ++it1, ++index1)
                    {
                        iterator_type it2 = boost::begin(range) + sit2->begin_index;
                        int index2 = sit2->begin_index;
                        for (unsigned int j = 0; j < sit2->count; j++, ++it2, ++index2)
                        {
                            double dg = geometry::distance(*it1, *it2);
                            if (dg < policy.gap_width())
                            {
                                double area, perimeter;
                                int count;
                                part_area_and_perimeter(range, it1, it2,
                                    area_strategy_type(), distance_strategy_type(),
                                    area, perimeter, count);

                                if (count >= 2
                                    && policy.apply(dg, whole_area, count, area, perimeter))
                                {
                                    candidates.push_back(
                                        helper_type(index1, index2, it1, it2, dg, area, perimeter, count));
                                }
                            }
                        }
                    }
                }
            }
        }

        if (boost::size(candidates) == 0)
        {
            return;
        }

        std::sort(candidates.begin(), candidates.end());

        /***
        if (boost::size(candidates) > 1)
        {

            // Remove overlaps
            bool first = true;
            typename boost::range_iterator<helper_vector_type>::type it = boost::begin(candidates);
            typename boost::range_iterator<helper_vector_type>::type prev = it;
            ++it;
            while (it != boost::end(candidates))
            {

                if ((it->index1 >= prev->index1 && it->index2 <= prev->index2)

                    )
                {
                    candidates.erase(it);
                    it = prev + 1;
                }
                else
                {
                    prev = it;
                }
            }
        }
        ***/

        // Check if some index combinations refer to larger combinations
#if defined(BOOST_GEOMETRY_DEBUG_MARK_SPIKES)
        for(typename boost::range_iterator<helper_vector_type>::type it
            = boost::begin(candidates); it != boost::end(candidates); ++it)
        {
            std::cout << it->count << " " << it->index1 << " " << it->index2
                << " gd=" << it->gap_distance
                << " a=" << it->area << " p=" << it->perimeter
                << " r=" << (it->perimeter > 0 ? it->area / it->perimeter : 0)
                // << " p1=" << geometry::wkt(*it->it1) << " p2=" << geometry::wkt(*it->it2)
                << std::endl;
        }
#endif

        typedef typename MarkMap::mapped_type bit_vector_type;

        // Add new vector to map if necessary
        if (mark_map.find(id) == mark_map.end())
        {
            // Add one to vector
            mark_map[id] = bit_vector_type();

            // Initialize it
            bit_vector_type& bits = mark_map[id];
            for (std::size_t i = 0; i < n; i++)
            {
                bits.push_back(false);
            }
        }

        bit_vector_type& bits = mark_map[id];

        // Mark this range or these ranges
        // TODO: we might use the fact that it is sorted and that ranges are inside others,
        // so skip those...
        for(typename boost::range_iterator<helper_vector_type const>::type it
            = boost::begin(candidates); it != boost::end(candidates); ++it)
        {
            iterator_type pit = boost::begin(range) + it->index1;
            iterator_type end = boost::begin(range) + it->index2;
            int i = it->index1;
            while (pit != end)
            {
                if (i != it->index1 && i != it->index2)
                {
                    bits[i] = true;
                }
                pit = circular_next(range, pit);
                i = circular_next_i(i, n);
            }
        }
    }
};

template <typename Polygon, typename MarkMap, typename Policy>
struct polygon_mark_spikes
{
    static inline void apply(Polygon const& polygon, ring_identifier id,
                    MarkMap& mark_map, Policy const& policy)
    {
        typedef typename geometry::ring_type<Polygon>::type ring_type;

        typedef range_mark_spikes<ring_type, MarkMap, Policy> per_range;

        // Exterior ring (-1)
        id.ring_index = -1;
        per_range::apply(exterior_ring(polygon), id, mark_map, policy);

        typename interior_return_type<Polygon const>::type rings
                    = interior_rings(polygon);
        for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
        {
            // Interior ring (zero based)
            id.ring_index++;
            per_range::apply(*it, id, mark_map, policy);
        }
    }
};

template <typename MultiGeometry, typename MarkMap, typename Policy, typename SinglePolicy>
struct multi_mark_spikes
{
    static inline void apply(MultiGeometry const& multi, ring_identifier id,
                    MarkMap& mark_map, Policy const& policy)
    {
        id.multi_index = 0;
        for (typename boost::range_iterator<MultiGeometry const>::type
                it = boost::begin(multi);
            it != boost::end(multi);
            ++it)
        {
            SinglePolicy::apply(*it, id, mark_map, policy);
            id.multi_index++;
        }
    }
};

}} // namespace detail::mark_spikes
#endif // DOXYGEN_NO_DETAIL

#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{

template
<
    typename Tag,
    typename Geometry,
    typename MarkMap,
    typename Policy
>
struct mark_spikes
{
    static inline void apply(Geometry&, Policy const&)
    {}
};

template <typename Ring, typename MarkMap, typename Policy>
struct mark_spikes<ring_tag, Ring, MarkMap, Policy>
    : detail::mark_spikes::range_mark_spikes<Ring, MarkMap, Policy>
{};

template <typename Polygon, typename MarkMap, typename Policy>
struct mark_spikes<polygon_tag, Polygon, MarkMap, Policy>
    : detail::mark_spikes::polygon_mark_spikes<Polygon, MarkMap, Policy>
{};

template <typename MultiPolygon, typename MarkMap, typename Policy>
struct mark_spikes<multi_polygon_tag, MultiPolygon, MarkMap, Policy>
    : detail::mark_spikes::multi_mark_spikes
        <
            MultiPolygon,
            MarkMap,
            Policy,
            detail::mark_spikes::polygon_mark_spikes
            <
                typename boost::range_value<MultiPolygon>::type,
                MarkMap,
                Policy
            >
        >
{};

} // namespace dispatch
#endif

/*!
    \ingroup mark_spikes
    \tparam Geometry geometry type
    \param geometry the geometry to make mark_spikes
*/
template <typename Geometry, typename MarkMap, typename Policy>
inline bool mark_spikes(Geometry const& geometry,
        MarkMap& mark_map,
        Policy const& policy)
{
    concept::check<Geometry const>();

    ring_identifier id;

    dispatch::mark_spikes
        <
            typename tag<Geometry>::type,
            Geometry,
            MarkMap,
            Policy
        >::apply(geometry, id, mark_map, policy);
    return mark_map.size() > 0;
}

template <typename T = double>
class select_gapped_spike
{
public :
    inline select_gapped_spike(T const gap_width, T const ratio = 0.1)
        : m_gap_width(gap_width)
        , m_ratio(ratio)
    {}

    inline T gap_width() const
    {
        return m_gap_width;
    }

    inline bool apply(T const gap_distance, T const whole_area,
                int count, T const area, T const perimeter) const
    {
        T const ratio = perimeter == 0 ? 0 : area / perimeter;
        return
            perimeter > gap_distance
            && area < whole_area / 10.0
            && ratio < m_ratio;
    }

private :
    T m_gap_width;
    T m_ratio;
};

}} // namespace boost::geometry

#endif // BOOST_GEOMETRY_EXTENSIONS_ALGORITHMS_MARK_SPIKES_HPP


#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>
#include <string>
#include <numeric>
#include <fstream>
#include <sstream>
#include <boost/algorithm/string.hpp>
#include <ctime>

#include "../../libs/main_path_analysis/src/mainPathAnalysis/checkGraphProperties.hpp"
#include "../../libs/main_path_analysis/src/mainPathAnalysis/edgeWeightGeneration.hpp"
#include "../../libs/main_path_analysis/src/mainPathAnalysis/mpaAlgorithms.hpp"
#include "../../libs/main_path_analysis/src/mainPathAnalysis/preAndPostProcessing.hpp"
#include "../../libs/main_path_analysis/src/mainPathAnalysis/propertyMaps.hpp"

using VertexProperties = boost::property<boost::vertex_name_t, std::string, boost::property<boost::vertex_finish_time_t, std::tm>>;
using Graph = boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS, VertexProperties, boost::property<boost::edge_index_t,std::size_t>, boost::vecS>;

Graph read_graph_from_file(std::istream& input, std::set<std::size_t> forbidden_vertices)
{
	std::size_t n_vertices, n_edges;

	std::string l;
	std::getline(input, l);
	n_vertices = std::stoul(l);
	std::getline(input, l);
	n_edges = std::stoul(l);

	Graph g;

	std::map<std::size_t, Graph::vertex_descriptor> v_map;

	for(std::size_t i = 0; i < n_vertices; i++)
	{
		std::string line;
		std::getline(input, line);
		boost::trim(line);

		if(!line.empty() && forbidden_vertices.find(i) == forbidden_vertices.end())
		{
			auto v = boost::add_vertex(g);
			v_map.insert({ i, v });
			std::vector<std::string> tmp;
			boost::split(tmp, line, boost::is_any_of("\t"));
			boost::trim(tmp[0]);

			boost::put(boost::vertex_name, g, v, tmp[0]);

			std::vector<std::string> date_strs;
			boost::split(date_strs, tmp[1], boost::is_any_of("_"));
			int year = std::stoul(date_strs[0]), month = std::stoul(date_strs[1]), day = std::stoul(date_strs[2]);
			std::tm date{};
			date.tm_year = year-1900;
			date.tm_mon = month-1;
			date.tm_mday = day;

			boost::put(boost::vertex_finish_time, g, v, date);
		}
	}

	for(std::size_t i = 0; i < n_edges; i++)
	{
		std::string line;
		std::getline(input, line);
		boost::trim(line);

		if(!line.empty())
		{
			std::stringstream ss(line);
			std::size_t from, to;
			ss >> from >> to;

			if(forbidden_vertices.find(from) == forbidden_vertices.end() && forbidden_vertices.find(to) == forbidden_vertices.end())
				boost::add_edge(v_map.at(from), v_map.at(to), g);
		}
	}

	return g;
}

class VertexLabelWriter {
	public:
		VertexLabelWriter(Graph& g, std::vector<std::vector<Graph::edge_descriptor>> main_paths = std::vector<std::vector<Graph::edge_descriptor>>())
			:_g(g),
			main_path_colors({ "blue", "green", "red" })
		{
			for (auto main_path : main_paths) {
				std::set<Graph::vertex_descriptor> vertices_in_path;
				for (auto e : main_path) {
					vertices_in_path.insert(boost::source(e,g));
					vertices_in_path.insert(boost::target(e,g));
				}
				_main_path_vertex_sets.push_back(vertices_in_path);
			}
		}

		template <class VertexOrEdge>
			void operator()(std::ostream& out, const VertexOrEdge& v) const {
				const std::size_t MAX_LENGTH = 50;
				std::string lab = boost::get(boost::vertex_name, _g, v);
				if(lab.length() > MAX_LENGTH+5)
					lab = lab.substr(0, MAX_LENGTH) + "[...]";
				out << "[";
				out << "label=\"" << lab << "\" ";

				std::size_t i = 0;
				for (auto mp : _main_path_vertex_sets)
				{
					if(mp.find(v) != mp.end())
					{
						out << "color=\"" << main_path_colors[i] << "\" ";
					}
					i++;
				}
				// out << "shape=point ";

				out << "fontsize=70 ";
				out << "]";
			}

	private:
		Graph& _g;

		std::vector<std::set<Graph::vertex_descriptor>> _main_path_vertex_sets;
		const std::vector<std::string> main_path_colors;
};

class EdgeLabelWriter {
	public:
		EdgeLabelWriter(Graph& g, std::vector<std::vector<Graph::edge_descriptor>> main_paths)
			:_g(g),
			main_path_colors({ "blue", "green", "red" })
		{
			for (auto mp : main_paths) {
				_main_path_sets.push_back(std::set<Graph::edge_descriptor>(mp.begin(), mp.end()));
			}
		}

		template <class VertexOrEdge>
			void operator()(std::ostream& out, const VertexOrEdge& e) const {
				out << "[";
				out << "fontsize=40 ";

				std::size_t i = 0;
				bool found = false;
				for (auto mp : _main_path_sets)
				{
					if(mp.find(e) != mp.end())
					{
						out << "color=\"" << main_path_colors[i] << "\" ";
						found = true;
					}
					i++;
				}

				if(found)
					out << "penwidth=\"20\" ";
				else
					out << "penwidth=\"15\" ";
				out << "]";
			}

	private:
		Graph& _g;
		std::vector<std::set<Graph::edge_descriptor>> _main_path_sets;
		const std::vector<std::string> main_path_colors;
};

int main(int argc, char *argv[])
{
	std::ifstream input_file(argv[1]);

	std::set<std::size_t> forbidden_vertices;
	if(argc > 2)
	{
		std::ifstream forbidden_file(argv[2]);
		std::size_t i_forbidden;
		while(!forbidden_file.eof())
		{
			forbidden_file >> i_forbidden;
			forbidden_vertices.insert(i_forbidden);
		}
	}

	auto g = read_graph_from_file(input_file, forbidden_vertices);

	std::vector<Graph::vertex_descriptor> ordered_vertices(boost::num_vertices(g));
	std::iota(ordered_vertices.begin(), ordered_vertices.end(), 0);
	std::sort(ordered_vertices.begin(), ordered_vertices.end(), [&g](const Graph::vertex_descriptor& v1, const Graph::vertex_descriptor& v2)
	{
		return boost::in_degree(v1,g) + boost::out_degree(v1,g) < boost::in_degree(v2,g) + boost::out_degree(v2,g);
	});

	for (auto v : ordered_vertices) {
		std::cout << boost::get(boost::vertex_name, g, v) << std::endl;
	}

	std::cout << boost::num_vertices(g) << " " << boost::num_edges(g) << std::endl;

	MainPathAnalysis::set_increasing_edge_index(g);

	// add s and t vertex
	Graph::vertex_descriptor s, t;
	MainPathAnalysis::add_source_and_sink_vertex<Graph>(g, s, t);

	// compute spc weights
	// auto weights = MainPathAnalysis::generate_spc_weights(g, s, t);
	auto weights = MainPathAnalysis::generate_spc_weights_big_int(g, s, t);

	// compute global main path
	// double alpha = 1;
	// do {
		// main_path.clear();
		// // MainPathAnalysis::localForward(std::back_inserter(main_path), g, weights, s, t);
		// // MainPathAnalysis::localForward(std::back_inserter(main_path), g, weights, s, t);
		// MainPathAnalysis::globalAlpha(std::back_inserter(main_path), g, weights, s, t, alpha);
		// alpha += 1;
		// std::cout << main_path.size() << " " << alpha << std::endl;
	// }
	// while(main_path.size() > 50);

	std::vector<Graph::edge_descriptor> main_path_local, main_path_global, main_path_alpha;
	MainPathAnalysis::localForward<Graph, MainPathAnalysis::BigInt, std::back_insert_iterator<std::vector<Graph::edge_descriptor>>>(std::back_inserter(main_path_local), g, weights, s, t);
	// MainPathAnalysis::global(std::back_inserter(main_path_global), g, weights, s, t);

	if(argc > 5)
	{
		main_path_local.clear();

		std::cout << "Alpha Main Path" << std::endl;
		std::size_t max_length = std::stoul(argv[5]);

		MainPathAnalysis::BigInt upper_alpha = 1;
		MainPathAnalysis::BigInt lower_alpha = 0;

		MainPathAnalysis::globalAlpha(std::back_inserter(main_path_local), g, weights, s, t, lower_alpha);

		// multiply by 2 until bigger
		while(main_path_local.size() > max_length)
		{
			main_path_local.clear();
			MainPathAnalysis::globalAlpha(std::back_inserter(main_path_local), g, weights, s, t, upper_alpha);
			upper_alpha *= 2;
		}

		std::cout << "UPPER ALPHA " << upper_alpha << std::endl;

		// binary search
		bool found = false;
		while(!found)
		{
			std::cout << "loop" << std::endl;
			MainPathAnalysis::BigInt middle_alpha = (upper_alpha + lower_alpha) / 2;

			std::cout <<  lower_alpha << std::endl;
			std::cout <<  middle_alpha << std::endl;
			std::cout <<  upper_alpha << std::endl;

			main_path_local.clear();
			MainPathAnalysis::globalAlpha(std::back_inserter(main_path_local), g, weights, s, t, middle_alpha);

			std::cout << "SIZE: " << main_path_local.size() << std::endl;

			if(middle_alpha == upper_alpha || middle_alpha == lower_alpha)
				break;

			if(main_path_local.size() > max_length)
				lower_alpha = middle_alpha;
			else
				upper_alpha = middle_alpha;

			if(main_path_local.size() == max_length)
				found = true;

			std::cout << std::endl;

		}

	}

	// remove s and t from main path and from copy of graph
	// MainPathAnalysis::remove_edges_containing_source_or_sink(g, s, t, main_path_global);
	MainPathAnalysis::remove_edges_containing_source_or_sink(g, s, t, main_path_local);
	// MainPathAnalysis::remove_edges_containing_source_or_sink(g, s, t, main_path_alpha);
	MainPathAnalysis::remove_source_and_sink_vertex(g, s, t);

	// build json object of main path
	// EdgeList main_path_edges;
	// for (auto e : main_path)
		// main_path_edges.push_back({ boost::source(e,g), boost::target(e,g) });

	// _global_main_path_cache.insert({ category_id, std::move(main_path_edges) });

	std::cout << "main_path_local: " << main_path_local.size() << std::endl;
	std::cout << "main_path_global: " << main_path_global.size() << std::endl;
	std::cout << "main_path_alpha: " << main_path_alpha.size() << std::endl;

	if(argc > 3)
	{
		std::ofstream output_file(argv[3]);
		VertexLabelWriter vertex_label_writer(g, { main_path_local });
		EdgeLabelWriter edge_label_writer(g, { main_path_local });
		boost::write_graphviz(output_file, g, vertex_label_writer, edge_label_writer);
	}

	if(argc > 4)
	{
		std::ofstream output_file(argv[4]);

		const auto& mp = main_path_local;
		Graph mp_graph(mp.size() + 1);
		std::size_t i_vertex = 0;
		for (const auto& e : mp) {
			boost::add_edge(i_vertex, i_vertex+1, mp_graph);
			boost::put(boost::vertex_name, mp_graph, i_vertex, boost::get(boost::vertex_name, g, boost::source(e,g)));
			boost::put(boost::vertex_finish_time, mp_graph, i_vertex, boost::get(boost::vertex_finish_time, g, boost::source(e,g)));
			i_vertex++;
		}
		boost::put(boost::vertex_name, mp_graph, i_vertex, boost::get(boost::vertex_name, g, boost::target(mp.back(),g)));
		boost::put(boost::vertex_finish_time, mp_graph, i_vertex, boost::get(boost::vertex_finish_time, g, boost::target(mp.back(),g)));

		VertexLabelWriter vertex_label_writer(mp_graph);
		boost::write_graphviz(output_file, mp_graph, vertex_label_writer);
	}

	return 0;
}


//////////////////////////////////////////////////////////////////////////////
// Copyright 2002-2006 Andreas Huber Doenni
// Distributed under the Boost Software License, Version 1.0. (See accompany-
// ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
#define NO_OF_BITS 3
//////////////////////////////////////////////////////////////////////////////
// This program demonstrates the fact that measures must be taken to hide some
// of the complexity (e.g. in separate .cpp file) of a Boost.Statechart state
// machine once a certain size is reached.
// For this purpose, a state machine with exactly 2^NO_OF_BITS states (i.e.
// BitState< 0 > .. BitState< 2^NO_OF_BITS - 1 >) is generated. For the events
// EvFlipBit< 0 > .. EvFlipBit< NO_OF_BITS - 1 > there is a transition from
// each state to the state with the corresponding bit toggled. That is, there
// is a total of 2^NO_OF_BITS * NO_OF_BITS transitions.
// E.g. if the state machine is currently in state BitState< 5 > and receives
// EvFlipBit< 2 >, it transitions to state BitState< 1 >. If it is in
// BitState< 15 > and receives EvFlipBit< 4 > it transitions to BitState< 31 >
// etc.
// The maximum size of such a state machine depends on your compiler. The
// following table gives upper limits for NO_OF_BITS. From this, rough
// estimates for the maximum size of any "naively" implemented Boost.Statechart
// machine (i.e. no attempt is made to hide inner state implementation in a
// .cpp file) can be deduced.
//
// NOTE: Due to the fact that the amount of generated code more than
// *doubles* each time NO_OF_BITS is *incremented*, build times on most
// compilers soar when NO_OF_BITS > 6.
//
// Compiler      | max. NO_OF_BITS b | max. states s  |
// --------------|-------------------|----------------|
// MSVC 7.1      |      b < 6        |  32 < s <  64  |
// GCC 3.4.2 (1) |      b < 8        | 128 < s < 256  |
//
// (1) This is a practical rather than a hard limit, caused by a compiler
//     memory footprint that was significantly larger than the 1GB physical
//     memory installed in the test machine. The resulting frequent swapping
//     led to compilation times of hours rather than minutes.
//////////////////////////////////////////////////////////////////////////////

#include "UniqueObject.hpp"

#include <boost/statechart/event.hpp>
#include <boost/statechart/simple_state.hpp>
#include <boost/statechart/state_machine.hpp>
#include <boost/statechart/transition.hpp>

#include <boost/mpl/list.hpp>
#include <boost/mpl/front_inserter.hpp>
#include <boost/mpl/transform_view.hpp>
#include <boost/mpl/copy.hpp>
#include <boost/mpl/range_c.hpp>
#include <boost/mpl/integral_c.hpp>
#include <boost/mpl/shift_left.hpp>
#include <boost/mpl/bitxor.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/placeholders.hpp>
#include <boost/mpl/aux_/lambda_support.hpp>

#include <boost/config.hpp>
#include <boost/intrusive_ptr.hpp>

#include <iostream>
#include <iomanip>
#include <cstddef> // size_t

#ifdef BOOST_INTEL
#  pragma warning( disable: 304 ) // access control not specified
#  pragma warning( disable: 444 ) // destructor for base is not virtual
#  pragma warning( disable: 981 ) // operands are evaluated in unspecified order
#endif

namespace sc = boost::statechart;
namespace mpl = boost::mpl;

//////////////////////////////////////////////////////////////////////////////
struct IDisplay
{
  virtual void Display() const = 0;
};

//////////////////////////////////////////////////////////////////////////////
template< class BitNo >
struct EvFlipBit : sc::event< EvFlipBit< BitNo > > {};

template< class StateNo >
struct BitState;

struct BitMachine : sc::state_machine<
  BitMachine, BitState< mpl::integral_c< unsigned int, 0 > > > {};

template< class BitNo, class StateNo >
struct FlipTransition
{
  private:
    typedef typename mpl::bitxor_<
      StateNo,
      mpl::shift_left< mpl::integral_c< unsigned int, 1 >, BitNo >
    >::type NextStateNo;

  public:
    typedef typename sc::transition<
      EvFlipBit< BitNo >, BitState< NextStateNo > > type;

    BOOST_MPL_AUX_LAMBDA_SUPPORT( 2, FlipTransition, (BitNo, StateNo) );
};

//////////////////////////////////////////////////////////////////////////////
void DisplayBits( unsigned int number )
{
  char buffer[ NO_OF_BITS + 1 ];
  buffer[ NO_OF_BITS ] = 0;

  for ( unsigned int bit = 0; bit < NO_OF_BITS; ++bit )
  {
    buffer[ bit ] = number & ( 1 << ( NO_OF_BITS - bit - 1 ) ) ? '1' : '0';
  }

  std::cout << "Current state: " << std::setw( 4 ) <<
    number << " (" << buffer << ")" << std::endl;
}

template< class StateNo >
struct BitState : sc::simple_state< BitState< StateNo >, BitMachine >,
  UniqueObject< BitState< StateNo > >, IDisplay
{
  void * operator new( std::size_t size )
  {
    return UniqueObject< BitState< StateNo > >::operator new( size );
  }

  void operator delete( void * p, std::size_t size )
  {
    UniqueObject< BitState< StateNo > >::operator delete( p, size );
  }

  typedef typename mpl::copy<
    typename mpl::transform_view<
      mpl::range_c< unsigned int, 0, NO_OF_BITS >,
      FlipTransition< mpl::placeholders::_, StateNo > >::type,
    mpl::front_inserter< mpl::list<> >
  >::type reactions;

  virtual void Display() const
  {
    DisplayBits( StateNo::value );
  }
};

void DisplayMachineState( const BitMachine & bitMachine )
{
  bitMachine.state_cast< const IDisplay & >().Display();
}

//////////////////////////////////////////////////////////////////////////////
boost::intrusive_ptr< const sc::event_base > pFlipBitEvents[ NO_OF_BITS ];

struct EventInserter
{
  template< class BitNo >
  void operator()( const BitNo & )
  {
    pFlipBitEvents[ BitNo::value ] = new EvFlipBit< BitNo >();
  }
};

void FillEventArray()
{
  mpl::for_each< mpl::range_c< unsigned int, 0, NO_OF_BITS > >(
    EventInserter() );
}

//////////////////////////////////////////////////////////////////////////////
void VisitAllStates( BitMachine & bitMachine, unsigned int msb )
{
  if ( msb > 0 )
  {
    VisitAllStates( bitMachine, msb - 1 );
  }

  bitMachine.process_event( *pFlipBitEvents[ msb ] );
  DisplayMachineState( bitMachine );

  if ( msb > 0 )
  {
    VisitAllStates( bitMachine, msb - 1 );
  }
}

//////////////////////////////////////////////////////////////////////////////
char GetKey()
{
  char key;
  std::cin >> key;
  return key;
}

//////////////////////////////////////////////////////////////////////////////
int main()
{
  FillEventArray();

  const unsigned int noOfStates = 1 << NO_OF_BITS;
  std::cout << "Boost.Statechart BitMachine example\n";
  std::cout << "Machine configuration: " << noOfStates <<
    " states interconnected with " << noOfStates * NO_OF_BITS <<
    " transitions.\n\n";

  for ( unsigned int bit = 0; bit < NO_OF_BITS; ++bit )
  {
    std::cout << bit - 0 << "<CR>: Flips bit " << bit - 0 << "\n";
  }

  std::cout << "a<CR>: Goes through all states automatically\n";
  std::cout << "e<CR>: Exits the program\n\n";
  std::cout << "You may chain commands, e.g. 31<CR> flips bits 3 and 1\n\n";

  BitMachine bitMachine;
  bitMachine.initiate();

  char key = GetKey();

  while ( key != 'e' )
  {
    if ( ( key >= '0' ) && ( key < static_cast< char >( '0' + NO_OF_BITS ) ) )
    {
      bitMachine.process_event( *pFlipBitEvents[ key - '0' ] );
      DisplayMachineState( bitMachine );
    }
    else
    {
      switch( key )
      {
        case 'a':
        {
          VisitAllStates( bitMachine, NO_OF_BITS - 1 );
        }
        break;

        default:
        {
          std::cout << "Invalid key!\n";
        }
      }
    }

    key = GetKey();
  }

  return 0;
}


#ifndef CAMERA_HPP
#define CAMERA_HPP

#include <Eigen/Core>
#include <Eigen/Geometry>

#include "log.hpp"

class Camera {
  public:
    Camera(Eigen::Vector4d positionPoint, Eigen::Vector4d gazeDirection, Eigen::Vector4d viewUpDirection);
    void setTransformation(Eigen::Matrix4d transformation);
    Eigen::Matrix4d getTransformation();
    Eigen::Vector4d getUDirection();
    Eigen::Vector4d getVDirection();
    Eigen::Vector4d getWDirection();
    Eigen::Vector4d getPositionPoint();
    void setPositionPoint(Eigen::Vector4d positionPoint);
    Eigen::Vector4d getVelocityVector();
    void setVelocityVector(Eigen::Vector4d velocityVector);
    // Eigen::Vector4d getGazeDirection();
    // Eigen::Vector4d getViewUpDirection();

  private:
    void generateTransformation(Eigen::Vector4d positionPoint, Eigen::Vector4d gazeDirection, Eigen::Vector4d viewUpDirection);

    // Camera model
    Eigen::Matrix4d transformation;
    Eigen::Vector4d u;
    Eigen::Vector4d v;
    Eigen::Vector4d w;
    Eigen::Vector4d positionPoint;
    Eigen::Vector4d velocityVector;
    // Eigen::Vector4d gazeDirection;
    // Eigen::Vector4d viewUpDirection;
};

#endif // CAMERA_HPP