text:
#ifndef USE_CUDA

#include <engine/Vectormath.hpp>
#include <engine/Manifoldmath.hpp>
#include <utility/Constants.hpp>
#include <utility/Logging.hpp>
#include <utility/Exception.hpp>

#include <Eigen/Dense>

#include <array>
#include <algorithm>

using namespace Utility;
using Utility::Constants::Pi;

namespace Engine
{
    namespace Vectormath
    {

        void rotate(const Vector3 & v, const Vector3 & axis, const scalar & angle, Vector3 & v_out)
        {
            v_out = v * std::cos(angle) + axis.cross(v) * std::sin(angle) +
                    axis * axis.dot(v) * (1 - std::cos(angle));
        }

        // XXX: should we add test for that function since it's calling the already tested rotat()
        void rotate( const vectorfield & v, const vectorfield & axis, const scalarfield & angle,
                     vectorfield & v_out )
        {
            for( unsigned int i=0; i<v_out.size(); i++)
                rotate( v[i], axis[i], angle[i], v_out[i] );
        }

        Vector3 decompose(const Vector3 & v, const std::vector<Vector3> & basis)
        {
            Eigen::Ref<const Matrix3> A = Eigen::Map<const Matrix3>(basis[0].data());
            return A.colPivHouseholderQr().solve(v);
        }

        /////////////////////////////////////////////////////////////////

        void Build_Spins(vectorfield & positions, intfield & atom_types,
                         const std::vector<Vector3> & cell_atoms, const intfield & cell_atom_types,
                         const std::vector<Vector3> & translation_vectors, const intfield & n_cells)
        {
            // Check for erronous input placing two spins on the same location
            int max_a = std::min(10, n_cells[0]);
            int max_b = std::min(10, n_cells[1]);
            int max_c = std::min(10, n_cells[2]);
            Vector3 sp;
            for (unsigned int i = 0; i < cell_atoms.size(); ++i)
            {
                for (unsigned int j = 0; j < cell_atoms.size(); ++j)
                {
                    for (int ka = -max_a; ka <= max_a; ++ka)
                    {
                        for (int k2 = -max_b; k2 <= max_b; ++k2)
                        {
                            for (int k3 = -max_c; k3 <= max_c; ++k3)
                            {
                                // Norm is zero if translated basis atom is at position of another basis atom
                                sp = cell_atoms[i] - (cell_atoms[j]
                                    + ka * translation_vectors[0]
                                    + k2 * translation_vectors[1]
                                    + k3 * translation_vectors[2]);
                                if ( (i != j || ka != 0 || k2 != 0 || k3 != 0) &&
                                    std::abs(sp[0]) < 1e-9 && std::abs(sp[1]) < 1e-9 && std::abs(sp[2]) < 1e-9 )
                                {
                                    spirit_throw(Exception_Classifier::System_not_Initialized, Log_Level::Severe,
                                        "Unable to initialize Spin-System, since 2 spins occupy the same space.\nPlease check the config file!");
                                }
                            }
                        }
                    }
                }
            }

            // Build up the spins array
            int i, j, k, s, ispin;
            int nos_basic = cell_atoms.size();
            //int nos = nos_basic * n_cells[0] * n_cells[1] * n_cells[2];
            Vector3 build_array;
            for (k = 0; k < n_cells[2]; ++k) {
                for (j = 0; j < n_cells[1]; ++j) {
                    for (i = 0; i < n_cells[0]; ++i) {
                        for (s = 0; s < nos_basic; ++s) {
                            ispin = k * n_cells[1] * n_cells[0] * nos_basic +
                                    j * n_cells[0] * nos_basic + i * nos_basic + s;
                            build_array = i * translation_vectors[0] + j * translation_vectors[1] +
                                          k * translation_vectors[2];
                            // paste initial spin orientations across the lattice translations
                            //spins[dim*nos + ispin] = spins[dim*nos + s];
                            // calculate the spin positions
                            positions[ispin] = cell_atoms[s] + build_array;
                            atom_types[ispin] = cell_atom_types[s];
                        }// endfor s
                    }// endfor k
                }// endfor j
            }// endfor dim

        }// end Build_Spins

        std::array<scalar,3> Magnetization(const vectorfield & vf)
        {
            Vector3 vfmean = mean(vf);
            std::array<scalar, 3> M{vfmean[0], vfmean[1], vfmean[2]};
            return M;
        }

        scalar solid_angle_1(const Vector3 & v1, const Vector3 & v2, const Vector3 & v3)
        {
            // Get sign
            scalar pm = v1.dot(v2.cross(v3));
            if (pm != 0) pm /= std::abs(pm);

            // angle
            scalar solid_angle = ( 1 + v1.dot(v2) + v2.dot(v3) + v3.dot(v1) ) /
                                std::sqrt( 2 * (1+v1.dot(v2)) * (1+v2.dot(v3)) * (1+v3.dot(v1)) );
            if (solid_angle == 1)
                solid_angle = 0;
            else
                solid_angle = pm * 2 * std::acos(solid_angle);

            return solid_angle;
        }

        scalar solid_angle_2(const Vector3 & v1, const Vector3 & v2, const Vector3 & v3)
        {
            // Using the solid angle formula by Oosterom and Strackee (note we assume vectors to be normalized to 1)
            // https://en.wikipedia.org/wiki/Solid_angle#Tetrahedron

            scalar x = v1.dot(v2.cross(v3));
            scalar y = 1 + v1.dot(v2) + v1.dot(v3) + v2.dot(v3);
            scalar solid_angle = 2 * std::atan2( x , y );

            return solid_angle;
        }

        scalar TopologicalCharge(const vectorfield & vf, const vectorfield & vf_pos, const std::vector<std::array<int, 3>> & triangulation)
        {
            // TODO: this still ignores periodical boundaries, as they are not part of the delaunay triangulation!

            scalar charge = 0, sign;
            Vector3 triangle_normal;
            for (int i = 0; i < triangulation.size(); ++i)
            {
                int i1 = triangulation[i][0];
                int i2 = triangulation[i][1];
                int i3 = triangulation[i][2];

                auto& vp1 = vf_pos[i1];
                auto& vp2 = vf_pos[i2];
                auto& vp3 = vf_pos[i3];

                // TODO: this will only work if the vf_pos are in the xy-plane!
                triangle_normal = (vp1-vp2).cross(vp1-vp3);
                triangle_normal.normalize();
                sign = triangle_normal[2]/std::abs(triangle_normal[2]);

                auto& v1 = vf[i1];
                auto& v2 = vf[i2];
                auto& v3 = vf[i3];

                // charge += sign * solid_angle_1(v1, v2, v3);
                charge += sign * solid_angle_2(v1, v2, v3);
            }
            return charge / (4*Pi);
        }

        // Utility function for the SIB Solver
        void transform(const vectorfield & spins, const vectorfield & force, vectorfield & out)
        {
            #pragma omp parallel for
            for (unsigned int i = 0; i < spins.size(); ++i)
            {
                Vector3 A = 0.5 * force[i];

                // 1/determinant(A)
                scalar detAi = 1.0 / (1 + pow(A.norm(), 2.0));

                // calculate equation without the predictor?
                Vector3 a2 = spins[i] - spins[i].cross(A);

                out[i][0] = (a2[0] * (A[0] * A[0] + 1   ) + a2[1] * (A[0] * A[1] - A[2]) + a2[2] * (A[0] * A[2] + A[1])) * detAi;
                out[i][1] = (a2[0] * (A[1] * A[0] + A[2]) + a2[1] * (A[1] * A[1] + 1   ) + a2[2] * (A[1] * A[2] - A[0])) * detAi;
                out[i][2] = (a2[0] * (A[2] * A[0] - A[1]) + a2[1] * (A[2] * A[1] + A[0]) + a2[2] * (A[2] * A[2] + 1   )) * detAi;
            }
        }

        void get_random_vector(std::uniform_real_distribution<scalar> & distribution, std::mt19937 & prng, Vector3 & vec)
        {
            for (int dim = 0; dim < 3; ++dim)
            {
                vec[dim] = distribution(prng);
            }
        }
        void get_random_vectorfield(std::mt19937 & prng, vectorfield & xi)
        {
            // PRNG gives RN [-1,1] -> multiply with epsilon
            auto distribution = std::uniform_real_distribution<scalar>(-1, 1);
            // TODO: parallelization of this is actually not quite so trivial
            #pragma omp parallel for
            for (unsigned int i = 0; i < xi.size(); ++i)
            {
                get_random_vector(distribution, prng, xi[i]);
            }
        }

        void get_random_vector_unitsphere(std::uniform_real_distribution<scalar> & distribution, std::mt19937 & prng, Vector3 & vec)
        {
            scalar v_z = distribution(prng);
            scalar phi = distribution(prng);

            scalar r_xy = std::sqrt(1 - v_z*v_z);

            vec[0] = r_xy * std::cos(2*Pi*phi);
            vec[1] = r_xy * std::sin(2*Pi*phi);
            vec[2] = v_z;
        }
        void get_random_vectorfield_unitsphere(std::mt19937 & prng, vectorfield & xi)
        {
            // PRNG gives RN [-1,1] -> multiply with epsilon
            auto distribution = std::uniform_real_distribution<scalar>(-1, 1);
            // TODO: parallelization of this is actually not quite so trivial
            #pragma omp parallel for
            for (unsigned int i = 0; i < xi.size(); ++i)
            {
                get_random_vector_unitsphere(distribution, prng, xi[i]);
            }
        }

        void get_gradient_distribution(const Data::Geometry & geometry, Vector3 gradient_direction, scalar gradient_start, scalar gradient_inclination, scalarfield & distribution, scalar range_min, scalar range_max)
        {
            // Ensure a normalized direction vector
            gradient_direction.normalize();

            // Basic linear gradient distribution
            set_c_dot(gradient_inclination, gradient_direction, geometry.positions, distribution);

            // Get the minimum (i.e. starting point) of the distribution
            scalar bmin = geometry.bounds_min.dot(gradient_direction);
            scalar bmax = geometry.bounds_max.dot(gradient_direction);
            scalar dist_min = std::min(bmin, bmax);
            // Set the starting point
            add(distribution, gradient_start - gradient_inclination*dist_min);

            // Cut off negative values
            set_range(distribution, range_min, range_max);
        }

        void directional_gradient(const vectorfield & vf, const Data::Geometry & geometry, const intfield & boundary_conditions, const Vector3 & direction, vectorfield & gradient)
        {
            // std::cout << "start gradient" << std::endl;
            vectorfield translations = { { 0,0,0 }, { 0,0,0 }, { 0,0,0 } };
            auto& n_cells = geometry.n_cells;

            Vector3 a = geometry.bravais_vectors[0]; // translation vectors of the system
            Vector3 b = geometry.bravais_vectors[1];
            Vector3 c = geometry.bravais_vectors[2];

            neighbourfield neigh;

            // TODO: calculate Neighbours outside iterations
            // Neighbours::get_Neighbours(geometry, neigh);

            // TODO: proper usage of neighbours
            // Hardcoded neighbours - for spin current in a rectangular lattice
            neigh = neighbourfield(0);
            Neighbour neigh_tmp;
            neigh_tmp.i = 0;
            neigh_tmp.j = 0;
            neigh_tmp.idx_shell = 0;

            neigh_tmp.translations[0] = 1;
            neigh_tmp.translations[1] = 0;
            neigh_tmp.translations[2] = 0;
            neigh.push_back(neigh_tmp);

            neigh_tmp.translations[0] = -1;
            neigh_tmp.translations[1] = 0;
            neigh_tmp.translations[2] = 0;
            neigh.push_back(neigh_tmp);

            neigh_tmp.translations[0] = 0;
            neigh_tmp.translations[1] = 1;
            neigh_tmp.translations[2] = 0;
            neigh.push_back(neigh_tmp);

            neigh_tmp.translations[0] = 0;
            neigh_tmp.translations[1] = -1;
            neigh_tmp.translations[2] = 0;
            neigh.push_back(neigh_tmp);

            neigh_tmp.translations[0] = 0;
            neigh_tmp.translations[1] = 0;
            neigh_tmp.translations[2] = 1;
            neigh.push_back(neigh_tmp);

            neigh_tmp.translations[0] = 0;
            neigh_tmp.translations[1] = 0;
            neigh_tmp.translations[2] = -1;
            neigh.push_back(neigh_tmp);

            // Loop over vectorfield
            for(unsigned int ispin = 0; ispin < vf.size(); ++ispin)
            {
                auto translations_i = translations_from_idx(n_cells, geometry.n_cell_atoms, ispin); // transVec of spin i
                // int k = i%geometry.n_cell_atoms; // index within unit cell - k=0 for all cases used in the thesis
                scalar n = 0;

                gradient[ispin].setZero();

                std::vector<Vector3> euclidean { {1,0,0}, {0,1,0}, {0,0,1} };
                std::vector<Vector3> contrib = { {0, 0, 0}, {0, 0, 0}, {0, 0, 0} };
                Vector3 proj = {0, 0, 0};
                Vector3 projection_inv = {0, 0, 0};

                // TODO: both loops together.

                // Loop over neighbours of this vector to calculate contributions of finite differences to current direction
                for(unsigned int j = 0; j < neigh.size(); ++j)
                {
                    if ( boundary_conditions_fulfilled(geometry.n_cells, boundary_conditions, translations_i, neigh[j].translations) )
                    {
                        // Index of neighbour
                        int ineigh = idx_from_translations(n_cells, geometry.n_cell_atoms, translations_i, neigh[j].translations);
                        if (ineigh >= 0)
                        {
                            auto d = geometry.positions[ineigh] - geometry.positions[ispin];
                            for (int dim=0; dim<3; ++dim)
                            {
                                proj[dim] += std::abs(euclidean[dim].dot(d.normalized()));
                            }
                        }
                    }
                }
                for (int dim=0; dim<3; ++dim)
                {
                    if (std::abs(proj[dim]) > 1e-10)
                        projection_inv[dim] = 1.0/proj[dim];
                }
                // Loop over neighbours of this vector to calculate finite differences
                for(unsigned int j = 0; j < neigh.size(); ++j)
                {
                    if ( boundary_conditions_fulfilled(geometry.n_cells, boundary_conditions, translations_i, neigh[j].translations) )
                    {
                        // Index of neighbour
                        int ineigh = idx_from_translations(n_cells, geometry.n_cell_atoms, translations_i, neigh[j].translations);
                        if (ineigh >= 0)
                        {
                            auto d = geometry.positions[ineigh] - geometry.positions[ispin];
                            for (int dim=0; dim<3; ++dim)
                            {
                                contrib[dim] += euclidean[dim].dot(d) / d.dot(d) * ( vf[ineigh] - vf[ispin] );
                            }
                        }
                    }
                }

                for (int dim=0; dim<3; ++dim)
                {
                    gradient[ispin] += direction[dim]*projection_inv[dim] * contrib[dim];
                }
            }
        }

        /////////////////////////////////////////////////////////////////

        void fill(scalarfield & sf, scalar s)
        {
            #pragma omp parallel for
            for (unsigned int i = 0; i<sf.size(); ++i)
                sf[i] = s;
        }
        void fill(scalarfield & sf, scalar s, const intfield & mask)
        {
            #pragma omp parallel for
            for (unsigned int i=0; i<sf.size(); ++i)
                sf[i] = mask[i]*s;
        }

        void scale(scalarfield & sf, scalar s)
        {
            #pragma omp parallel for
            for (unsigned int i = 0; i<sf.size(); ++i)
                sf[i] *= s;
        }

        void add(scalarfield & sf, scalar s)
        {
            #pragma omp parallel for
            for (unsigned int i = 0; i<sf.size(); ++i)
                sf[i] += s;
        }

        scalar sum(const scalarfield & sf)
        {
            scalar ret = 0;
            #pragma omp parallel for reduction(+:ret)
            for (unsigned int i = 0; i<sf.size(); ++i)
                ret += sf[i];
            return ret;
        }

        scalar mean(const scalarfield & sf)
        {
            scalar ret = sum(sf)/sf.size();
            return ret;
        }

        void set_range(scalarfield & sf, scalar sf_min, scalar sf_max)
        {
            #pragma omp parallel for
            for (unsigned int i = 0; i<sf.size(); ++i)
                sf[i] = std::min( std::max( sf_min, sf[i] ), sf_max );
        }

        void fill(vectorfield & vf, const Vector3 & v)
        {
            #pragma omp parallel for
            for (unsigned int i=0; i<vf.size(); ++i)
                vf[i] = v;
        }
        void fill(vectorfield & vf, const Vector3 & v, const intfield & mask)
        {
            #pragma omp parallel for
            for (unsigned int i=0; i<vf.size(); ++i)
                vf[i] = mask[i]*v;
        }

        void normalize_vectors(vectorfield & vf)
        {
            #pragma omp parallel for
            for (unsigned int i=0; i<vf.size(); ++i)
                vf[i].normalize();
        }

        void norm( const vectorfield & vf, scalarfield & norm )
        {
            for (unsigned int i=0; i<vf.size(); ++i)
                norm[i] = vf[i].norm();
        }

        std::pair<scalar, scalar> minmax_component(const vectorfield & v1)
        {
            scalar minval=1e6, maxval=-1e6;
            std::pair<scalar, scalar> minmax;
            #pragma omp parallel for reduction(min: minval) reduction(max : maxval)
            for (unsigned int i = 0; i < v1.size(); ++i)
            {
                for (int dim = 0; dim < 3; ++dim)
                {
                    if (v1[i][dim] < minval) minval = v1[i][dim];
                    if (v1[i][dim] > maxval) maxval = v1[i][dim];
                }
            }
            minmax.first = minval;
            minmax.second = maxval;
            return minmax;
        }
        scalar  max_abs_component(const vectorfield & vf)
        {
            // We want the Maximum of Absolute Values of all force components on all images
            scalar absmax = 0;
            // Find minimum and maximum values
            std::pair<scalar,scalar> minmax = minmax_component(vf);
            // Mamimum of absolute values
            absmax = std::max(absmax, std::abs(minmax.first));
            absmax = std::max(absmax, std::abs(minmax.second));
            // Return
            return absmax;
        }

        void scale(vectorfield & vf, const scalar & sc)
        {
            #pragma omp parallel for
            for (unsigned int i=0; i<vf.size(); ++i)
                vf[i] *= sc;
        }

        Vector3 sum(const vectorfield & vf)
        {
            Vector3 ret = { 0,0,0 };
            #pragma omp parallel for reduction(+:ret)
            for (unsigned int i = 0; i<vf.size(); ++i)
                ret += vf[i];
            return ret;
        }

        Vector3 mean(const vectorfield & vf)
        {
            Vector3 ret = sum(vf)/vf.size();
            return ret;
        }

        void divide( const scalarfield & numerator, const scalarfield & denominator, scalarfield & out )
        {
            #pragma omp parallel for
            for (unsigned int i=0; i<out.size(); ++i)
                out[i] = numerator[i] / denominator[i];
        }

        // computes the inner product of two vectorfields v1 and v2
        scalar dot(const vectorfield & v1, const vectorfield & v2)
        {
            scalar ret = 0;
            #pragma omp parallel for reduction(+:ret)
            for (unsigned int i = 0; i<v1.size(); ++i)
                ret += v1[i].dot(v2[i]);
            return ret;
        }

        // computes the inner products of vectors in vf1 and vf2
        // vf1 and vf2 are vectorfields
        void dot(const vectorfield & vf1, const vectorfield & vf2, scalarfield & out)
        {
            #pragma omp parallel for
            for (unsigned int i=0; i<vf1.size(); ++i)
                out[i] = vf1[i].dot(vf2[i]);
        }

        // computes the product of scalars in s1 and s2
        // s1 and s2 are scalarfields
        void dot( const scalarfield & s1, const scalarfield & s2, scalarfield & out )
        {
            #pragma omp parallel for
            for (unsigned int i=0; i<s1.size(); i++)
                out[i] = s1[i] * s2[i];
        }

        // computes the vector (cross) products of vectors in v1 and v2
        // v1 and v2 are vector fields
        void cross(const vectorfield & v1, const vectorfield & v2, vectorfield & out)
        {
            #pragma omp parallel for
            for (unsigned int i=0; i<v1.size(); ++i)
                out[i] = v1[i].cross(v2[i]);
        }

        // out[i] += c*a
        void add_c_a(const scalar & c, const Vector3 & vec, vectorfield & out)
        {
            #pragma omp parallel for
            for(unsigned int idx = 0; idx < out.size(); ++idx)
                out[idx] += c*vec;
        }
        // out[i] += c*a[i]
        void add_c_a(const scalar & c, const vectorfield & vf, vectorfield & out)
        {
            #pragma omp parallel for
            for(unsigned int idx = 0; idx < out.size(); ++idx)
                out[idx] += c*vf[idx];
        }
        void add_c_a(const scalar & c, const vectorfield & vf, vectorfield & out, const intfield & mask)
        {
            #pragma omp parallel for
            for (unsigned int idx = 0; idx < out.size(); ++idx)
                out[idx] += mask[idx] * c*vf[idx];
        }
        // out[i] += c[i]*a[i]
        void add_c_a( const scalarfield & c, const vectorfield & vf, vectorfield & out )
        {
            #pragma omp parallel for
            for( unsigned int idx = 0; idx < out.size(); ++idx )
                out[idx] += c[idx] * vf[idx];
        }

        // out[i] = c*a
        void set_c_a(const scalar & c, const Vector3 & vec, vectorfield & out)
        {
            #pragma omp parallel for
            for(unsigned int idx = 0; idx < out.size(); ++idx)
                out[idx] = c*vec;
        }
        // out[i] = c*a
        void set_c_a(const scalar & c, const Vector3 & vec, vectorfield & out, const intfield & mask)
        {
            #pragma omp parallel for
            for(unsigned int idx = 0; idx < out.size(); ++idx)
                out[idx] = mask[idx]*c*vec;
        }

        // out[i] = c*a[i]
        void set_c_a(const scalar & c, const vectorfield & vf, vectorfield & out)
        {
            #pragma omp parallel for
            for(unsigned int idx = 0; idx < out.size(); ++idx)
                out[idx] = c*vf[idx];
        }
        // out[i] = c*a[i]
        void set_c_a(const scalar & c, const vectorfield & vf, vectorfield & out, const intfield & mask)
        {
            #pragma omp parallel for
            for(unsigned int idx = 0; idx < out.size(); ++idx)
                out[idx] = mask[idx] * c*vf[idx];
        }
        // out[i] = c[i]*a[i]
        void set_c_a( const scalarfield & c, const vectorfield & vf, vectorfield & out )
        {
            #pragma omp parallel for
            for( unsigned int idx=0; idx < out.size(); ++idx)
                out[idx] = c[idx] * vf[idx];
        }

        // out[i] += c * a*b[i]
        void add_c_dot(const scalar & c, const Vector3 & vec, const vectorfield & vf, scalarfield & out)
        {
            #pragma omp parallel for
            for(unsigned int idx = 0; idx < out.size(); ++idx)
                out[idx] += c*vec.dot(vf[idx]);
        }
        // out[i] += c * a[i]*b[i]
        void add_c_dot(const scalar & c, const vectorfield & vf1, const vectorfield & vf2, scalarfield & out)
        {
            #pragma omp parallel for
            for(unsigned int idx = 0; idx < out.size(); ++idx)
                out[idx] += c*vf1[idx].dot(vf2[idx]);
        }

        // out[i] = c * a*b[i]
        void set_c_dot(const scalar & c, const Vector3 & a, const vectorfield & b, scalarfield & out)
        {
            #pragma omp parallel for
            for(unsigned int idx = 0; idx < out.size(); ++idx)
                out[idx] = c*a.dot(b[idx]);
        }
        // out[i] = c * a[i]*b[i]
        void set_c_dot(const scalar & c, const vectorfield & a, const vectorfield & b, scalarfield & out)
        {
            #pragma omp parallel for
            for(unsigned int idx = 0; idx < out.size(); ++idx)
                out[idx] = c*a[idx].dot(b[idx]);
        }

        // out[i] += c * a x b[i]
        void add_c_cross(const scalar & c, const Vector3 & a, const vectorfield & b, vectorfield & out)
        {
            #pragma omp parallel for
            for(unsigned int idx = 0; idx < out.size(); ++idx)
                out[idx] += c*a.cross(b[idx]);
        }
        // out[i] += c * a[i] x b[i]
        void add_c_cross(const scalar & c, const vectorfield & a, const vectorfield & b, vectorfield & out)
        {
            #pragma omp parallel for
            for(unsigned int idx = 0; idx < out.size(); ++idx)
                out[idx] += c*a[idx].cross(b[idx]);
        }
        // out[i] += c[i] * a[i] x b[i]
        void add_c_cross(const scalarfield & c, const vectorfield & a, const vectorfield & b, vectorfield & out)
        {
            #pragma omp parallel for
            for (unsigned int idx = 0; idx < out.size(); ++idx)
                out[idx] += c[idx] * a[idx].cross(b[idx]);
        }

        // out[i] = c * a x b[i]
        void set_c_cross(const scalar & c, const Vector3 & a, const vectorfield & b, vectorfield & out)
        {
            #pragma omp parallel for
            for(unsigned int idx = 0; idx < out.size(); ++idx)
                out[idx] = c*a.cross(b[idx]);
        }
        // out[i] = c * a[i] x b[i]
        void set_c_cross(const scalar & c, const vectorfield & a, const vectorfield & b, vectorfield & out)
        {
            #pragma omp parallel for
            for(unsigned int idx = 0; idx < out.size(); ++idx)
                out[idx] = c*a[idx].cross(b[idx]);
        }
    }
}

#endif

max_stars_repo_name: SpiritSuperUser/spirit

max_issues_repo_name: SpiritSuperUser/spirit

max_forks_repo_name: SpiritSuperUser/spirit


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

// Copyright (c) 2007-2011 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_GEOMETRY_POLICIES_RELATE_INTERSECTION_POINTS_HPP
#define BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_INTERSECTION_POINTS_HPP

#include <algorithm>
#include <string>

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

#include <boost/geometry/core/access.hpp>
#include <boost/geometry/strategies/side_info.hpp>
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/util/select_most_precise.hpp>

namespace boost { namespace geometry
{

namespace policies { namespace relate
{

template <typename S1, typename S2, typename ReturnType, typename CalculationType = void>
struct segments_intersection_points
{
    typedef ReturnType return_type;
    typedef S1 segment_type1;
    typedef S2 segment_type2;
    typedef typename select_calculation_type
        <
            S1, S2, CalculationType
        >::type coordinate_type;

    // Get the same type, but at least a double
    typedef typename select_most_precise<coordinate_type, double>::type rtype;

    static inline return_type segments_intersect(side_info const&,
                    coordinate_type const& dx1, coordinate_type const& dy1,
                    coordinate_type const& dx2, coordinate_type const& dy2,
                    S1 const& s1, S2 const& s2)
    {
        return_type result;
        typedef typename geometry::coordinate_type
            <
                typename return_type::point_type
            >::type coordinate_type;

        // Get the same type, but at least a double (also used for divisions
        typedef typename select_most_precise
            <
                coordinate_type, double
            >::type promoted_type;

        promoted_type const s1x = get<0, 0>(s1);
        promoted_type const s1y = get<0, 1>(s1);

        // Calculate other determinants - Cramers rule
        promoted_type const wx = get<0, 0>(s1) - get<0, 0>(s2);
        promoted_type const wy = get<0, 1>(s1) - get<0, 1>(s2);
        promoted_type const d = (dy2 * dx1) - (dx2 * dy1);
        promoted_type const da = (promoted_type(dx2) * wy) - (promoted_type(dy2) * wx);

        // r: ratio 0-1 where intersection divides A/B
        promoted_type const r = da / d;

        result.count = 1;
        set<0>(result.intersections[0],
            boost::numeric_cast<coordinate_type>(s1x + r * promoted_type(dx1)));
        set<1>(result.intersections[0],
            boost::numeric_cast<coordinate_type>(s1y + r * promoted_type(dy1)));

        return result;
    }

    static inline return_type collinear_touch(coordinate_type const& x,
                coordinate_type const& y, int, int)
    {
        return_type result;
        result.count = 1;
        set<0>(result.intersections[0], x);
        set<1>(result.intersections[0], y);
        return result;
    }

    template <typename S>
    static inline return_type collinear_inside(S const& s, int index1 = 0, int index2 = 1)
    {
        return_type result;
        result.count = 2;
        set<0>(result.intersections[index1], get<0, 0>(s));
        set<1>(result.intersections[index1], get<0, 1>(s));
        set<0>(result.intersections[index2], get<1, 0>(s));
        set<1>(result.intersections[index2], get<1, 1>(s));
        return result;
    }

    template <typename S>
    static inline return_type collinear_interior_boundary_intersect(S const& s, bool a_in_b,
                int, int, bool opposite)
    {
        int index1 = opposite && ! a_in_b ? 1 : 0;
        return collinear_inside(s, index1, 1 - index1);
    }

    static inline return_type collinear_a_in_b(S1 const& s, bool opposite)
    {
        return collinear_inside(s);
    }
    static inline return_type collinear_b_in_a(S2 const& s, bool opposite)
    {
        int index1 = opposite ? 1 : 0;
        return collinear_inside(s, index1, 1 - index1);
    }

    static inline return_type collinear_overlaps(
                coordinate_type const& x1, coordinate_type const& y1,
                coordinate_type const& x2, coordinate_type const& y2,
                int, int, bool)
    {
        return_type result;
        result.count = 2;
        set<0>(result.intersections[0], x1);
        set<1>(result.intersections[0], y1);
        set<0>(result.intersections[1], x2);
        set<1>(result.intersections[1], y2);
        return result;
    }

    static inline return_type segment_equal(S1 const& s, bool opposite)
    {
        return_type result;
        result.count = 2;
        // TODO: order of IP's
        set<0>(result.intersections[0], get<0, 0>(s));
        set<1>(result.intersections[0], get<0, 1>(s));
        set<0>(result.intersections[1], get<1, 0>(s));
        set<1>(result.intersections[1], get<1, 1>(s));
        return result;
    }

    static inline return_type disjoint()
    {
        return return_type();
    }
    static inline return_type error(std::string const& msg)
    {
        return return_type();
    }

    static inline return_type collinear_disjoint()
    {
        return return_type();
    }
    static inline return_type parallel()
    {
        return return_type();
    }
    static inline return_type degenerate(S1 const& s, bool)
    {
        return_type result;
        result.count = 1;
        set<0>(result.intersections[0], get<0, 0>(s));
        set<1>(result.intersections[0], get<0, 1>(s));
        return result;
    }
};

}} // namespace policies::relate

}} // namespace boost::geometry

#endif // BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_INTERSECTION_POINTS_HPP

ext: hpp

max_stars_repo_name: zigaosolin/Raytracer

max_issues_repo_name: zigaosolin/Raytracer

max_forks_repo_name: zigaosolin/Raytracer


text:
#include "LiveViewAgent.h"

#include "Utils\Patterns\PublisherSubscriber\Broker.h"
#include "../../Network/Events.h"
#include "..\..\Network\Model\Credentials.h"
#include "..\..\System\Services\IniFileService.h"
#include "System\Model\ExecutableFile.h"
#include "System\Model\ProcessInformation.h"
#include "System/Services/LogService.h"

#include <boost/filesystem.hpp>
#include <iostream>
#include <chrono>
#include <locale>
#include <codecvt>
#include <string>
#include <thread>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/c_local_time_adjustor.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/thread.hpp>

#include <httplib.h>

namespace desktop { namespace core { namespace agent {

	LiveViewAgent::LiveViewAgent(std::unique_ptr<service::system::ICreateProcessService> createProcessService,
									std::unique_ptr<service::system::TerminateProcessService> terminateProcessService,
									std::unique_ptr<service::HTTPClientService> clientService,
									std::unique_ptr<service::ApplicationDataService> applicationService,
									std::unique_ptr<service::IniFileService> iniFileService,
									std::unique_ptr<service::TimestampFolderService> timestampFolderService,
									std::unique_ptr<service::TimeZoneService> timeZoneService)
	: m_iniFileService(std::move(iniFileService))
	, m_clientService(std::move(clientService))
	, m_applicationService(std::move(applicationService))
	, m_timestampFolderService(std::move(timestampFolderService))
	, m_createProcessService(std::move(createProcessService))
	, m_terminateProcessService(std::move(terminateProcessService))
	, m_timeZoneService(std::move(timeZoneService))
	, m_server(std::make_unique<httplib::Server>())
	{
		auto documents = m_applicationService->getMyDocuments();

		{
			m_seconds = m_iniFileService->get<unsigned int>(documents + "Blink.ini", "LiveView", "Interval", 10);

			m_outFolder = m_iniFileService->get<std::string>(documents + "Blink.ini", "LiveView", "Output", documents + "Download\\Videos\\");

			m_saveLocalTime = m_iniFileService->get<bool>(documents + "Blink.ini", "LiveView", "UseLocalTime", false);
		}

		auto host = m_iniFileService->get<std::string>(documents + "Blink.ini", "LiveView", "Host", "127.0.0.1");
		auto port = m_iniFileService->get<int>(documents + "Blink.ini", "LiveView", "Port", 9192);

		m_endpoint = "http://" + host + ":" + std::to_string(port);

		m_server->Get(".*", [this](const httplib::Request& req, httplib::Response& res) {handleGET(req, res); });
		m_server->Post(".*", [this](const httplib::Request& req, httplib::Response& res, const httplib::ContentReader &content_reader) {handlePOST(req, res, content_reader); });
		m_server->Delete(".*", [this](const httplib::Request& req, httplib::Response& res) {handleDELETE(req, res); });

		service::LogService::info("Listening LiveViewServer at {}:{}", host, port);

		std::thread([=]()
		{
			m_server->listen(host.c_str(), port);
		}).detach();
	}

	LiveViewAgent::~LiveViewAgent()
	{
		m_enabled = false;

		m_server->stop();

		for(auto& liveView : m_liveViews)
		{
			m_terminateProcessService->sigint(*liveView.second);
			m_liveViews.erase(liveView.first);
		}
	}

	void LiveViewAgent::handleGET(const httplib::Request& req, httplib::Response& res) const
	{
		auto body = req.path;

		body = boost::replace_all_copy(body, "/", "\\");

		boost::replace_all(body, "%20", " ");

		boost::filesystem::path path(m_outFolder + body);

		std::string pepe = path.extension().string();

		if(path.extension() == ".m3u8")
		{
			while(!boost::filesystem::exists(path) && m_enabled)
			{
				boost::this_thread::sleep_for(boost::chrono::milliseconds(200));
			}
		}

		if (boost::filesystem::exists(path))
		{
			std::ifstream ifs(path.string(), std::ifstream::binary);
			std::string data = std::string(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>());

			res.set_content(data, "application/x-mpegURL");
		}
		else
		{
			res.status = 404;
		}

		service::LogService::info("HTTP GET {} LiveViewServer {}", res.status, body);
	}

	void LiveViewAgent::handlePOST(const httplib::Request& req, httplib::Response& res, const httplib::ContentReader &content_reader)
	{
		std::stringstream ss;
		content_reader([&](const char *data, size_t data_length)
		{
			ss << std::string(data, data_length);
			return true;
		});

		boost::property_tree::ptree payload;
		boost::property_tree::read_json(ss, payload);

		std::string url = payload.get<std::string>("url");

		m_RTP = std::make_unique<model::RTP>(url);

		auto appFolder = m_applicationService->getApplicationFolder();

		time_t now;
		time(&now);

		std::string iso = boost::posix_time::to_iso_extended_string(boost::posix_time::from_time_t(now));

		std::string currentTime = iso.substr(0, iso.find_first_of(",")) + "+00:00";

		if (m_saveLocalTime)
		{
			currentTime = m_timeZoneService->universalToLocal(currentTime);
		}

		currentTime = boost::replace_all_copy(currentTime, ":", "_");

		std::stringstream folderSS;
		folderSS << m_timestampFolderService->get(currentTime) << "LiveView_";
		folderSS << currentTime;

		auto folder = folderSS.str();

		auto absPath = m_outFolder + folder;

		boost::filesystem::create_directories(absPath);

		auto arguments = "-report -i \"" + m_RTP->m_url + "\" -c copy -vcodec copy -g 30 -hls_time 1 out.m3u8 -vcodec copy " + currentTime + ".mp4";

		model::system::ExecutableFile ffmpeg(model::system::ExecutableFile::Path(appFolder + "\\ffmpeg.exe"), model::system::ExecutableFile::Arguments(arguments));

		int camera_id = payload.get<int>("camera_id");

		std::stringstream camera_idss;
		camera_idss << camera_id;

		auto process = m_createProcessService->create(ffmpeg, absPath);

		m_liveViews.insert(std::make_pair(camera_id, std::move(process)));

		boost::replace_all(folder, "\\", "/");

		std::string endpoint = m_endpoint + "/" + boost::replace_all_copy(folder, "\\", "/") + "/out.m3u8";

		res.set_content("{\"camera_id\": " + camera_idss.str() + ", \"url\": \"" + endpoint + "\"}", "application/json");

		service::LogService::info("HTTP POST {} LiveViewServer {}", res.status, url);

		service::LogService::info("Execute FFMPEG {}", arguments);
	}

	void LiveViewAgent::handleDELETE(const httplib::Request& req, httplib::Response& res)
	{
		int camera_id;

		std::istringstream is(req.get_param_value("camera_id"));
		is >> camera_id;

		auto liveView = m_liveViews.find(camera_id);

		if (liveView != m_liveViews.end())
		{
			m_terminateProcessService->sigint(*liveView->second);

			m_liveViews.erase(camera_id);

			res.set_content("{}", "application/json");
		}
		else
		{
			res.status = 404;
		}

		service::LogService::info("HTTP DELETE {} LiveViewServer Camera {}", res.status, camera_id);
	}
}}}

ext: cpp


text:
#include <iostream>
#include <string>

#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>

class BackGroundJobManager
{
    boost::asio::io_service& m_io_service;
    boost::shared_ptr<boost::asio::io_service::work> m_Work;
    boost::thread_group m_Group;

public:
    BackGroundJobManager( boost::asio::io_service& io_service, std::size_t size)
        : m_io_service(io_service)
    {
        m_Work.reset( new boost::asio::io_service::work(m_io_service) );

        for (std::size_t i = 0; i < size; ++i)
        {
            m_Group.create_thread( boost::bind(&boost::asio::io_service::run, &m_io_service) );
        }
    }

    ~BackGroundJobManager()
    {
        m_Work.reset();
        m_Group.join_all();
    }

    template <class F>
    void post(F f)
    {
        m_io_service.post(f);
    }
};

void Function( int nNumber )
{
    char szMessage[128] = {0,};
    sprintf_s( szMessage, 128-1, "%s(%d) | time(%d)", __FUNCTION__, nNumber, time(NULL) );
    {
        std::cout << "워커 스레드 ID: " << ::GetCurrentThreadId() << ". " << szMessage << std::endl;
    }

    ::Sleep(1000);
}

int main()
{
    std::cout << "메인 스레드 ID: " << ::GetCurrentThreadId() << std::endl;

    boost::asio::io_service io_service;
    BackGroundJobManager JobManager( io_service, 3 );

    boost::asio::strand st( io_service );
    JobManager.post( st.wrap( boost::bind(Function, 11) ) );
    JobManager.post( st.wrap( boost::bind(Function, 12) ) );

    ::Sleep(3000);
    return 0;
}


text:
//
// udpvpn.cpp
// ~~~~~~~~~~
//

#include <string>
#include <iostream>
#include <fstream>
#include <memory>
#include <functional>
#include <boost/array.hpp>
#include <boost/asio.hpp>
#include <boost/program_options.hpp>
#include <boost/exception/diagnostic_information.hpp>
#include <boost/exception_ptr.hpp>
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <openssl/hmac.h>
#include <linux/if.h>
#include <linux/if_tun.h>

// 256 bit keys and 128 bit initial vector
static constexpr int symmetric_key_len = 256 / 8;
static constexpr int symmetric_iv_len = 128 / 8;
static constexpr int signing_key_len = 256 / 8;
static constexpr int signature_len = 256 / 8;

// When used with encryption the payload consists of
// 256-bit SHA-256 HMAC signature followed by a random
// 128-bit initial vector (used by the AES-CBC encryption)
// followed by an encrypted payload.
#pragma pack(push, 1)
struct UdpVpnEncryptedData {
  unsigned char signature[signature_len];
  unsigned char initial_vector[symmetric_iv_len];
  unsigned char data[];
};
#pragma pack(pop)

class UdpVpnServer {
 public:
  UdpVpnServer(boost::asio::io_service& io_service,
               const boost::asio::ip::udp::endpoint& remote,
               const boost::asio::ip::udp::endpoint& local,
               const std::string& tunnel,
               const unsigned char* encryption_key,
               const unsigned char* signing_key)
      : send_socket_(io_service, boost::asio::ip::udp::v4()),
        remote_(remote),
        receive_socket_(io_service, local),
        tunfd_(io_service, tun_alloc(tunnel, IFF_TUN)),
        encryption_key_(encryption_key), signing_key_(signing_key) {
    crypt_init();
  }

  ~UdpVpnServer() {
    if (rx_crypt_ctx_) {
      EVP_CIPHER_CTX_free(rx_crypt_ctx_);
    }
    if (tx_crypt_ctx_) {
      EVP_CIPHER_CTX_free(tx_crypt_ctx_);
    }
    if (hmac_ctx_) {
      HMAC_CTX_free(hmac_ctx_);
    }
  }

  void Start() {
    if (tunfd_.is_open()) {
      TunReceive();
      UdpReceive();
    }
  }

  void TunReceive() {
    tunfd_.async_read_some(
        boost::asio::buffer(tunnel_buffer_, buf_max_len),
        [this](const boost::system::error_code& error,
               std::size_t bytes_transferred) {
          if (bytes_transferred) {
            //std::cout << "Received Tunnel " << bytes_transferred << " bytes\n";
            std::array<unsigned char, buf_max_len>* buffer_data;
            if (tx_crypt_ctx_) {
              UdpVpnEncryptedData* enc_data = (UdpVpnEncryptedData*)
                  encrypted_tunnel_buffer_.data();

              // Generate a random initial vector
              if (RAND_bytes(enc_data->initial_vector, symmetric_iv_len) != 1) {
                ERR_print_errors_fp(stderr);
                throw CryptoException();
              }
              // Encrypt using the random IV
              bytes_transferred = encrypt(
                  tx_crypt_ctx_, enc_data->initial_vector,
                  tunnel_buffer_.data(), bytes_transferred,
                  enc_data->data);
              // Generate a signature over the encrypted data
              sign_data(enc_data->signature, enc_data->data, bytes_transferred);
              // Replace with the complete buffer
              buffer_data = &encrypted_tunnel_buffer_;
              bytes_transferred += signature_len + symmetric_iv_len;
            } else {
              // Use the plaintext buffer
              buffer_data = &tunnel_buffer_;
            }
            send_socket_.async_send_to(
                boost::asio::buffer(*buffer_data, bytes_transferred),
                remote_,
                [this](const boost::system::error_code& error,
                       std::size_t bytes_transferred) {
                  //std::cout << "Sent UDP " << bytes_transferred << " bytes: " << error << "\n";
                  TunReceive();
                });
          }
        });
  }

  void UdpReceive() {
    receive_socket_.async_receive_from(
        boost::asio::buffer(udp_buffer_, buf_max_len),
        from_endpoint_,
        [this](const boost::system::error_code& error,
               std::size_t bytes_transferred) {
          if (bytes_transferred) {
            std::array<unsigned char, buf_max_len>* buffer_data;
            //std::cout << "Received UDP " << bytes_transferred << " bytes\n";
            if (rx_crypt_ctx_) {
              const UdpVpnEncryptedData* enc_data = (UdpVpnEncryptedData*)
                  udp_buffer_.data();
              // Adjust to remove the signature and initial_vector
              bytes_transferred = bytes_transferred - signature_len - symmetric_iv_len;
              // Check that the signature is good
              if (!check_signature(
                      enc_data->signature, enc_data->data, bytes_transferred)) {
                std::cout << "Failed the signature check - drop the data\n";
                UdpReceive();
                return;
              }
              // Decrypt the data using the included initial vector
              bytes_transferred = decrypt(
                  rx_crypt_ctx_, enc_data->initial_vector,
                  enc_data->data, bytes_transferred, plaintext_udp_buffer_.data());
              buffer_data = &plaintext_udp_buffer_;
            } else {
              // Just use the plaintext buffer
              buffer_data = &udp_buffer_;
            }
            tunfd_.async_write_some(
                boost::asio::buffer(*buffer_data, bytes_transferred),
                [this](const boost::system::error_code& error,
                       std::size_t bytes_transferred) {
                  //std::cout << "Sent Tunnel " << bytes_transferred << " bytes: " << error << "\n";
                  UdpReceive();
                });
          }
        });
  }

 private:

  int tun_alloc(std::string dev, int flags) {
    struct ifreq ifr;
    int fd, err;
    char name[IFNAMSIZ];

    strncpy(name, dev.c_str(), IFNAMSIZ);

    if ((fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK)) < 0 ) {
      perror("Opening /dev/net/tun");
      return fd;
    }

    memset(&ifr, 0, sizeof(ifr));
    ifr.ifr_flags = flags;
    strncpy(ifr.ifr_name, name, IFNAMSIZ);
    if ((err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0 ) {
      if (errno == EPERM) {
        std::cerr << "Insufficient priviledge to create or bind to a Tunnel Device.\n" <<
            "Try elevating the user to root access\n";
        close(fd);
        return err;
      }
      perror("ioctl(TUNSETIFF)");
      close(fd);
      return err;
    }

    strcpy(name, ifr.ifr_name);
    return fd;
  }

  struct CryptoException : std::exception {
    char const* what() const throw() {
      return "CryptoException";
    }
  };

  void crypt_init() {
    if (encryption_key_ == nullptr || signing_key_ == nullptr) {
      return;
    }

    /* Create and initialise the contexts */
    if (!(rx_crypt_ctx_ = EVP_CIPHER_CTX_new()))
      throw CryptoException();

    if (!(tx_crypt_ctx_ = EVP_CIPHER_CTX_new()))
      throw CryptoException();

    if (!(hmac_ctx_ = HMAC_CTX_new()))
      throw CryptoException();
  }

  void sign_data(unsigned char* destination,
                 const unsigned char* source,
                 int length) {
    HMAC_Init_ex(hmac_ctx_, signing_key_, signing_key_len, EVP_sha256(), NULL);
    HMAC_Update(hmac_ctx_, source, length);
    unsigned int len = signature_len;
    HMAC_Final(hmac_ctx_, destination, &len);
  }

  bool check_signature(const unsigned char* data_signature,
                       const unsigned char* source,
                       int length) {
    unsigned char signature[signature_len];

    sign_data(signature, source, length);

    return CRYPTO_memcmp(data_signature, signature, signature_len) == 0;
  }

  int encrypt(EVP_CIPHER_CTX *ctx, unsigned char *iv,
              const unsigned char *plaintext,
              int plaintext_len, unsigned char *ciphertext)
  {
    int len;
    int ciphertext_len;

    /*
     * Initialise the encryption operation. IMPORTANT - ensure you use a key
     * and IV size appropriate for your cipher
     * In this example we are using 256 bit AES (i.e. a 256 bit key). The
     * IV size for *most* modes is the same as the block size. For AES this
     * is 128 bits
     */
    if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, encryption_key_, iv)) {
      ERR_print_errors_fp(stderr);
      throw CryptoException();
    }

    /*
     * Provide the message to be encrypted, and obtain the encrypted output.
     * EVP_EncryptUpdate can be called multiple times if necessary
     */
    if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) {
      ERR_print_errors_fp(stderr);
      throw CryptoException();
    }
    ciphertext_len = len;

    /*
     * Finalise the encryption. Further ciphertext bytes may be written at
     * this stage.
     */
    if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) {
      ERR_print_errors_fp(stderr);
      throw CryptoException();
    }
    ciphertext_len += len;

    return ciphertext_len;
  }

  int decrypt(EVP_CIPHER_CTX *ctx, const unsigned char *iv,
              const unsigned char *ciphertext,
              int ciphertext_len, unsigned char *plaintext)
  {
    int len;
    int plaintext_len;

    /*
     * Initialise the decryption operation. IMPORTANT - ensure you use a key
     * and IV size appropriate for your cipher
     * In this example we are using 256 bit AES (i.e. a 256 bit key). The
     * IV size for *most* modes is the same as the block size. For AES this
     * is 128 bits
     */
    if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, encryption_key_, iv)) {
      ERR_print_errors_fp(stderr);
      throw CryptoException();
    }

    /*
     * Provide the message to be decrypted, and obtain the plaintext output.
     * EVP_DecryptUpdate can be called multiple times if necessary.
     */
    if (1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len)) {
      ERR_print_errors_fp(stderr);
      throw CryptoException();
    }
    plaintext_len = len;

    /*
     * Finalise the decryption. Further plaintext bytes may be written at
     * this stage.
     */
    if (1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) {
      ERR_print_errors_fp(stderr);
      throw CryptoException();
    }
    plaintext_len += len;

    return plaintext_len;
  }

  static constexpr int buf_max_len = 1600;
  std::array<unsigned char, buf_max_len> tunnel_buffer_;
  std::array<unsigned char, buf_max_len> encrypted_tunnel_buffer_;
  std::array<unsigned char, buf_max_len> udp_buffer_;
  std::array<unsigned char, buf_max_len> plaintext_udp_buffer_;

  boost::asio::ip::udp::socket send_socket_;
  boost::asio::ip::udp::endpoint remote_;
  boost::asio::ip::udp::socket receive_socket_;
  boost::asio::ip::udp::endpoint from_endpoint_;

  boost::asio::posix::stream_descriptor tunfd_;

  const unsigned char *encryption_key_;
  const unsigned char *signing_key_;
  HMAC_CTX *hmac_ctx_ = nullptr;
  EVP_CIPHER_CTX *rx_crypt_ctx_ = nullptr;
  EVP_CIPHER_CTX *tx_crypt_ctx_ = nullptr;
};

bool decompose_ip_port(const std::string endpoint, std::string& ip, int& port) {
  int cpos = endpoint.find_first_of(':');
  if (cpos == std::string::npos) {
    return false;
  }
  ip = endpoint.substr(0, cpos);
  try {
    boost::asio::ip::address::from_string(ip);
    port = stoi(endpoint.substr(cpos + 1));
  } catch (...) { return false; }
  return true;
}

bool load_encryption_data(const std::string& key_file_path,
                          unsigned char* symmetric_key,
                          unsigned char* signing_key) {
  std::ifstream key_file(key_file_path, std::ifstream::binary);

  key_file.read((char*)symmetric_key, symmetric_key_len);
  if (key_file.gcount() != symmetric_key_len) {
    return false;
  }
  key_file.read((char*)signing_key, signing_key_len);
  if (key_file.gcount() != signing_key_len) {
    return false;
  }

  return true;
}

namespace po = boost::program_options;

int main(int argc, char **argv) {
  std::string endpoint_local;
  std::string endpoint_remote;
  std::string tunnel_device;
  std::string key_file_path;

  po::options_description description(
      "A program to implement a simple VPN tunnel over UDP");
  description.add_options()
      ("help", "Display this help message")
      ("local", po::value<std::string>(&endpoint_local)->required(),
       "(required) Local IP Address and port number for UDP packets (IP:UDPPort)")
      ("remote", po::value<std::string>(&endpoint_remote)->required(),
       "(required) Remote IP Address and port number for UDP packets (IP:UDPPort)")
      ("tunnel", po::value<std::string>(&tunnel_device)->default_value("tun1"),
       "(optional) Tunnel device name to use (default: tun1)")
      ("key", po::value<std::string>(&key_file_path),
       "(optional) Key file to use for symmetric encryption (key file must contain a 256 bit binary key, followed by a 128 bit binary initial vector)");
  po::variables_map vm;

  po::store(
      po::parse_command_line(argc, argv, description), vm);

  try {
    po::notify(vm);
  } catch (...) {
    std::cout << description << "\n";
    exit(1);
  }

  if (vm.count("help")) {
    std::cout << description << "\n";
    exit(0);
  }

  unsigned char symmetric_key[symmetric_key_len];
  unsigned char signing_key[signing_key_len];

  if (!key_file_path.empty()) {
    if (!load_encryption_data(key_file_path, symmetric_key, signing_key)) {
      std::cout << "Unable to load key file from " << key_file_path << "\n";
      exit(1);
    }
  }

  std::string remote_ip;
  int remote_port;
  std::string local_ip;
  int local_port;

  if (!decompose_ip_port(endpoint_remote, remote_ip, remote_port) ||
      !decompose_ip_port(endpoint_local, local_ip, local_port)) {
    std::cout << "IP Address and port number must be in the form IP:UDPPort\n";
    exit(1);
  }

  std::cout << "Remote: " << remote_ip << ":" << remote_port << "\n";
  std::cout << "Local: " << local_ip << ":" << local_port << "\n";
  std::cout << "Tunnel: " << tunnel_device << "\n";

  boost::asio::io_service io_service;

  boost::asio::ip::udp::endpoint remote(
      boost::asio::ip::address::from_string(remote_ip), remote_port);
  boost::asio::ip::udp::endpoint local(
      boost::asio::ip::address::from_string(local_ip), local_port);

  try {
    UdpVpnServer udp_server(io_service, remote, local, tunnel_device,
                            !key_file_path.empty() ? symmetric_key : nullptr,
                            !key_file_path.empty() ? signing_key : nullptr);
    udp_server.Start();
    io_service.run();
  } catch (const boost::exception& ex) {
    std::cout << "exception: " << diagnostic_information(ex) << "\n";
    exit(1);
  }

  exit(0);
}

max_stars_repo_name: jdtsillas/udpvpn

max_issues_repo_name: jdtsillas/udpvpn

max_forks_repo_name: jdtsillas/udpvpn


text:
/* Copyright 2006-2008 Joaquin M Lopez Munoz.
 * 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)
 *
 * See http://www.boost.org/libs/flyweight for library home page.
 */

#ifndef BOOST_FLYWEIGHT_HPP
#define BOOST_FLYWEIGHT_HPP

#if defined(_MSC_VER)&&(_MSC_VER>=1200)
#pragma once
#endif

#include <boost/flyweight/flyweight.hpp>
#include <boost/flyweight/hashed_factory.hpp>
#include <boost/flyweight/refcounted.hpp>
#include <boost/flyweight/simple_locking.hpp>
#include <boost/flyweight/static_holder.hpp>

#endif

max_stars_repo_name: importlib/klib

max_issues_repo_name: isuhao/klib

max_forks_repo_name: isuhao/klib


text:
#ifdef IS_TEST_NET
#include <boost/test/unit_test.hpp>

#include <deip/chain/database/database.hpp>
#include <deip/chain/util/reward.hpp>

#include <deip/chain/schema/expertise_allocation_proposal_object.hpp>
#include <deip/chain/schema/grant_application_object.hpp>
#include <deip/chain/schema/grant_application_review_object.hpp>
#include <deip/chain/schema/research_discipline_relation_object.hpp>
s#include <deip/chain/schema/review_object.hpp>
#include <deip/chain/schema/reward_pool_object.hpp>

#include <deip/chain/services/dbs_account_balance.hpp>

#include "database_fixture.hpp"

namespace deip {
namespace chain {

class database_unit_service_fixture : public clean_database_fixture
{
public:
    database_unit_service_fixture()
            : account_service(db.obtain_service<dbs_account>()),
              review_votes_service(db.obtain_service<dbs_review_vote>()),
              research_content_service(db.obtain_service<dbs_research_content>()),
              account_balance_service(db.obtain_service<dbs_account_balance>())
    {
    }

    void create_researches()
    {
        db.create<research_object>([&](research_object& d) {
            d.id = 1;
            d.research_group_id = 31;
            d.description = "name1";
        });

        db.create<research_object>([&](research_object& d) {
            d.id = 2;
            d.research_group_id = 32;
            d.description = "name2";
        });
    }

    void create_research_contents()
    {
        db.create<research_content_object>([&](research_content_object& d) {
            d.id = 1;
            d.research_id = 1;
            d.type = milestone_article;
            d.authors = {"alice"};
            d.activity_state = research_content_activity_state::active;
        });

        db.create<research_content_object>([&](research_content_object& d) {
            d.id = 2;
            d.research_id = 2;
            d.type = milestone_data;
            d.authors = {"alex"};
            d.activity_state = research_content_activity_state::active;
        });
    }

    void create_research_contents_for_activity_windows()
    {
        db.create<research_content_object>([&](research_content_object& d) {
            d.id = 1;
            d.research_id = 1;
            d.type = milestone_data;
            d.authors = {"alice"};
            d.activity_state = research_content_activity_state::active;
            d.activity_round = 2;
            d.activity_window_end = db.head_block_time() + DAYS_TO_SECONDS(7);
        });

        db.create<research_content_object>([&](research_content_object& d) {
            d.id = 2;
            d.research_id = 2;
            d.type = final_result;
            d.authors = {"alex"};
            d.activity_state = research_content_activity_state::active;
            d.activity_round = 3;
            d.activity_window_end = db.head_block_time() + DAYS_TO_SECONDS(14);
        });
    }

    void create_reward_pools()
    {
        db.create<reward_pool_object>([&](reward_pool_object& d) {
            d.id = 1;
            d.discipline_id = 10;
            d.balance = asset(500, DEIP_SYMBOL);
            d.expertise = 500;
            d.research_content_id = 1;
        });

        db.create<reward_pool_object>([&](reward_pool_object& d) {
            d.id = 2;
            d.discipline_id = 10;
            d.balance = asset(500, DEIP_SYMBOL);
            d.expertise = 500;
            d.research_content_id = 2;
        });
    }

    void create_reviews()
    {
        db.create<review_object>([&](review_object& d) {
            bip::map<discipline_id_type, share_type> reward_weights_per_discipline;
            reward_weights_per_discipline[10] = 100;
            d.id = 1;
            d.research_content_id = 1;
            d.is_positive = true;
            d.author = "alice";
            d.expertise_tokens_amount_by_discipline.insert(reward_weights_per_discipline.begin(), reward_weights_per_discipline.end());
            d.expertise_tokens_amount_by_discipline[10] = 50;
        });

        db.create<review_object>([&](review_object& d) {
            bip::map<discipline_id_type, share_type> reward_weights_per_discipline;
            reward_weights_per_discipline[10] = 100;
            d.id = 2;
            d.research_content_id = 1;
            d.is_positive = true;
            d.author = "bob";
            d.expertise_tokens_amount_by_discipline.insert(reward_weights_per_discipline.begin(), reward_weights_per_discipline.end());
            d.expertise_tokens_amount_by_discipline[10] = 50;
        });
    }

    void create_review_votes()
    {
        db.create<review_vote_object>([&](review_vote_object& d) {
            d.id = 1;
            d.discipline_id = 10;
            d.voter = "jack";
            d.review_id = 1;
            d.weight = 40;
        });

        db.create<review_vote_object>([&](review_vote_object& d) {
            d.id = 2;
            d.discipline_id = 10;
            d.voter = "john";
            d.review_id = 1;
            d.weight = 60;
        });

        db.create<review_vote_object>([&](review_vote_object& d) {
            d.id = 3;
            d.discipline_id = 10;
            d.voter = "jack";
            d.review_id = 2;
            d.weight = 40;
        });

        db.create<review_vote_object>([&](review_vote_object& d) {
            d.id = 4;
            d.discipline_id = 10;
            d.voter = "john";
            d.review_id = 2;
            d.weight = 60;
        });
    }

    void create_discipline_with_weight()
    {
        dbs_discipline& discipline_service = db.obtain_service<dbs_discipline>();

        db.create<discipline_object>([&](discipline_object& d) {
            d.parent_id = 1;
            d.name = "Test Discipline With Weight";
        });
    }

    void create_grant_test_case()
    {
        dbs_discipline& discipline_service = db.obtain_service<dbs_discipline>();

        db.create<discipline_object>([&](discipline_object& d) {
            d.parent_id = 1;
            d.name = "Test Discipline For Grant With Weight";
        });

        db.create<research_content_object>([&](research_content_object& d) {
            d.id = 3;
            d.research_id = 2;
            d.type = final_result;
            d.authors = {"jack"};
        });
    }

    void create_expertise_allocation_proposals()
    {
        db.create<expertise_allocation_proposal_object>([&](expertise_allocation_proposal_object& eap_o) {
            eap_o.id = 0;
            eap_o.claimer = "bob";
            eap_o.discipline_id = 2;
            eap_o.total_voted_expertise = 0;
            eap_o.description = "test1";
            eap_o.expiration_time = time_point_sec(132);
            eap_o.quorum = 15 * DEIP_1_PERCENT;
        });
        db.create<expertise_allocation_proposal_object>([&](expertise_allocation_proposal_object& eap_o) {
            eap_o.id = 1;
            eap_o.claimer = "mike";
            eap_o.discipline_id = 2;
            eap_o.total_voted_expertise = 0;
            eap_o.description = "test2";
            eap_o.expiration_time = time_point_sec(0xffffffff);
            eap_o.quorum = 15 * DEIP_1_PERCENT;
        });
        db.create<expertise_allocation_proposal_object>([&](expertise_allocation_proposal_object& eap_o) {
            eap_o.id = 2;
            eap_o.claimer = "alice";
            eap_o.discipline_id = 21;
            eap_o.total_voted_expertise = 100000;
            eap_o.description = "test3";
            eap_o.expiration_time = time_point_sec(0xffffffff);
            eap_o.quorum = 15 * DEIP_1_PERCENT;
        });
    }

    void create_researches_for_grants()
    {
        db.create<research_object>([&](research_object& d) {
            d.id = 1;
            d.research_group_id = 31;
            d.description = "name1";
            d.number_of_positive_reviews = 10;
        });

        db.create<research_object>([&](research_object& d) {
            d.id = 2;
            d.research_group_id = 32;
            d.description = "name2";
            d.number_of_positive_reviews = 10;
        });

        db.create<research_object>([&](research_object& d) {
            d.id = 3;
            d.research_group_id = 33;
            d.description = "name3";
            d.number_of_positive_reviews = 10;
        });
    }

    void create_rd_relations_for_grants()
    {
        db.create<research_discipline_relation_object>([&](research_discipline_relation_object& r) {
            r.id = 0,
            r.research_id = 1,
            r.discipline_id = 1;
            r.research_eci = 5000;
        });

        db.create<research_discipline_relation_object>([&](research_discipline_relation_object& r) {
            r.id = 1,
            r.research_id = 1,
            r.discipline_id = 2;
            r.research_eci = 5000;
        });

        db.create<research_discipline_relation_object>([&](research_discipline_relation_object& r) {
            r.id = 2,
            r.research_id = 2,
            r.discipline_id = 1;
            r.research_eci = 3000;
        });

        db.create<research_discipline_relation_object>([&](research_discipline_relation_object& r) {
            r.id = 3,
            r.research_id = 2,
            r.discipline_id = 2;
            r.research_eci = 3000;
        });

        db.create<research_discipline_relation_object>([&](research_discipline_relation_object& r) {
            r.id = 4,
            r.research_id = 3,
            r.discipline_id = 1;
            r.research_eci = 2000;
        });

        db.create<research_discipline_relation_object>([&](research_discipline_relation_object& r) {
            r.id = 5,
            r.research_id = 3,
            r.discipline_id = 2;
            r.research_eci = 2000;
        });
    }

    dbs_account& account_service;
    dbs_review_vote& review_votes_service;
    dbs_research_content& research_content_service;
    dbs_account_balance& account_balance_service;
};

BOOST_FIXTURE_TEST_SUITE(database_unit_service, database_unit_service_fixture)

BOOST_AUTO_TEST_SUITE_END()

} // namespace chain
} // namespace deip

#endif

max_stars_repo_name: DEIPworld/deip-chain

max_issues_repo_name: DEIPworld/deip-chain

max_forks_repo_name: DEIPworld/deip-chain


text:
#include <rapidxml_ns/rapidxml_ns.hpp>
#include <svgpp/policy/xml/rapidxml_ns.hpp>
#include <svgpp/document_traversal.hpp>
#include <boost/mpl/set.hpp>
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>

class Gradient;

class GradientStop
{
public:
  GradientStop(Gradient & parent)
    : parent_(parent)
  {
  }

  void on_exit_element();

  void set(svgpp::tag::attribute::offset, double val)
  {
    stop_ = val;
  }

private:
  Gradient & parent_;
  double stop_;
};

class Gradient
{
public:
  enum SpreadMethod { spreadPad, spreadReflect, spreadRepeat };

  Gradient()
    : useObjectBoundingBox_(true)
    , spreadMethod_(spreadPad)
  {
  }

  void add_stop(double stop)
  {
    stops_.push_back(stop);
  }

  void on_exit_element()
  {
  }

  void transform_matrix(const boost::array<double, 6> & matrix)
  {
    matrix_ = matrix;
  }

  template<class StringRange>
  void set(svgpp::tag::attribute::id, StringRange const & str)
  {
    id_.assign(boost::begin(str), boost::end(str));
  }

  void set(svgpp::tag::attribute::gradientUnits, svgpp::tag::value::userSpaceOnUse)
  {
    useObjectBoundingBox_ = false;
  }

  void set(svgpp::tag::attribute::gradientUnits, svgpp::tag::value::objectBoundingBox)
  {
    useObjectBoundingBox_ = true;
  }

  void set(svgpp::tag::attribute::spreadMethod, svgpp::tag::value::pad)
  {
    spreadMethod_ = spreadPad;
  }

  void set(svgpp::tag::attribute::spreadMethod, svgpp::tag::value::reflect)
  {
    spreadMethod_ = spreadReflect;
  }

  void set(svgpp::tag::attribute::spreadMethod, svgpp::tag::value::repeat)
  {
    spreadMethod_ = spreadRepeat;
  }

protected:
  std::string id_;
  boost::array<double, 6> matrix_;
  bool useObjectBoundingBox_;
  SpreadMethod spreadMethod_;
  std::vector<double> stops_;
};

class LinearGradient: public Gradient
{
public:
  LinearGradient()
  {
  }

  using Gradient::set;

  void set(svgpp::tag::attribute::x1, double val)
  {
    x1_ = val;
  }

  void set(svgpp::tag::attribute::y1, double val)
  {
    y1_ = val;
  }

  void set(svgpp::tag::attribute::x2, double val)
  {
    x2_ = val;
  }

  void set(svgpp::tag::attribute::y2, double val)
  {
    y2_ = val;
  }

private:
  double x1_, y1_, x2_, y2_;
};

class RadialGradient: public Gradient
{
public:
  RadialGradient()
  {
  }

  using Gradient::set;

  void set(svgpp::tag::attribute::cx, double val)
  {
    cx_ = val;
  }

  void set(svgpp::tag::attribute::cy, double val)
  {
    cy_ = val;
  }

  void set(svgpp::tag::attribute::r, double val)
  {
    r_ = val;
  }

  void set(svgpp::tag::attribute::fx, double val)
  {
    fx_ = val;
  }

  void set(svgpp::tag::attribute::fy, double val)
  {
    fy_ = val;
  }

private:
  double cx_, cy_, fx_, fy_, r_;
};

void GradientStop::on_exit_element()
{
  parent_.add_stop(stop_);
}

class Canvas
{
public:
  void on_enter_element(svgpp::tag::element::svg const &)
  {
  }

  void on_exit_element()
  {
  }

  boost::shared_ptr<LinearGradient> get_child_context(svgpp::tag::element::linearGradient const &)
  {
    return boost::make_shared<LinearGradient>();
  }

  boost::shared_ptr<RadialGradient> get_child_context(svgpp::tag::element::radialGradient const &)
  {
    return boost::make_shared<RadialGradient>();
  }
};

struct ContextFactories
{
  template<class ParentContext, class ElementTag>
  struct apply
  {
    typedef svgpp::factory::context::same<ParentContext, ElementTag> type;
  };
};

template<class ParentContext>
struct ContextFactories::apply<ParentContext, svgpp::tag::element::linearGradient>
{
  typedef svgpp::factory::context::get_ptr_from_parent<svgpp::tag::element::linearGradient, boost::shared_ptr<LinearGradient> > type;
};

template<class ParentContext>
struct ContextFactories::apply<ParentContext, svgpp::tag::element::radialGradient>
{
  typedef svgpp::factory::context::get_ptr_from_parent<svgpp::tag::element::radialGradient, boost::shared_ptr<RadialGradient> > type;
};

template<class ParentContext>
struct ContextFactories::apply<ParentContext, svgpp::tag::element::stop>
{
  typedef svgpp::factory::context::on_stack<GradientStop> type;
};

int main()
{
#define TEXT(x) #x
  char text[] =
    TEXT(<linearGradient id="MyGradient" xmlns="http://www.w3.org/2000/svg">)
    TEXT( <stop offset="5%" stop-color="#F60"/>)
    TEXT( <stop offset="95%" stop-color="#FF6"/>)
    TEXT(</linearGradient>);

  rapidxml_ns::xml_document<> doc;    // character type defaults to char
  doc.parse<0>(text);
  if (rapidxml_ns::xml_node<> * gradient_element = doc.first_node())
  {
    Canvas canvas;
    svgpp::document_traversal<
      svgpp::context_factories<ContextFactories>,
      svgpp::processed_elements<
        boost::mpl::set<
          svgpp::tag::element::linearGradient,
          svgpp::tag::element::radialGradient,
          svgpp::tag::element::stop
        >::type
      >,
      svgpp::processed_attributes<
        boost::mpl::set<
          boost::mpl::pair<svgpp::tag::element::linearGradient, svgpp::tag::attribute::id>,
          boost::mpl::pair<svgpp::tag::element::linearGradient, svgpp::tag::attribute::x1>,
          boost::mpl::pair<svgpp::tag::element::linearGradient, svgpp::tag::attribute::y1>,
          boost::mpl::pair<svgpp::tag::element::linearGradient, svgpp::tag::attribute::x2>,
          boost::mpl::pair<svgpp::tag::element::linearGradient, svgpp::tag::attribute::y2>,
          boost::mpl::pair<svgpp::tag::element::radialGradient, svgpp::tag::attribute::id>,
          boost::mpl::pair<svgpp::tag::element::radialGradient, svgpp::tag::attribute::fx>,
          boost::mpl::pair<svgpp::tag::element::radialGradient, svgpp::tag::attribute::fy>,
          boost::mpl::pair<svgpp::tag::element::radialGradient, svgpp::tag::attribute::cx>,
          boost::mpl::pair<svgpp::tag::element::radialGradient, svgpp::tag::attribute::cy>,
          boost::mpl::pair<svgpp::tag::element::radialGradient, svgpp::tag::attribute::r>,
          svgpp::tag::attribute::gradientUnits,
          svgpp::tag::attribute::gradientTransform,
          svgpp::tag::attribute::spreadMethod,
          boost::mpl::pair<svgpp::tag::element::stop, svgpp::tag::attribute::offset>
        >::type
      >
    >::load_referenced_element<
      svgpp::expected_elements<svgpp::traits::gradient_elements>
    >::load(gradient_element, canvas);
  }
  return 0;
}

max_stars_repo_name: RichardCory/svgpp


text:
// Copyright Sebastian Ramacher, 2007.
// 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)

#ifndef BOOST_PTR_CONTAINER_SERIALIZE_HPP
#define BOOST_PTR_CONTAINER_SERIALIZE_HPP

#include <boost/ptr_container/serialize_ptr_array.hpp>
#include <boost/ptr_container/serialize_ptr_deque.hpp>
#include <boost/ptr_container/serialize_ptr_list.hpp>
#include <boost/ptr_container/serialize_ptr_map.hpp>
#include <boost/ptr_container/serialize_ptr_set.hpp>
#include <boost/ptr_container/serialize_ptr_vector.hpp>
#include <boost/ptr_container/serialize_ptr_unordered_set.hpp>
#include <boost/ptr_container/serialize_ptr_unordered_map.hpp>
#include <boost/ptr_container/serialize_ptr_circular_buffer.hpp>

#endif

max_stars_repo_name: rudylee/expo

max_issues_repo_name: rudylee/expo

max_forks_repo_name: rudylee/expo


text:
#include "RplidarClass.h"

//#include "rplidar.h" //RPLIDAR standard sdk, all-in-one header
//#include "C:\usr\include\GregUtils\strguple.h"
//#include <boost/circular_buffer.hpp>
//#include <boost/thread.hpp>
#include "windows.h"
#include <chrono>
#include <thread>

#include "c:/usr/include/gregutils/Sqlbuilder.h"
#include <boost/algorithm/string/join.hpp>
#include <boost/range/adaptor/transformed.hpp>
//#include "..\..\..\sdk\workspaces\vc10\rplidarReader\rosstuff.h"
#include "c:/usr/include/rplidar/rosstuff.h"

INIT_RPLIDAR
INIT_STRGUPLE

RplidarReadingQueue::RplidarReadingQueue(float fromRadial, float toRadial, int qSize,
	_u32 baud /*= 256000*/,const char * opt_com_path /*= "\\\\.\\com3"*/) :fromRadial(fromRadial), toRadial(toRadial), baud(baud), opt_com_path(opt_com_path), useRangeFilter(true)
{
	SGUP_ODSA(__FUNCTION__, "COMPORT RECEIVED:", opt_com_path)
	cb = new boost::circular_buffer<rp::measure>(qSize);
}

RplidarReadingQueue::RplidarReadingQueue(int size)
{
	cb = new boost::circular_buffer<rp::measure>(size);
}

void RplidarReadingQueue::setRange(int from, int to)
{
	fromRadial = from;
	toRadial = to;

	if (from == to) {
		useRangeFilter = false;
	}
	else
	useRangeFilter = true;
}

int RplidarReadingQueue::getFromTo(rp::measure & m, int fromRadial, int toRadial)
{
	//boost::mutex::scoped_lock lock(qMutex);
	return -1;
}

int RplidarReadingQueue::getFront(rp::measure & m)
{
	//boost::mutex::scoped_lock lock(qMutex);

	if (cb->empty())
		return 0;

	m = cb->front();

	return cb->size();

}

bool RplidarReadingQueue::isInRange(float theta)
{
	//	float minTheta = std::min(fromRadial, toRadial);
	//	float maxTheta = std::max(fromRadial, toRadial);

	bool truth1 = (theta >= fromRadial) && (theta <= 359.99f);
	//or
	bool truth2 = (theta > 0.0f) && (theta <= toRadial);

	//	SGUP_ODS(__FUNCTION__, "from/to radials", fromRadial, toRadial, "theta:",theta, truth1,truth2,  (truth1 || truth2)?"TRUE":"FALSE"    );

	return (truth1 || truth2);

	//sweep to the right so
	//we must be greater than minTheta up to 359.999
}

//boost::mutex boobs;

bool RplidarReadingQueue::push(rp::measure &m)
{
//	boost::mutex::scoped_lock lock(qMutex);
	//SGUP_ODS(__FUNCTION__, "acquiring lock")

	auto fnConv=[&](_u16 angle, _u16 dist, rp::Clock::time_point tp) {
		auto p = rp::measure::convertAngleDist(angle, dist);
		auto tkey = roundf(p.first * 10) / 10;
	//	storedRead[tkey] = { p.second,tp }; //tkey is angle
		storedRead[tkey] = {  rp::beam(p.second, RplidarReadingQueue::tilt, tp) }; //[angle] ={ distance }
	};

	if (m.distance() == 0) return false;

	auto thet = m.theta();
	m.born = rp::Clock::now();

	if (useRangeFilter)
		if (isInRange(thet)) {
		//	OutputDebugStringA(__FUNCTION__ " start");
			qMutex.lock();
			cb->push_back(m);

			fnConv(m.angle_q6_checkbit, m.distance_q2, m.born);

			//storedRead[m.angle_q6_checkbit] = m.distance_q2;
	//		OutputDebugStringA(__FUNCTION__ " end");
			qMutex.unlock();
		//	SGUP_ODSA("PUSH THETA:", thet);
		//	cout << thet << " ";

			return true;
		}
		else {
			//		SGUP_ODS("REJECT THETA:", thet);

			return false;
		}
	else {
//		OutputDebugStringA(__FUNCTION__ " start 2");
		qMutex.lock();
		cb->push_back(m);
		fnConv(m.angle_q6_checkbit, m.distance_q2, m.born);
		//storedRead[m.theta()] = m.distance();
	//	storedRead[m.angle_q6_checkbit] = m.distance_q2;
		qMutex.unlock();
	//	OutputDebugStringA(__FUNCTION__ " end 2");
	}

	//SGUP_ODS(__FUNCTION__, "release lock")
	return true;
}

void RplidarReadingQueue::getScan(rp::RplidarProxy::ScanVecType2 ** theScan, int msecExpiry)
{

	if (lidarStatus != rp::STARTED) {
		//OutputDebugStringA(__FUNCTION__ " LIDAR not spooled up yet...returning...");
		*theScan = nullptr;
		return;
	}
	SGUP_ODSA(__FUNCTION__, "acquiring lock")
	qMutex.lock();
	//theScan = storedRead;
	//<angle  <distance, timepoint   >>
	*theScan = new rp::RplidarProxy::ScanVecType2();

	if (msecExpiry == 0) {
		//(*theScan)->push_back({ 2.2,3.3 });
		(*theScan)->assign(storedRead.begin(), storedRead.end());
		//theScan.push_back({ 2.2,3.4 });
		storedRead.clear();
	}
	else { //we have an expiry time

		for (auto &x : storedRead) {

			auto born =  x.second.stamp  ;//RP_GET_EXPIRY(x);
			auto lived = std::chrono::duration_cast<std::chrono::milliseconds>(rp::Clock::now() - born).count();

			if (lived > msecExpiry) { //it is old, skip it
				//(**theScan).erase(itr);

				SGUP_ODS(__FUNCTION__, "old ray detected, deleting:", x.first, x.second.distance) //angle/distance
			}
			else
			{
				(*theScan)->push_back(x);

			//	std::next(itr);
			}
		}

		storedRead.clear();
	}
	//theScan = crap;
	//SGUP_ODSA(__FUNCTION__, "BOOBS!", theScan.size());
	qMutex.unlock();
//	SGUP_ODS(__FUNCTION__, "unlocked")

		//try {
	//	boobs.lock();
	//	theScan = storedRead;
	//	boobs.unlock();
	//}
	//catch (std::exception &e)
	//{
	//	SGUP_ODSA(__FUNCTION__, e.what());
	//}

	return;

	OutputDebugStringA(__FUNCTION__ " going to try and get lock");
	auto b = qMutex.try_lock();
	if (!b) {
		OutputDebugStringA(__FUNCTION__ " try and fail lock");
		return;
	}
	else
	{
//		theScan.assign(storedRead.begin(), storedRead.end());
		OutputDebugStringA(__FUNCTION__ " Got lock, unlocking");
		qMutex.unlock();

	}
	//qMutex.lock();

	OutputDebugStringA(__FUNCTION__ " end");
	//SGUP_ODS(__FUNCTION__, "releaseing lock")

}

RplidarReadingQueue::~RplidarReadingQueue()
{

	if (cb)
		delete cb;

	if(drv)
		delete drv;
	//drv->disconnect();
	//drv->DisposeDriver(drv);

//	RPlidarDriver::DisposeDriver(drv);

	drv = nullptr;

}

void RplidarReadingQueue::stop()
{
	SGUP_ODS(__FUNCTION__)
	keepGoing = false;
	scanThread->interrupt();
}

rp::enumLidarStatus RplidarReadingQueue::getLidarStatus()
{
	return lidarStatus;
}

bool RplidarReadingQueue::initLidat()
{
	_u32         baudrateArray[2] = { 115200, 256000 };
	_u32         opt_com_baudrate = 0;
	u_result     op_result;
	using namespace rp::standalone::rplidar;
	keepGoing = true;

//	opt_com_baudrate = baud;
	SGUP_ODSA(__FUNCTION__, "COMPORT RECEIVED:", opt_com_path)

		if (!drv) {
			SGUP_ODS(__FUNCTION__,"attempting to create LIDAR driver on serial port.")
			drv = RPlidarDriver::CreateDriver(DRIVER_TYPE_SERIALPORT);
		}

	if (!drv) {
		SGUP_ODS("insufficent memory, exit");
		return false;
	}

	rplidar_response_device_info_t devinfo;
	bool connectSuccess = false;
	// make connection...

	if (!drv)
		drv = RPlidarDriver::CreateDriver(DRIVER_TYPE_SERIALPORT);
	if (IS_OK(drv->connect(opt_com_path.c_str(), baud)))
	{
		auto op_result = drv->getDeviceInfo(devinfo);

		if (IS_OK(op_result))
		{
			connectSuccess = true;
			SGUP_ODS("connect lidar successful");
		}
		else
		{
			SGUP_ODS("failure to connect lidar.");
			delete drv;
			drv = NULL;

		}
	}

	if (!connectSuccess) {
		SGUP_ODS("Error, cannot bind to the specified serial port", opt_com_path);
		return false;
	}

	SGUP_ODS("Firmware Ver: %d.%02d\n", devinfo.firmware_version >> 8
		, devinfo.firmware_version & 0xFF,
		"Hardware Rev: %d\n", (int)devinfo.hardware_version);

	return true;
}

bool RplidarReadingQueue::run()
{
	//		signal(SIGINT, ctrlc);
	//SGUP_ODS(__FUNCTION__)

	if (!initLidat()) return false;
	SGUP_ODS(__FUNCTION__, "COMPORT RECEIVED:", opt_com_path)

	SGUP_ODS(__FUNCTION__, "initdat worked?")

	drv->startMotor();
	// start scan...
	drv->startScan(0, 1);

	lidarStatus = rp::STARTED;

	char temp[512];
	SGUP_ODS(__FUNCTION__, "keepgoing:", keepGoing);

	// fetech result and print it out...
	while (keepGoing && lidarStatus==rp::STARTED) {
		std::this_thread::sleep_for(std::chrono::milliseconds(1)); //new
		rplidar_response_measurement_node_t nodes[8192];
		size_t   count = _countof(nodes);

		auto op_result = drv->grabScanData(nodes, count);

		if (IS_OK(op_result)) {
			drv->ascendScanData(nodes, count);
			for (int pos = 0; pos < (int)count; ++pos) {

				rp::measure m = (rp::measure&)nodes[pos];
				if (push(m)) {
					//	SGUP_ODS(m.debugPrint());
				}
				else {
					//	SGUP_ODS("REJECT:", m.theta());
				}

			}
		}
		else {
			SGUP_ODS(__FUNCTION__, "error:strange");
		}

		try {
			boost::this_thread::interruption_point();

		}
		catch (...)
		{
			OutputDebugStringA(__FUNCTION__ "interupt!");

			SGUP_ODS(__FUNCTION__, "thread interrupt");

			SGUP_ODS("Stopping scan and motor");

			OutputDebugStringA(__FUNCTION__ "about stop motors");

			drv->stop();
			drv->stopMotor();

			OutputDebugStringA(__FUNCTION__ "motors stopped!");
			lidarStatus = rp::STOPPED;
			break;
		}
	}

}

bool RplidarReadingQueue::run2()
{
	//		signal(SIGINT, ctrlc);
	//SGUP_ODS(__FUNCTION__)

	if (!initLidat()) return false;
	SGUP_ODS(__FUNCTION__, "COMPORT RECEIVED:", opt_com_path)

		SGUP_ODS(__FUNCTION__, "initdat worked?")

		drv->startMotor();
	// start scan...
	drv->startScan(0, 1);

	lidarStatus = rp::STARTED;

	char temp[512];
	SGUP_ODS(__FUNCTION__, "keepgoing:", keepGoing);

	// fetech result and print it out...
	while (keepGoing && lidarStatus == rp::STARTED) {
		std::this_thread::sleep_for(std::chrono::milliseconds(1)); //new
		rplidar_response_measurement_node_hq_t nodes[8192];
		size_t   count = _countof(nodes);

		auto op_result = drv->grabScanDataHq(nodes, count);

		if (IS_OK(op_result)) {
			drv->ascendScanData(nodes, count);
			for (int pos = 0; pos < (int)count; ++pos) {

				rp::measure m = (rp::measure&)nodes[pos];
				if (push(m)) {
				//		SGUP_ODS(m.debugPrint());
				}
				else {
						//SGUP_ODS("REJECT:", m.theta());
				}

			}

		}
		else {
			SGUP_ODS(__FUNCTION__, "error:strange");
		}

		try {
			boost::this_thread::interruption_point();

		}
		catch (...)
		{
			OutputDebugStringA(__FUNCTION__ "interupt!");

			SGUP_ODS(__FUNCTION__, "thread interrupt");

			SGUP_ODS("Stopping scan and motor");

			OutputDebugStringA(__FUNCTION__ "about stop motors");

			drv->stop();
			drv->stopMotor();

			OutputDebugStringA(__FUNCTION__ "motors stopped!");
			lidarStatus = rp::STOPPED;
			break;
		}
	}

}

bool RplidarReadingQueue::runThreaded()
{
	//SGUP_ODS(__FUNCTION__)
	SGUP_ODSA(__FUNCTION__, "COMPORT RECEIVED:", opt_com_path)

		//greg:changed from run() to run2
	scanThread = new boost::thread(std::bind(&RplidarReadingQueue::run2, this));
	return true;
}

void RplidarReadingQueue::join()
{
	scanThread->join();
}

void RplidarReadingQueue::dumpScanToFile(std::string &fname, rp::RplidarProxy::ScanVecType2 * theScan, bool append/*=false*/)
{
	std::fstream of;

	if(append)
		of.open(fname, std::fstream::out | std::fstream::app);
	else
		of.open(fname, std::fstream::out);

	of << "BOOBS" << std::endl;
	rp::point pnt;
	float x, y, z;
	using namespace std;

	for (auto &p : *theScan) {
		pnt=rp::measure::convToCart(p.second.distance, p.first);
		of <<' '<<  p.first << ' ' << p.second.distance <<'\t'<< pnt.x<<' '<<pnt.y<<std::endl;
	}

	of << endl << endl;

}

INIT_SQLBUILDER

auto bind(SQLBuilder  & sb, int const index, int const value)
{
//	ASSERT(handle);
	sqlite3_stmt *ppStmt;
	std::string sql = "insert into sweep(id, angle, distance) VALUES(?1,?2,?3)";

	auto result = sqlite3_prepare_v2(sb.gdb,
		sql.c_str(),
		sql.length(),
		&ppStmt,
		nullptr);

//	auto const result = sqlite3_bind_int(0,
	//	value);

	if (SQLITE_OK != result)
	{
	/*	throw sql_exception
		{
		  result,
		  sqlite3_errmsg(sqlite3_db_handle(handle.get()))
		};*/
	}
}

void RplidarReadingQueue::savePresentScan(int id, std::string & database, rp::RplidarProxy::ScanVecType2 * theScan,
	const std::string & tblName)
{

	//sqlite3_stmt *ppStmt;
	//std::string sql = "insert into sweep(id, angle, distance) VALUES(?1,?2,?3)";

	SGUP_ODSA(__FUNCTION__, "ID:", id);

	//rp::RplidarProxy::ScanVecType * sv;

	SQLBuilder  sb;
	sb.createOrOpenDatabase(database);

	//auto result = sqlite3_prepare_v2(sb.gdb,
	//	sql.c_str(),
	//	sql.length(),
	//	&ppStmt,
	//	nullptr);

	if (theScan == nullptr) { //possibly not spooled up yet?
		SGUP_ODSA(__FUNCTION__, __LINE__, "bad scan nullptr");
		return;
	}

	if (theScan->size() == 0) {
		SGUP_ODSA(__FUNCTION__, __LINE__, "0 size scan");
		return;
	}
	else
	{
		SGUP_ODSA(__FUNCTION__, "size:", theScan->size());
	}

	//else if (theScan->size() == 0)
	//{
	//	SGUP_ODSA(__FUNCTION__, __LINE__, "getScan size 0");
	//	return;
	//}
	//else
	//	SGUP_ODSA(__FUNCTION__, __LINE__, "getScan size:", sv->size());

	std::stringstream ss;
	ss<< "insert into "<<tblName<<"(id, angle, distance, tilt) VALUES \n";

	//insert all this in SQL
	//if (sv != nullptr);
		for (auto &reading : *theScan) {

			auto angle =    reading.first;
			auto dist = reading.second.distance;
			auto tilt = reading.second.tilt	;

			auto s = boost::format("(%1%,%2%,%3%,%4%),") % id %angle %dist %tilt;

		//	SGUP_ODSA(__FUNCTION__,"looping...", s);
			ss << s << std::endl;

		/*	sqlite3_bind_double( ppStmt,1, id);
			sqlite3_bind_double(ppStmt, 2, angle);
			sqlite3_bind_double(ppStmt, 3, dist);

			rc = sqlite3_step(ppStmt)) == SQLITE_ROW*/

		}

		ss.seekp(-2, ss.cur);
		ss << "; ";
	//	REPLACE_LAST_CHAR_ON_SS(ss, ';')

	//	SGUP_ODSA(__FUNCTION__, ss.str());

		auto b=sb.sendSQL(ss.str());

		if (!b)
		{
			SGUP_ODSA(__FUNCTION__, __LINE__, "sendsql failed");
		}

	//end sql

}

bool RplidarReadingQueue::sendSQL(std::string & path, std::shared_ptr<std::string>  &sql)
{
	SQLBuilder  sb;
	sb.createOrOpenDatabase(path);
	std::string temp;

	if (path.empty()) {
		SGUP_ODSA(__FUNCTION__, __LINE__, "database path empty, error");
		return false;
	}

	SGUP_ODSA(__FUNCTION__, __LINE__, "sending sql:",sql);

	auto b = sb.sendSQL(*sql);

	if (!b)
	{
		SGUP_ODSA(__FUNCTION__, __LINE__, "sendsql failed");
		return false;
	}

	//not lets convert the results to a big string and return them in sql
//	sql.clear();
	SGUP_ODSA(__FUNCTION__, "stringify called for:",sql);

	//temp.assign(sb.stringifyResults().c_str());
	//sql->clear();
//	sql->assign(sb.stringifyResults().c_str());
	std::shared_ptr<std::string> thestring(new std::string(sb.stringifyResults()), rp::RplidarProxy::deleter);

	sql = thestring;

	SGUP_ODSA(__FUNCTION__, "stringify returned", *thestring);
	return true;
}

void RplidarReadingQueue::setTiltLidar(float tilt)
{

	//TODO: actuate mechanical action with real tipper
	RplidarReadingQueue::tilt = tilt;

}

//returns the penultimate id after the scan retrieved
int RplidarReadingQueue::getScanFromDatabase(rp::RplidarProxy::ScanVecType2 ** psv, std::string & path,
	std::optional<int> & id, std::optional<std::string> & sweepTableName)
{

	stringstream ss;
	SQLBuilder  sb;
	sb.createOrOpenDatabase(path);

	int last_id = -1;
	std::string theSweepTableName;

	if (sweepTableName) {
		theSweepTableName = *sweepTableName;
	}
	else
		theSweepTableName = "sweep";

	if (id) { //we have passed in a specific id, which is the callers responsability
		last_id = *id;
	}
	else //we want the last
	{

		ss << "select ifnull(max(id),0) from " << theSweepTableName << ";";
		auto b = sb.sendSQL(ss.str());

		if (!b || !sb.results.size())
		{
			SGUP_ODSA(__FUNCTION__, __LINE__, "sendsql error failed or no results");
		}

		last_id=  std::stoi(sb.results[0][0].second);

		SGUP_ODSA(__FUNCTION__, "the last ID is:", last_id);

	}

	ss.str("");

	ss<<"select angle, distance, tilt from "<<theSweepTableName<<" where id=="<< last_id<<";";

	auto b = sb.sendSQL(ss.str());

	if (!b)
	{
		SGUP_ODSA(__FUNCTION__, __LINE__, "sendsql error failed");
	}

	//todo::loop through and fill newly created psv;
	*psv = new rp::RplidarProxy::ScanVecType2;

	if (!sb.results.empty()) {
		for (auto & r : sb.results) {
			(*psv)->push_back(std::pair<float, rp::beam>(std::stof(r[0].second),
				rp::beam(std::stoi(  r[1].second),std::stof( r[2].second))
				)
				);
		}
	}
	else
	{
		SGUP_ODSA(__FUNCTION__, "results empty? Strange...");
	}

	ss.str((boost::format("select DISTINCT id from %1% where id < %2% order by id DESC LIMIT 1") %theSweepTableName % last_id).str().c_str() );

	EXECSQL(sb, ss.str());

	if (!sb.sendSQL(ss.str()))	{
		SGUP_ODSA(__FUNCTION__, __LINE__, "sendsql error failed");
		last_id = -1;
	}
	else
		last_id = std::stoi( sb.results[0][0].second );

	return last_id;

}

int RplidarReadingQueue::saveScanToDatabase(rp::RplidarProxy::ScanVecType2 * psv, std::string & path,
	std::optional<int> & id, std::optional<std::string> & sweepTableName)
{
	stringstream ss;
	SQLBuilder  sb;
	sb.createOrOpenDatabase(path);
	int last=0;

	if (!id){
		auto lid = getLastIDFromSweep(path,sweepTableName);
		last = *lid;
		SGUP_ODSA(__FUNCTION__, "we have an empty id:", last);
	}
	else
	{
		last = *id;
		SGUP_ODSA(__FUNCTION__, "we have an FULL id:", last);
	}

	last++;

	std::string table = sweepTableName ? *sweepTableName : "sweep";

	savePresentScan(last, path, psv,table );

	return last;

}

std::optional<int> RplidarReadingQueue::getLastIDFromSweep(std::string & path, std::optional<std::string> & sweepTableName)
{
	int last_id = -1;

	std::stringstream ss;
	SQLBuilder  sb;
	sb.createOrOpenDatabase(path);

	std::string theSweepTableName;

	if (sweepTableName) {
		theSweepTableName = *sweepTableName;
	}
	else
		theSweepTableName = "sweep";

	ss << "select ifnull(max(id),0) from "<< theSweepTableName <<";";
	auto b = sb.sendSQL(ss.str());

	if (!b || !sb.results.size())
	{
		SGUP_ODSA(__FUNCTION__, __LINE__, "sendsql error failed or no results");
		return std::nullopt;
	}

	last_id = std::stoi(sb.results[0][0].second);

	SGUP_ODSA(__FUNCTION__, "the last ID is:", last_id);
	return std::optional<int>(last_id);

}

const char * rp::measure::debugPrint()
{
	sprintf(temp, "%s theta: %03.2f Dist: %08.2f Q: %d \n",
		(sync_quality & RPLIDAR_RESP_MEASUREMENT_SYNCBIT) ? "S " : "  ",
		(angle_q6_checkbit >> RPLIDAR_RESP_MEASUREMENT_ANGLE_SHIFT) / 64.0f,
		distance_q2 / 4.0f,
		sync_quality >> RPLIDAR_RESP_MEASUREMENT_QUALITY_SHIFT);

	return temp;
}

max_stars_repo_name: codenotes/rplidar

max_issues_repo_name: codenotes/rplidar

max_forks_repo_name: codenotes/rplidar