text:
#include <boost/tuple/tuple.hpp>
#include <string>
#include <iostream>

boost::tuple<std::string, int> func()
{
  return boost::make_tuple("Error message", 2009);
}

int main()
{
  std::string errmsg;
  int errcode;

  boost::tie(errmsg, errcode) = func();
  std::cout << errmsg << ": " << errcode << std::endl;
}

ext: cpp

max_stars_repo_path: Boost/The Boost C++ Libraries/src/14.2.10/main.cpp


text:
#ifndef MOCHIMOCHI_ADAGRAD_RDA_HPP_
#define MOCHIMOCHI_ADAGRAD_RDA_HPP_

#include <Eigen/Dense>
#include "../../functions/enumerate.hpp"

class ADAGRAD_RDA {
private :
  const std::size_t kDim;
  const double kEta;
  const double kLambda;

private :
  std::size_t _timestep;
  Eigen::VectorXd _w;
  Eigen::VectorXd _h;
  Eigen::VectorXd _g;

public :
  ADAGRAD_RDA(const std::size_t dim, const double eta, const double lambda)
    : kDim(dim),
      kEta(eta),
      kLambda(lambda),
      _timestep(0),
      _w(Eigen::VectorXd::Zero(kDim)),
      _h(Eigen::VectorXd::Zero(kDim)),
      _g(Eigen::VectorXd::Zero(kDim)) {
    static_assert(std::numeric_limits<decltype(dim)>::max() > 0, "Dimension Error. (Dimension > 0)");
    static_assert(std::numeric_limits<decltype(eta)>::max() > 0, "Hyper Parameter Error. (eta > 0)");
    static_assert(std::numeric_limits<decltype(lambda)>::max() > 0, "Hyper Parameter Error. (lambda > 0)");
    assert(dim > 0);
    assert(eta > 0);
    assert(lambda > 0);
  }

  virtual ~ADAGRAD_RDA() { }

private :

  double calculate_margin(const Eigen::VectorXd& x) const {
    return _w.dot(x);
  }

  double suffer_loss(const Eigen::VectorXd& x, const int y) const {
    return std::max(0.0, 1.0 - y * _w.dot(x));
  }

public :

  bool update(const Eigen::VectorXd& feature, const int label) {
    if (suffer_loss(feature, label) <= 0.0) { return false; }

    _timestep++;
    functions::enumerate(feature.data(), feature.data() + feature.size(), 0,
                       [&](const int index, const double value) {
                         const auto gradiant = -label * value;
                         _g[index] += gradiant;
                         _h[index] += gradiant * gradiant;

                         const auto sign = _g[index] >= 0 ? 1 : -1;
                         const auto eta = kEta / std::sqrt(_h[index]);
                         const auto u = std::abs(_g[index]) / _timestep;

                         _w[index] = (u <= kLambda) ? 0.0 : -sign * eta * _timestep * (u - kLambda);
                       });
    return true;
  }

  int predict(const Eigen::VectorXd& x) const {
    return calculate_margin(x) > 0.0 ? 1 : -1;
  }

};

#endif //MOCHIMOCHI_ADAGRAD_RDA_HPP_

ext: hpp

max_stars_repo_name: olanleed/MochiMochi

max_issues_repo_name: olanleed/MochiMochi

max_forks_repo_name: olanleed/MochiMochi


text:
#include <geometry.h>
#include <tiny_math_types.h>

#define BOOST_AUTO_TEST_MAIN
#include <boost/test/auto_unit_test.hpp>
#include <boost/test/unit_test_suite.hpp>
#include <boost/test/floating_point_comparison.hpp>
#include <boost/test/test_tools.hpp>

BOOST_AUTO_TEST_SUITE(geometry);

BOOST_AUTO_TEST_CASE(inside_cylinder_test)
{
  typedef tiny::MathTypes<double>   MT;
  typedef MT::vector3_type          V;
  typedef MT::real_type             T;

  V const center = V::make(1.0, 2.0, 4.0);
  V const axis   = V::make(0.0, 0.0, 1.0);
  T const radius = 2.0;
  T const height = 4.0;

  geometry::Cylinder<V> const cylinder = geometry::make_cylinder(radius, height, axis, center);

  BOOST_CHECK(geometry::is_valid(cylinder));

  // on bottom surface
  {
    V    const p    = V::make( 1.0, 2.0, 2.0);
    bool const test = geometry::inside_cylinder( p,  cylinder);
    BOOST_CHECK( test );
  }

  // on top surface
  {
    V    const p    = V::make( 1.0, 2.0, 6.0);
    bool const test = geometry::inside_cylinder( p,  cylinder);
    BOOST_CHECK( test );
  }

  // on cylinder surface
  {
    V    const p    = V::make( 3.0, 2.0, 4.0);
    bool const test = geometry::inside_cylinder( p,  cylinder);
    BOOST_CHECK( test );
  }

  // inside
  {
    V    const p    = V::make( 1.0, 2.0, 2.1);
    bool const test = geometry::inside_cylinder( p,  cylinder);
    BOOST_CHECK( test );
  }

  // inside
  {
    V    const p    = V::make( 1.0, 2.0, 5.9);
    bool const test = geometry::inside_cylinder( p,  cylinder);
    BOOST_CHECK( test );
  }

  // inside
  {
    V    const p    = V::make( 2.9, 2.0, 4.0);
    bool const test = geometry::inside_cylinder( p,  cylinder);
    BOOST_CHECK( test );
  }

  // outside
  {
    V    const p    = V::make( 1.0, 2.0, 1.9);
    bool const test = geometry::inside_cylinder( p,  cylinder);
    BOOST_CHECK( !test );
  }

  // outside
  {
    V    const p    = V::make( 1.0, 2.0, 6.1);
    bool const test = geometry::inside_cylinder( p,  cylinder);
    BOOST_CHECK( !test );
  }

  // outside
  {
    V    const p    = V::make( 3.1, 2.0, 4.0);
    bool const test = geometry::inside_cylinder( p,  cylinder);
    BOOST_CHECK( !test );
  }

}

BOOST_AUTO_TEST_SUITE_END();

max_stars_repo_name: diku-dk/PROX

max_issues_repo_name: erleben/matchstick

max_forks_repo_name: erleben/matchstick


text:
/*
 * Copyright (c) 2019 Opticks Team. All Rights Reserved.
 *
 * This file is part of Opticks
 * (see https://bitbucket.org/simoncblyth/opticks).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <string>
#include <vector>
#include <cstdio>

#ifdef __clang__
#pragma GCC visibility push(default)
#endif

#include <boost/bind.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/program_options.hpp>
#include <boost/tokenizer.hpp>

#ifdef __clang__
#pragma GCC visibility pop
#endif

/*
Listener classes need to provide a methods::

   void configureF(const char* name, std::vector<float> values);
   void configureI(const char* name, std::vector<int> values);
   void configureS(const char* name, std::vector<std::string> values);

which is called whenever the option parsing methods are called.
Typically the last value in the vector should be used to call the Listeners
setter method as selected by the name.
*/
#include "BRAP_API_EXPORT.hh"
#include "BRAP_HEAD.hh"

#ifdef _MSC_VER
// m_vm m_desc m_others m_commandline m_error_message needs dll-interface
#pragma warning( disable : 4251 )
#endif

class BRAP_API BCfg {

public:
     void dumpTree(const char* msg="BCfg::dumpTree");
private:
     void dumpTree_(unsigned int depth=0);

protected:
    boost::program_options::variables_map       m_vm;
    boost::program_options::options_description m_desc ;

    // binding to overloaded methods is problematic : so spell it out

    template <class Listener>
    void addOptionF(Listener* listener, const char* name, const char* description);

    template <class Listener>
    void addOptionI(Listener* listener, const char* name, const char* description);

    template <class Listener>
    void addOptionS(Listener* listener, const char* name, const char* description);

public:
    BCfg(const char* name, bool live);
    bool isLive();
    const char* getName();
    bool hasOpt(const char* opt) const ;

public:
    // holding others
    void add(BCfg* cfg);
    bool containsOthers();
    unsigned int getNumOthers();
    BCfg* getOther(unsigned int index);
    BCfg* findOther(const char* name);
    BCfg* operator [](const char* name);

public:
    void setVerbose(bool verbose=true);
    boost::program_options::options_description& getDesc();
    std::string getDescString();

    const std::string& getCommandLine();
    virtual void commandline(int argc, char** argv);
    void liveline(const char* line);
    void configfile(const char* path);

    std::vector<std::string> parse_commandline(int argc, char** argv, bool verbose=false);
    std::vector<std::string> parse_configfile(const char* path);
    std::vector<std::string> parse_liveline(const char* line);
    std::vector<std::string> parse_tokens(std::vector<std::string>& tokens);

    virtual void dump(const char* msg);

    static void dump(std::vector<std::string>& ss, const char* msg );
    static void dump(boost::program_options::options_description& desc, const char* msg);
    static void dump(boost::program_options::variables_map&       vm, const char* msg);
    static void dump(boost::program_options::parsed_options& opts, const char* msg );

    bool hasError();
    std::string getErrorMessage();
private:
    const char*       m_name ;
    std::vector<BCfg*> m_others ;
    std::string       m_commandline ;
    bool              m_live ;
    bool              m_error ;
    std::string       m_error_message ;
    bool              m_verbose ;

};

template <class Listener>
inline void BCfg::addOptionF(Listener* listener, const char* name, const char* description )
{
        m_desc.add_options()(name,
                             boost::program_options::value<std::vector<float> >()
                                ->composing()
                                ->notifier(boost::bind(&Listener::configureF, listener, name, _1)),
                             description) ;
}

template <class Listener>
inline void BCfg::addOptionI(Listener* listener, const char* name, const char* description )
{
        m_desc.add_options()(name,
                             boost::program_options::value<std::vector<int> >()
                                ->composing()
                                ->notifier(boost::bind(&Listener::configureI, listener, name, _1)),
                             description) ;
}

template <class Listener>
inline void BCfg::addOptionS(Listener* listener, const char* name, const char* description )
{
        if(m_verbose)
        {
             printf("BCfg::addOptionS %s %s \n", name, description);
        }
        m_desc.add_options()(name,
                             boost::program_options::value<std::vector<std::string> >()
                                ->composing()
                                ->notifier(boost::bind(&Listener::configureS, listener, name, _1)),
                             description) ;
}

#include "BRAP_TAIL.hh"

ext: hh

max_stars_repo_name: seriksen/opticks

max_issues_repo_name: seriksen/opticks

max_forks_repo_name: seriksen/opticks


text:
/*    Copyright (c) 2010-2015, Delft University of Technology
 *    All rights reserved.
 *
 *    Redistribution and use in source and binary forms, with or without modification, are
 *    permitted provided that the following conditions are met:
 *      - Redistributions of source code must retain the above copyright notice, this list of
 *        conditions and the following disclaimer.
 *      - Redistributions in binary form must reproduce the above copyright notice, this list of
 *        conditions and the following disclaimer in the documentation and/or other materials
 *        provided with the distribution.
 *      - Neither the name of the Delft University of Technology nor the names of its contributors
 *        may be used to endorse or promote products derived from this software without specific
 *        prior written permission.
 *
 *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
 *    OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 *    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *    COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 *    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 *    GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 *    AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 *    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 *    OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *    Changelog
 *      YYMMDD    Author            Comment
 *      110208    D. Dirkx          First version of file.
 *      110210    L. Adulkadir      Code check.
 *      110211    K. Kumar          Corrected Doxygen errors; corrected layout errors; corrected
 *                                  double precision; updated function-naming.
 *      120605    J. Vandamme       Boostified unit test.
 *      120912    K. Kumar          Removed erroneous using-statements; added missing <cmath>
 *                                  include.
 *
 *    References
 *      Anderson Jr., J.D. , Fundamentals of Aerodynamics, 3rd edition, McGraw Hill, 2001.
 *      Anderson Jr. , J.D, Hypersonic and High-Temperature Gas Dynamics, 2nd edition,
 *          AIAA Education Series, 2006.
 *
 *    Notes
 *
 */

#define BOOST_TEST_MAIN

#include <cmath>

#include <boost/test/floating_point_comparison.hpp>
#include <boost/test/unit_test.hpp>

#include "Tudat/Mathematics/BasicMathematics/mathematicalConstants.h"

#include "Tudat/Astrodynamics/Aerodynamics/aerodynamics.h"

namespace tudat
{
namespace unit_tests
{

BOOST_AUTO_TEST_SUITE( test_aerodynamics_namespace )

//! Test aerodynamic namespace pressure functions.
BOOST_AUTO_TEST_CASE( testAerodynamicNamespacePressureFunctions )
{
    using namespace tudat;
    using namespace aerodynamics;
    using mathematical_constants::PI;

    // Set default test conditions.
    const double machNumber_ = 12.0;
    const double ratioOfSpecificHeats_ = 1.4;

    // Test local to static pressure ratio.
    const double localToStaticPressureRatio_ = computeLocalToStaticPressureRatio(
           machNumber_, ratioOfSpecificHeats_ );

    const double expectedLocalToStaticPressureRatio_ = 1.0 / 0.1445e6;
    const double toleranceRatioCoefficient_ = 0.1445e6 * 1.0e-8 * 100.0
            / expectedLocalToStaticPressureRatio_;

    // Check if computed local-to-static pressure ratio matches expected value.
    BOOST_CHECK_CLOSE_FRACTION( localToStaticPressureRatio_,
                                expectedLocalToStaticPressureRatio_,
                                toleranceRatioCoefficient_ );

    // Test stagnation pressure coefficient.
    const double stagnationPressureCoefficient_
            = computeStagnationPressure( machNumber_, ratioOfSpecificHeats_ );

    const double expectedStagnationPressureCoefficient_ = 1.83402;
    const double toleranceStagnationPressureCoefficient_ = 1.0e-5 * 100.0
            / expectedStagnationPressureCoefficient_;

    // Check if computed stagnation pressure coefficient matches expected value.
    BOOST_CHECK_CLOSE_FRACTION( stagnationPressureCoefficient_,
                                expectedStagnationPressureCoefficient_,
                                toleranceStagnationPressureCoefficient_ );

    // Test modified Newtonian pressure coefficient.
    const double newtonianPressureCoefficient_ = computeModifiedNewtonianPressureCoefficient(
                PI / 2.0, stagnationPressureCoefficient_ );

    const double expectedNewtonianPressureCoefficient_ = stagnationPressureCoefficient_;
    const double toleranceNewtonianPressureCoefficient_ = 1.0e-15 * 100.0
            / expectedNewtonianPressureCoefficient_;

    // Check if computed Newtonian pressure coefficient matches expected value.
    BOOST_CHECK_CLOSE_FRACTION( newtonianPressureCoefficient_,
                                expectedNewtonianPressureCoefficient_,
                                toleranceNewtonianPressureCoefficient_ );

    // Test empirical tangent cone pressure coefficient.
    const double empiricalTangentConePressureCoefficient_
            = computeEmpiricalTangentConePressureCoefficient( PI / 2.0, machNumber_ );

    const double expectedEmpiricalTangentConePressureCoefficient_ = 2.08961;
    const double toleranceEmpiricalTangentConePressureCoefficient_ = 1.0e-5 * 100.0
            / expectedEmpiricalTangentConePressureCoefficient_;

    // Check if computed empirical tangent cone pressure coefficient matches expected value.
    BOOST_CHECK_CLOSE_FRACTION( empiricalTangentConePressureCoefficient_,
                                expectedEmpiricalTangentConePressureCoefficient_,
                                toleranceEmpiricalTangentConePressureCoefficient_ );

    // Test high Mach base pressure coefficient.
    const double highMachBasePressure_ = computeHighMachBasePressure( machNumber_ );

    const double expectedHighMachBasePressure_ = -1.0 / ( machNumber_ * machNumber_ );
    const double toleranceHighMachBasePressure_ = std::fabs( 1.0e-15 * 100.0 / expectedHighMachBasePressure_ );

    // Check if computed high Mach base pressure coefficient matches expected value.
    BOOST_CHECK_CLOSE_FRACTION( highMachBasePressure_,
                                expectedHighMachBasePressure_,
                                toleranceHighMachBasePressure_ );

    // Test empirical tangent wedge pressure coefficient.
    const double empiricalTangentWedgePressureCoefficient_
            = computeEmpiricalTangentWedgePressureCoefficient( PI / 2.0, machNumber_ );

    const double expectedEmpiricalTangentWedgePressureCoefficient_ = 2.38867;
    const double toleranceEmpiricalTangentWedgePressureCoefficient_ = 1.0e-5 * 100.0
            / expectedEmpiricalTangentWedgePressureCoefficient_;

    // Check if computed tangent wedge pressure coefficient matches expected value.
    BOOST_CHECK_CLOSE_FRACTION( empiricalTangentWedgePressureCoefficient_,
                                expectedEmpiricalTangentWedgePressureCoefficient_,
                                toleranceEmpiricalTangentWedgePressureCoefficient_ );

    // Test free-stream Prandtl-Meyer function.
    const double freestreamPrandtlMeyerFunction_ = computePrandtlMeyerFunction(
           machNumber_, ratioOfSpecificHeats_ );

    const double expectedFreeStreamPrandtlMeyerFunction_ = 106.9 * PI / 180.0;
    const double toleranceFreeStreamPrandtlMeyerFunction_ = 1.0e-3 * 100.0
            / expectedFreeStreamPrandtlMeyerFunction_;

    // Check if computed free-stream Prandtl-Meyer function matches expected value.
    BOOST_CHECK_CLOSE_FRACTION( freestreamPrandtlMeyerFunction_,
                                expectedFreeStreamPrandtlMeyerFunction_,
                                toleranceFreeStreamPrandtlMeyerFunction_ );

    // Test vacuum pressure coefficient function.
    const double vacuumPressureCoefficient_ = computeVacuumPressureCoefficient(
           machNumber_, ratioOfSpecificHeats_ );

    const double expectedVacuumPressureCoefficient_ = -2.0 / ( ratioOfSpecificHeats_
                                                               * machNumber_ * machNumber_ );
    const double toleranceVacuumPressureCoefficient_ = std::fabs( 1.0e-15 * 100.0
            / expectedVacuumPressureCoefficient_ );

    // Check if computed vacuum pressure coefficient matches expected value.
    BOOST_CHECK_CLOSE_FRACTION( vacuumPressureCoefficient_,
                                expectedVacuumPressureCoefficient_,
                                toleranceVacuumPressureCoefficient_ );
}

//! Test pressure coefficients.
BOOST_AUTO_TEST_CASE( testPressureCoefficients )
{
    using std::sin;
    using namespace tudat;
    using namespace aerodynamics;
    using mathematical_constants::PI;

    // Set default conditions.
    const double machNumber_ = 12.0;
    const double ratioOfSpecificHeats_ = 1.4;

    // Iterate over 10 angles and test pressure coefficients.
    for ( int i = 0; i < 10; i++ )
    {
         // Set angle.
         const double angle_ = static_cast< double > ( i ) * PI / 10.0;

         // Compute and compare Newtonian pressure coefficient.
         const double newtonianPressureCoefficient_
                 = computeNewtonianPressureCoefficient( angle_ );

         const double expectedNewtonianPressureCoefficient_ =  2.0 * sin( angle_ ) * sin( angle_ );
         const double toleranceNewtonianPressureCoefficient_ = 1.0e-15 * 100.0
                 / expectedNewtonianPressureCoefficient_;

         // Check if computed Newtonian pressure coefficient matches expected value.
         BOOST_CHECK_CLOSE_FRACTION( newtonianPressureCoefficient_,
                                     expectedNewtonianPressureCoefficient_,
                                     toleranceNewtonianPressureCoefficient_ );

         // Compute Prandtl-Meyer pressure coefficient and test if it is not
         // lower than vacuum pressure coefficient.
         const double freestreamPrandtlMeyerFunction_ = computePrandtlMeyerFunction(
                     machNumber_, ratioOfSpecificHeats_ );

         const double prandtlMeyerPressureCoefficient_ =
                 computePrandtlMeyerFreestreamPressureCoefficient(
                     -1.0 * angle_, machNumber_, ratioOfSpecificHeats_,
                     freestreamPrandtlMeyerFunction_ );

         const double vacuumPressureCoefficient_ = computeVacuumPressureCoefficient(
                     machNumber_, ratioOfSpecificHeats_ );

         bool isPrandtlMeyerPressureCoefficient = false;

         if ( vacuumPressureCoefficient_ < prandtlMeyerPressureCoefficient_ + 1.0e-15 )
         {
             isPrandtlMeyerPressureCoefficient = true;
         }

         // Check if Prandt-Meyer pressure coefficient is lower than vacuum pressure coefficient.
         BOOST_CHECK( isPrandtlMeyerPressureCoefficient );

         // Test shock pressure ratio.
         const double shockPressureRatio_ = computeShockPressureRatio( machNumber_,
                                                                       ratioOfSpecificHeats_ );

         const double expectedShockPressureRatio_ = 167.8;
         const double toleranceShockPressureRatio_ = 0.1 * 100.0 / expectedShockPressureRatio_;

         // Check if computed shock pressure ratio matches expected value.
         BOOST_CHECK_CLOSE_FRACTION( shockPressureRatio_,
                                     expectedShockPressureRatio_,
                                     toleranceShockPressureRatio_ );

         // Test shock density ratio.
         const double shockDensityRatio_ = computeShockDensityRatio( machNumber_,
                                                                     ratioOfSpecificHeats_ );

         const double expectedShockDensityRatio_ = 5.799;
         const double toleranceShockDensityRatio_ = 0.001 * 100 / expectedShockDensityRatio_;

         // Check if computed shock density ratio matches expected value.
         BOOST_CHECK_CLOSE_FRACTION( shockDensityRatio_,
                                     expectedShockDensityRatio_,
                                     toleranceShockDensityRatio_ );

         // Test shock temperature ratio.
         const double shockTemperatureRatio_ = computeShockTemperatureRatio(
                     machNumber_, ratioOfSpecificHeats_ );

         const double expectedShockTemperatureRatio_ = 28.94;
         const double toleranceShockTemperatureRatio_ = 0.01 * 100.0
                 / expectedShockTemperatureRatio_;

         // Check if shock temperature ratio matches expected value.
         BOOST_CHECK_CLOSE_FRACTION( shockTemperatureRatio_,
                                     expectedShockTemperatureRatio_,
                                     toleranceShockTemperatureRatio_ );

         // Test shock total pressure ratio.
         const double shockTotalPressureRatio_ = computeShockTotalPressureRatio(
                     machNumber_, ratioOfSpecificHeats_, 287.058 );

         const double expectedShockTotalPressureRatio_ = 0.001287;
         const double toleranceShockTotalPressureRatio_ = 1.0e-6 *100.0
                 / expectedShockTotalPressureRatio_;

         // Check if shock total pressure ratio matches expected value.
         BOOST_CHECK_CLOSE_FRACTION( shockTotalPressureRatio_,
                                     expectedShockTotalPressureRatio_,
                                     toleranceShockTotalPressureRatio_ );
    }
}

BOOST_AUTO_TEST_SUITE_END( )

} // namespace unit_tests
} // namespace tudat

max_stars_repo_name: JPelamatti/ThesisTUDAT

max_issues_repo_name: JPelamatti/ThesisTUDAT

max_forks_repo_name: JPelamatti/ThesisTUDAT


text:
#include "RTSystemExtItem.h"
#include "RTSCommonUtilExt.h"
#include "ProfileHandlerExt.h"
#include <cnoid/MessageView>
#include <cnoid/ItemManager>
#include <cnoid/Archive>
#include <cnoid/EigenArchive>
#include <cnoid/AppConfig>
#include <cnoid/Timer>
#include <boost/format.hpp>
#include "LoggerUtil.h"

#include "gettext.h"

using namespace cnoid;
using namespace std;
using namespace std::placeholders;
using namespace RTC;
using boost::format;

namespace cnoid {

struct RTSPortComparator
{
    std::string name_;

    RTSPortComparator(std::string value)
    {
        name_ = value;
    }
    bool operator()(const RTSPortExtPtr elem) const
    {
        return (name_ == elem->name);
    }
};
//////////
class RTSystemExtItemImpl
{
public:
    map<string, RTSCompExtPtr> rtsComps;
    RTSystemExtItem::RTSConnectionMap rtsConnections;
    bool autoConnection;

    std::string vendorName;
    std::string version;
    int pollingCycle;
    bool checkAtLoading;

#if defined(OPENRTM_VERSION12)
    int heartBeatPeriod;
#endif

    enum State_Detection
    {
        POLLING_CHECK = 0,
        MANUAL_CHECK,
#if defined(OPENRTM_VERSION12)
        OBSERVER_CHECK,
#endif
        N_STATE_DETECTION
    };
    Selection stateCheck;

    RTSystemExtItemImpl(RTSystemExtItem* self);
    RTSystemExtItemImpl(RTSystemExtItem* self, const RTSystemExtItemImpl& org);
    ~RTSystemExtItemImpl();

    void initialize();
    void onLocationChanged(std::string host, int port);
    RTSCompExt* addRTSComp(const string& name, const QPointF& pos);
    RTSCompExt* addRTSComp(const NamingContextHelper::ObjectInfo& info, const QPointF& pos);
    void deleteRTSComp(const string& name);
    RTSCompExt* nameToRTSComp(const string& name);
    bool compIsAlive(RTSCompExt* rtsComp);
    RTSConnectionExt* addRTSConnection(
        const string& id, const string& name,
        RTSPortExt* sourcePort, RTSPortExt* targetPort, const std::vector<NamedValueExtPtr>& propList,
        const bool setPos, const Vector2 pos[]);
    RTSConnectionExt* addRTSConnectionName(
        const string& id, const string& name,
        const string& sourceComp, const string& sourcePort,
        const string& targetComp, const string& targetPort,
        const string& dataflow, const string& subscription,
        const bool setPos, const Vector2 pos[]);
    bool connectionCheck();
    void RTSCompToConnectionList(const RTSCompExt* rtsComp, list<RTSConnectionExt*>& rtsConnectionList, int mode);
    void removeConnection(RTSConnectionExt* connection);
    void doPutProperties(PutPropertyFunction& putProperty);
    bool saveRtsProfile(const string& filename);
    void restoreRTSystem(const Archive& archive);
    void restoreRTSComp(const string& name, const Vector2& pos,
            const vector<pair<string, bool>>& inPorts, const vector<pair<string, bool>>& outPorts);
    string getConnectionNumber();
    void setStateCheckMethodByString(const string& value);
    void checkStatus();

    Signal<void(bool)> sigLoaded;
    Signal<void(bool)> sigStatusUpdate;

    void onActivated();
    void changePollingPeriod(int value);
    void changeStateCheck();

private:
    RTSystemExtItem* self;
    Connection locationChangedConnection;
    int connectionNo;

    Timer timer;
    ScopedConnection timeOutConnection;

    void setStateCheckMethod(int value);
};

}
//////////
RTSPortExt::RTSPortExt(const string& name_, PortService_var port_, RTSCompExt* parent)
    : rtsComp(parent), isConnected_(false)
{
    isInPort = true;
    name = name_;
    port = port_;
    //
    if (port) {
        RTC::PortProfile_var profile = port->get_port_profile();
        RTC::PortInterfaceProfileList interfaceList = profile->interfaces;
        for (CORBA::ULong index = 0; index < interfaceList.length(); ++index) {
            RTC::PortInterfaceProfile ifProfile = interfaceList[index];
            PortInterfaceExtPtr portIf(new PortInterfaceExt());
            if (parent) {
                portIf->rtc_name = parent->name;
            }
            const char* port_name;
            portIf->port_name = string((const char*)profile->name);
            if (ifProfile.polarity == PortInterfacePolarity::REQUIRED) {
                portIf->if_polarity = "required";
            } else {
                portIf->if_polarity = "provided";
            }
            const char* if_iname;
            const char* if_tname;
            if_iname = (const char*)ifProfile.instance_name;
            if_tname = (const char*)ifProfile.type_name;
            DDEBUG_V("name: %s, IF name: %s, instance_name: %s, type_name: %s", name_.c_str(), portIf->port_name.c_str(), if_iname, if_tname);
            portIf->if_tname = if_tname;
            portIf->if_iname = if_iname;
            interList.push_back(portIf);

            isConnected_ = isConnected();
        }
    }
}

bool RTSPortExt::isConnected()
{
    if (!port || !isObjectAlive(port)) {
        return false;
    }
    ConnectorProfileList_var connectorProfiles = port->get_connector_profiles();
    return connectorProfiles->length() != 0;
}

bool RTSPortExt::isConnectedWith(RTSPortExt* target)
{
    if (!port || !target->port ||
       CORBA::is_nil(port) || port->_non_existent() ||
       CORBA::is_nil(target->port) || target->port->_non_existent()) {
        return false;
    }

    ConnectorProfileList_var connectorProfiles = port->get_connector_profiles();

    for (CORBA::ULong i = 0; i < connectorProfiles->length(); ++i) {
        ConnectorProfile& connectorProfile = connectorProfiles[i];
        PortServiceList& connectedPorts = connectorProfile.ports;
        for (CORBA::ULong j = 0; j < connectedPorts.length(); ++j) {
            PortService_ptr connectedPortRef = connectedPorts[j];
            if (connectedPortRef->_is_equivalent(target->port)) {
                return true;
            }
        }
    }

    return false;
}

bool RTSPortExt::checkConnectablePort(RTSPortExt* target)
{
    DDEBUG("RTSPort::checkConnectablePort");
    if (rtsComp == target->rtsComp) {
        return false;
    }
    if (!port || !target->port) {
        return false;
    }

    if ((isInPort && target->isInPort) ||
        (isInPort && target->isServicePort) ||
        (!isInPort && !isServicePort && !target->isInPort) ||
        (isServicePort && !target->isServicePort)) {
        return false;
    }

    //In case of connection between data ports
    if (!isServicePort && !target->isServicePort) {
        vector<string> dataTypes = RTCCommonUtilExt::getAllowDataTypes(this, target);
        vector<string> ifTypes = RTCCommonUtilExt::getAllowInterfaceTypes(this, target);
        vector<string> subTypes = RTCCommonUtilExt::getAllowSubscriptionTypes(this, target);
        if (dataTypes.size() == 0 || ifTypes.size() == 0 || subTypes.size() == 0) {
            return false;
        }
    }

    return true;
}

vector<string> RTSPortExt::getDataTypes()
{
    return getProperty("dataport.data_type");
}

vector<string> RTSPortExt::getInterfaceTypes()
{
    return getProperty("dataport.interface_type");
}

vector<string> RTSPortExt::getDataflowTypes()
{
    return getProperty("dataport.dataflow_type");
}

vector<string> RTSPortExt::getSubscriptionTypes()
{
    return getProperty("dataport.subscription_type");
}

vector<string> RTSPortExt::getProperty(const string& key)
{
    vector<string> result;

    NVList properties = port->get_port_profile()->properties;
    for (int index = 0; index < properties.length(); ++index) {
        string strName(properties[index].name._ptr);
        if (strName == key) {
            const char* nvValue;
            properties[index].value >>= nvValue;
            string strValue(nvValue);
            result = RTCCommonUtil::split(strValue, ',');
            break;
        }
    }

    return result;
}

RTSPortExt* RTSCompExt::nameToRTSPort(const string& name)
{
    //DDEBUG_V("RTSComp::nameToRTSPort %s", name.c_str());

    auto it = find_if(inPorts.begin(), inPorts.end(), RTSPortComparator(name));
    if (it != inPorts.end()) {
        return *it;
    }
    it = find_if(outPorts.begin(), outPorts.end(), RTSPortComparator(name));
    if (it != outPorts.end()) {
        return *it;
    }
    return nullptr;
}
//////////
RTSConnectionExt::RTSConnectionExt(const string& id, const string& name,
        const string& sourceRtcName, const string& sourcePortName,
        const string& targetRtcName, const string& targetPortName)
    : id(id), name(name), sourceRtcName(sourceRtcName), sourcePortName(sourcePortName),
    targetRtcName(targetRtcName), targetPortName(targetPortName), setPos(false)
{
    isAlive_ = false;
}

bool RTSConnectionExt::connect()
{
    DDEBUG("RTSConnection::connect");

    if (!sourcePort || !targetPort) {
        return false;
    }

    if (!sourcePort->port || !targetPort->port ||
       CORBA::is_nil(sourcePort->port) || sourcePort->port->_non_existent() ||
       CORBA::is_nil(targetPort->port) || targetPort->port->_non_existent()) {
        DDEBUG("RTSConnection::connect False");
        return false;
    }

    if (sourcePort->isConnectedWith(targetPort)) {
        return false;
    }

    ConnectorProfile cprof;
    cprof.connector_id = CORBA::string_dup(id.c_str());
    cprof.name = CORBA::string_dup(name.c_str());
    cprof.ports.length(2);
    cprof.ports[0] = PortService::_duplicate(sourcePort->port);
    cprof.ports[1] = PortService::_duplicate(targetPort->port);

    for (int index = 0; index < propList.size(); index++) {
        NamedValueExtPtr param = propList[index];
        CORBA_SeqUtil::push_back(
            cprof.properties, NVUtil::newNV(param->name_.c_str(), param->value_.c_str()));
    }

    RTC::ReturnCode_t result = sourcePort->port->connect(cprof);
    if (result == RTC::RTC_OK) {
        PortProfile_var portprofile = sourcePort->port->get_port_profile();
        ConnectorProfileList connections = portprofile->connector_profiles;
        for (CORBA::ULong i = 0; i < connections.length(); i++) {
            ConnectorProfile& connector = connections[i];
            PortServiceList& connectedPorts = connector.ports;
            for (CORBA::ULong j = 0; j < connectedPorts.length(); ++j) {
                PortService_ptr connectedPortRef = connectedPorts[j];
                if (connectedPortRef->_is_equivalent(targetPort->port)) {
                    id = string(connector.connector_id);
                    isAlive_ = true;
                    DDEBUG("RTSConnection::connect End");
                    return true;
                }
            }
        }
        return false;
    }

    DDEBUG("connect Error");
    return false;
}

bool RTSConnectionExt::disconnect()
{
    isAlive_ = false;

    if (CORBA::is_nil(sourcePort->port) || sourcePort->port->_non_existent()) {
        return false;
    }

    return (sourcePort->port->disconnect(id.c_str()) == RTC_OK);
}

void RTSConnectionExt::setPosition(const Vector2 pos[])
{
    for (int i = 0; i < 6; ++i) {
        position[i] = pos[i];
    }
    setPos = true;
    srcRTC->rts()->suggestFileUpdate();
}
//////////
RTSCompExt::RTSCompExt(const string& name, const std::string& fullPath, RTC::RTObject_ptr rtc, RTSystemExtItem* rts, const QPointF& pos, const string& host, int port)
    : rts_(rts), pos_(pos), name(name), fullPath(fullPath), hostAddress(host), portNo(port)
{
    setRtc(rtc);
}

void RTSCompExt::setRtc(RTObject_ptr rtc)
{
    DDEBUG("RTSComp::setRtc");
    rtc_ = 0;

    rts_->suggestFileUpdate();

    setRTObject(rtc);

    if (!isObjectAlive(rtc)) {
        participatingExeContList = 0;
        for (auto it = inPorts.begin(); it != inPorts.end(); ++it) {
            RTSPortExt* port = *it;
            port->port = 0;
        }
        for (auto it = outPorts.begin(); it != outPorts.end(); ++it) {
            RTSPortExt* port = *it;
            port->port = 0;
        }
        DDEBUG("RTSComp::setRtc Failed");
        return;
    }

    ComponentProfile_var cprofile = rtc_->get_component_profile();
    participatingExeContList = rtc_->get_participating_contexts();
    rtc_status_ = getRTCState();

    inPorts.clear();
    outPorts.clear();

    PortServiceList_var portlist = rtc_->get_ports();
    for (CORBA::ULong i = 0; i < portlist->length(); ++i) {
        PortProfile_var portprofile = portlist[i]->get_port_profile();
        coil::Properties pproperties = NVUtil::toProperties(portprofile->properties);
        string portType = pproperties["port.port_type"];
        RTSPortExtPtr rtsPort = new RTSPortExt(string(portprofile->name), portlist[i], this);
        if (RTCCommonUtil::compareIgnoreCase(portType, "CorbaPort")) {
            rtsPort->isServicePort = true;
            rtsPort->isInPort = false;
            outPorts.push_back(rtsPort);
        } else {
            rtsPort->isServicePort = false;
            if (RTCCommonUtil::compareIgnoreCase(portType, "DataInPort")) {
                inPorts.push_back(rtsPort);
            } else {
                rtsPort->isInPort = false;
                outPorts.push_back(rtsPort);
            }
        }
    }

    list<RTSConnectionExt*> rtsConnectionList;
    rts_->impl->RTSCompToConnectionList(this, rtsConnectionList, 0);
    for (auto it = rtsConnectionList.begin(); it != rtsConnectionList.end(); ++it) {
        RTSConnectionExtPtr connection = (*it);
        rts_->impl->removeConnection(*it);
        RTSPortExt* sourcePort = connection->srcRTC->nameToRTSPort(connection->sourcePortName);
        RTSPortExt* targetPort = connection->targetRTC->nameToRTSPort(connection->targetPortName);
        if (sourcePort && targetPort) {
            connection->sourcePort = sourcePort;
            connection->targetPort = targetPort;
            rts_->impl->rtsConnections[RTSystemExtItem::RTSPortPair(sourcePort, targetPort)] = connection;
        }
    }

    connectionCheck();
    DDEBUG("RTSComp::setRtc End");
}

bool RTSCompExt::connectionCheck()
{
    //DDEBUG("RTSComp::connectionCheck");

    bool updated = false;

    for (auto it = inPorts.begin(); it != inPorts.end(); ++it) {
        if (connectionCheckSub(*it)) {
            updated = true;
        }
        bool isCon = (*it)->isConnected();
        if( (*it)->isConnected_ != isCon) {
            updated = true;
            (*it)->isConnected_ = isCon;
        }
    }
    for (auto it = outPorts.begin(); it != outPorts.end(); it++) {
        if (connectionCheckSub(*it)) {
            updated = true;
        }
        bool isCon = (*it)->isConnected();
        if( (*it)->isConnected_ != isCon) {
            updated = true;
            (*it)->isConnected_ = isCon;
        }
    }

    return updated;
}

bool RTSCompExt::connectionCheckSub(RTSPortExt* rtsPort)
{
    bool updated = false;

    if (isObjectAlive(rtsPort->port) == false) return updated;

    /**
       The get_port_profile() function should not be used here because
       it takes much time when the port has large data and its owner RTC is in a remote host.
       The get_connector_profiles() function does not seem to cause such a problem.
    */
    ConnectorProfileList_var connectorProfiles = rtsPort->port->get_connector_profiles();

    for (CORBA::ULong i = 0; i < connectorProfiles->length(); ++i) {
        ConnectorProfile& connectorProfile = connectorProfiles[i];
        PortServiceList& connectedPorts = connectorProfile.ports;
        for (CORBA::ULong j = 0; j < connectedPorts.length(); ++j) {
            PortService_var connectedPortRef = connectedPorts[j];
            if(CORBA::is_nil(connectedPortRef)){
                continue;
            }
            PortProfile_var connectedPortProfile;
            try {
                connectedPortProfile = connectedPortRef->get_port_profile();
            }
            catch (CORBA::SystemException& ex) {
                MessageView::instance()->putln(
                    MessageView::WARNING, format(_("CORBA %1% (%2%), %3% in RTSComp::connectionCheckSub()"))
                    % ex._name() % ex._rep_id() % ex.NP_minorString());
                continue;
            }
            string portName = string(connectedPortProfile->name);
            vector<string> target;
            RTCCommonUtil::splitPortName(portName, target);
            if (target[0] == name) continue;

            string rtcPath;
            if(!getComponentPath(connectedPortRef, rtcPath)){
                continue;
            }
            RTSCompExt* targetRTC = rts_->impl->nameToRTSComp("/" + rtcPath);
            if(!targetRTC){
                continue;
            }

            //DDEBUG("targetRTC Found");
            RTSPortExt* targetPort = targetRTC->nameToRTSPort(portName);
            if (targetPort) {
                auto itr = rts_->impl->rtsConnections.find(RTSystemExtItem::RTSPortPair(rtsPort, targetPort));
                if (itr != rts_->impl->rtsConnections.end()) {
                    continue;
                }
                RTSConnectionExtPtr rtsConnection = new RTSConnectionExt(
                    string(connectorProfile.connector_id), string(connectorProfile.name),
                    name, rtsPort->name,
                    target[0], portName);
                coil::Properties properties = NVUtil::toProperties(connectorProfile.properties);
                vector<NamedValueExtPtr> propList;
                NamedValueExtPtr dataType(new NamedValueExt("dataport.dataflow_type", properties["dataport.dataflow_type"]));
                propList.push_back(dataType);
                NamedValueExtPtr subscription(new NamedValueExt("dataport.subscription_type", properties["dataport.subscription_type"]));
                rtsConnection->propList = propList;

                rtsConnection->srcRTC = this;
                rtsConnection->sourcePort = nameToRTSPort(rtsConnection->sourcePortName);
                rtsConnection->targetRTC = targetRTC;
                rtsConnection->targetPort = targetRTC->nameToRTSPort(rtsConnection->targetPortName);
                rtsConnection->isAlive_ = true;
                rts_->impl->rtsConnections[RTSystemExtItem::RTSPortPair(rtsPort, targetPort)] = rtsConnection;

                rts_->suggestFileUpdate();

                updated = true;
            }
        }
    }

    return updated;
}

bool RTSCompExt::getComponentPath(RTC::PortService_ptr source, std::string& out_path)
{
    PortProfile_var portprofile = source->get_port_profile();
    if(!CORBA::is_nil(portprofile->owner)){
        ComponentProfile_var cprofile;
        try {
            cprofile = portprofile->owner->get_component_profile();
        }
        catch (CORBA::SystemException& ex) {
            MessageView::instance()->putln(
                MessageView::WARNING, format(_("CORBA %1% (%2%), %3% in RTSComp::getComponentPath()"))
                % ex._name() % ex._rep_id() % ex.NP_minorString());
            return false;
        }
        NVList properties = cprofile->properties;
        for(int index = 0; index < properties.length(); ++index){
            string strName(properties[index].name._ptr);
            if(strName == "naming.names"){
                const char* nvValue;
                properties[index].value >>= nvValue;
                out_path = string(nvValue);
                return true;
            }
        }
    }
    return false;
}

void RTSCompExt::moveToRelative(const QPointF& p)
{
    QPointF newPos = pos_ + p;
    if (newPos != pos_) {
        pos_ = newPos;
        rts_->suggestFileUpdate();
    }
}
//////////
void RTSystemExtItem::initializeClass(ExtensionManager* ext)
{
    DDEBUG("RTSystemItem::initializeClass");
    ItemManager& im = ext->itemManager();
    im.registerClass<RTSystemExtItem>(N_("RTSystemItem"));
    im.addCreationPanel<RTSystemExtItem>();
    im.addLoaderAndSaver<RTSystemExtItem>(
        _("RT-System"), "RTS-PROFILE-XML", "xml",
        [](RTSystemExtItem* item, const std::string& filename, std::ostream&, Item*) {
        return item->loadRtsProfile(filename);
    },
        [](RTSystemExtItem* item, const std::string& filename, std::ostream&, Item*) {
        return item->saveRtsProfile(filename);
    });
}

RTSystemExtItem::RTSystemExtItem()
{
    DDEBUG("RTSystemItem::RTSystemItem");
    impl = new RTSystemExtItemImpl(this);
}

RTSystemExtItemImpl::RTSystemExtItemImpl(RTSystemExtItem* self)
    : self(self), pollingCycle(1000)
{
    initialize();
    autoConnection = true;
}

RTSystemExtItem::RTSystemExtItem(const RTSystemExtItem& org)
    : Item(org)
{
    impl = new RTSystemExtItemImpl(this, *org.impl);
}

RTSystemExtItemImpl::RTSystemExtItemImpl(RTSystemExtItem* self, const RTSystemExtItemImpl& org)
    : self(self), pollingCycle(1000)
{
    initialize();
    autoConnection = org.autoConnection;
}

void RTSystemExtItemImpl::initialize()
{
    DDEBUG_V("RTSystemItemImpl::initialize cycle:%d", pollingCycle);
    connectionNo = 0;

    Mapping* config = AppConfig::archive()->openMapping("OpenRTM");
    vendorName = config->get("defaultVendor", "AIST");
    version = config->get("defaultVersion", "1.0.0");
    stateCheck.setSymbol(POLLING_CHECK, "Polling");
    stateCheck.setSymbol(MANUAL_CHECK, "Manual");
    checkAtLoading = true;
#if defined(OPENRTM_VERSION12)
    stateCheck.setSymbol(OBSERVER_CHECK, "Observer");
    heartBeatPeriod = config->get("heartBeatPeriod", 500);
#endif

    timer.setInterval(pollingCycle);
    timer.setSingleShot(false);
    timeOutConnection.reset(
        timer.sigTimeout().connect(
            std::bind(&RTSystemExtItemImpl::checkStatus, this)));

}

RTSystemExtItem::~RTSystemExtItem()
{
    delete impl;
}

RTSystemExtItemImpl::~RTSystemExtItemImpl()
{
    locationChangedConnection.disconnect();
}

Item* RTSystemExtItem::doDuplicate() const
{
    return new RTSystemExtItem(*this);
}

void RTSystemExtItemImpl::onLocationChanged(string host, int port)
{
    NameServerManager::instance()->getNCHelper()->setLocation(host, port);
}

void RTSystemExtItem::onActivated()
{
    impl->onActivated();
}

void RTSystemExtItemImpl::onActivated()
{
    DDEBUG("RTSystemExtItemImpl::onActivated");
    if( sigStatusUpdate.empty() == false && stateCheck.selectedIndex()==POLLING_CHECK ) {
        timer.start();
    }
}

RTSCompExt* RTSystemExtItem::nameToRTSComp(const string& name)
{
    return impl->nameToRTSComp(name);
}

RTSCompExt* RTSystemExtItemImpl::nameToRTSComp(const string& name)
{
    //DDEBUG_V("RTSystemItemImpl::nameToRTSComp:%s", name.c_str());
    map<string, RTSCompExtPtr>::iterator it = rtsComps.find(name);
    if (it == rtsComps.end())
        return 0;
    else
        return it->second.get();
}

RTSCompExt* RTSystemExtItem::addRTSComp(const string& name, const QPointF& pos)
{
    return impl->addRTSComp(name, pos);
}

RTSCompExt* RTSystemExtItemImpl::addRTSComp(const string& name, const QPointF& pos)
{
    DDEBUG_V("RTSystemItemImpl::addRTSComp:%s", name.c_str());

    if (!nameToRTSComp("/" + name + ".rtc")) {
        std::vector<NamingContextHelper::ObjectPath> pathList;
        NamingContextHelper::ObjectPath path(name, "rtc");
        pathList.push_back(path);
        NamingContextHelper* ncHelper = NameServerManager::instance()->getNCHelper();
        RTC::RTObject_ptr rtc = ncHelper->findObject<RTC::RTObject>(pathList);
        DDEBUG_V("ncHelper host:%s, port:%d", ncHelper->host().c_str(), ncHelper->port());
        if (rtc == RTC::RTObject::_nil()) {
            DDEBUG("RTSystemItemImpl::addRTSComp Failed");
            return nullptr;
        }

        string fullPath = "/" + name + ".rtc";
        RTSCompExtPtr rtsComp = new RTSCompExt(name, fullPath, rtc, self, pos, ncHelper->host().c_str(), ncHelper->port());
        rtsComps[fullPath] = rtsComp;

        self->suggestFileUpdate();

        return rtsComp;
    }

    return nullptr;
}

RTSCompExt* RTSystemExtItem::addRTSComp(const  NamingContextHelper::ObjectInfo& info, const QPointF& pos)
{
    return impl->addRTSComp(info, pos);
}

RTSCompExt* RTSystemExtItemImpl::addRTSComp(const NamingContextHelper::ObjectInfo& info, const QPointF& pos)
{
    DDEBUG("RTSystemItemImpl::addRTSComp");
    timeOutConnection.block();

    string fullPath = info.getFullPath();

    if (!nameToRTSComp(fullPath)) {
        std::vector<NamingContextHelper::ObjectPath> target = info.fullPath_;
        auto ncHelper = NameServerManager::instance()->getNCHelper();
        ncHelper->setLocation(info.hostAddress_, info.portNo_);
        RTC::RTObject_ptr rtc = ncHelper->findObject<RTC::RTObject>(target);
        if (!isObjectAlive(rtc)) {
            CORBA::release(rtc);
            rtc = nullptr;
        }

        RTSCompExtPtr rtsComp = new RTSCompExt(info.id_, fullPath, rtc, self, pos, info.hostAddress_, info.portNo_);
        rtsComps[fullPath] = rtsComp;

        self->suggestFileUpdate();

        return rtsComp.get();
    }
    timeOutConnection.unblock();

    return nullptr;
}

void RTSystemExtItem::deleteRTSComp(const string& name)
{
    impl->deleteRTSComp(name);
}

void RTSystemExtItemImpl::deleteRTSComp(const string& name)
{
    timeOutConnection.block();

    if (rtsComps.erase(name) > 0) {
        self->suggestFileUpdate();
    }

    timeOutConnection.unblock();
}

bool RTSystemExtItem::compIsAlive(RTSCompExt* rtsComp)
{
    return impl->compIsAlive(rtsComp);
}

bool RTSystemExtItemImpl::compIsAlive(RTSCompExt* rtsComp)
{
    //DDEBUG("RTSystemItemImpl::compIsAlive");
    if (rtsComp->isAlive_ && rtsComp->rtc_ && rtsComp->rtc_ != nullptr) {
        if (isObjectAlive(rtsComp->rtc_)) {
            return true;
        } else {
            rtsComp->setRtc(nullptr);
            return false;
        }
    } else {
        //DDEBUG_V("Full Path = %s", rtsComp->fullPath.c_str());
        QStringList nameList = QString::fromStdString(rtsComp->fullPath).split("/");
        std::vector<NamingContextHelper::ObjectPath> pathList;
        for (int index = 0; index < nameList.count(); index++) {
            QString elem = nameList[index];
            if (elem.length() == 0) continue;
            QStringList elemList = elem.split(".");
            if (elemList.size() != 2) return false;
            NamingContextHelper::ObjectPath path(elemList[0].toStdString(), elemList[1].toStdString());
            pathList.push_back(path);
        }

        NameServerManager::instance()->getNCHelper()->setLocation(rtsComp->hostAddress, rtsComp->portNo);
        RTC::RTObject_ptr rtc = NameServerManager::instance()->getNCHelper()->findObject<RTC::RTObject>(pathList);
        if (!isObjectAlive(rtc)) {
            //DDEBUG("RTSystemItemImpl::compIsAlive NOT Alive");
            return false;
        } else {
            DDEBUG("RTSystemItemImpl::compIsAlive Alive");
            rtsComp->setRtc(rtc);
            if (autoConnection) {
                list<RTSConnectionExt*> rtsConnectionList;
                RTSCompToConnectionList(rtsComp, rtsConnectionList, 0);
                for (auto it = rtsConnectionList.begin(); it != rtsConnectionList.end(); it++) {
                    auto connection = *it;
                    connection->connect();
                }
                DDEBUG("autoConnection End");
            }
            return true;
        }
    }
}

string RTSystemExtItemImpl::getConnectionNumber()
{
    stringstream ss;
    ss << connectionNo;
    connectionNo++;
    return ss.str();
}

RTSConnectionExt* RTSystemExtItem::addRTSConnection
(const std::string& id, const std::string& name, RTSPortExt* sourcePort, RTSPortExt* targetPort, const std::vector<NamedValueExtPtr>& propList, const Vector2 pos[])
{
    bool setPos = true;
    if (!pos) setPos = false;
    return impl->addRTSConnection(id, name, sourcePort, targetPort, propList, setPos, pos);
}

RTSConnectionExt* RTSystemExtItemImpl::addRTSConnection
(const string& id, const string& name,
 RTSPortExt* sourcePort, RTSPortExt* targetPort, const std::vector<NamedValueExtPtr>& propList,
 const bool setPos, const Vector2 pos[])
{
    DDEBUG("RTSystemItemImpl::addRTSConnection");
    timeOutConnection.block();

    bool updated = false;

    RTSConnectionExt* rtsConnection_;
    auto it = rtsConnections.find(RTSystemExtItem::RTSPortPair(sourcePort, targetPort));

    if (it != rtsConnections.end()) {
        rtsConnection_ = it->second;;

    } else {
        RTSConnectionExtPtr rtsConnection =
            new RTSConnectionExt(
                id, name,
                sourcePort->rtsComp->name, sourcePort->name,
                targetPort->rtsComp->name, targetPort->name);

        rtsConnection->srcRTC = sourcePort->rtsComp;
        rtsConnection->sourcePort = sourcePort;
        rtsConnection->targetRTC = targetPort->rtsComp;
        rtsConnection->targetPort = targetPort;
        rtsConnection->propList = propList;

        if (setPos) {
            rtsConnection->setPosition(pos);
        }

        rtsConnections[RTSystemExtItem::RTSPortPair(sourcePort, targetPort)] = rtsConnection;
        rtsConnection_ = rtsConnection;

        updated = true;
    }

    if (!CORBA::is_nil(sourcePort->port) && !sourcePort->port->_non_existent() &&
       !CORBA::is_nil(targetPort->port) && !targetPort->port->_non_existent()) {
        if (rtsConnection_->connect()) {
            updated = true;
        }
    }

    if (rtsConnection_->id.empty()) {
        rtsConnection_->id = "NoConnection_" + getConnectionNumber();
        updated = true;
    }

    if (updated) {
        self->suggestFileUpdate();
    }

    timeOutConnection.unblock();
    return rtsConnection_;
}

RTSConnectionExt* RTSystemExtItemImpl::addRTSConnectionName
(const string& id, const string& name,
 const string& sourceCompName, const string& sourcePortName,
 const string& targetCompName, const string& targetPortName,
 const string& dataflow, const string& subscription,
 const bool setPos, const Vector2 pos[])
{
    string sourceId = "/" + sourceCompName + ".rtc";
    RTSPortExt* sourcePort = 0;
    RTSCompExt* sourceRtc = nameToRTSComp(sourceId);
    if (sourceRtc) {
        sourcePort = sourceRtc->nameToRTSPort(sourcePortName);
    }

    string targetId = "/" + targetCompName + ".rtc";
    RTSPortExt* targetPort = 0;
    RTSCompExt* targetRtc = nameToRTSComp(targetId);
    if (targetRtc) {
        targetPort = targetRtc->nameToRTSPort(targetPortName);
    }
    if (sourcePort && targetPort) {
        vector<NamedValueExtPtr> propList;
        NamedValueExtPtr paramDataFlow(new NamedValueExt("dataport.dataflow_type", dataflow));
        propList.push_back(paramDataFlow);
        NamedValueExtPtr paramSubscription(new NamedValueExt("dataport.subscription_type", subscription));
        propList.push_back(paramSubscription);
        NamedValueExtPtr sinterfaceProp(new NamedValueExt("dataport.interface_type", "corba_cdr"));
        propList.push_back(sinterfaceProp);

        return addRTSConnection(id, name, sourcePort, targetPort, propList, setPos, pos);
    }

    return nullptr;
}

bool RTSystemExtItem::connectionCheck()
{
    return impl->connectionCheck();
}

bool RTSystemExtItemImpl::connectionCheck()
{
    bool updated = false;

    for (auto it = rtsConnections.begin(); it != rtsConnections.end(); it++) {
        const RTSystemExtItem::RTSPortPair& ports = it->first;
        if (ports(0)->isConnectedWith(ports(1))) {
            if (!it->second->isAlive_) {
                it->second->isAlive_ = true;
                updated = true;
            }
        } else {
            if (it->second->isAlive_) {
                it->second->isAlive_ = false;
                updated = true;
            }
        }
    }

    for (auto it = rtsComps.begin(); it != rtsComps.end(); it++) {
        if (it->second->connectionCheck()) {
            updated = true;
        }
    }

    return updated;
}

void RTSystemExtItem::RTSCompToConnectionList
(const RTSCompExt* rtsComp, list<RTSConnectionExt*>& rtsConnectionList, int mode)
{
    impl->RTSCompToConnectionList(rtsComp, rtsConnectionList, mode);
}

void RTSystemExtItemImpl::RTSCompToConnectionList
(const RTSCompExt* rtsComp, list<RTSConnectionExt*>& rtsConnectionList, int mode)
{
    for (RTSystemExtItem::RTSConnectionMap::iterator it = rtsConnections.begin();
            it != rtsConnections.end(); it++) {
        switch (mode) {
            case 0:
            default:
                if (it->second->sourceRtcName == rtsComp->name || it->second->targetRtcName == rtsComp->name)
                    rtsConnectionList.push_back(it->second);
                break;
            case 1:
                if (it->second->sourceRtcName == rtsComp->name)
                    rtsConnectionList.push_back(it->second);
                break;
            case 2:
                if (it->second->targetRtcName == rtsComp->name)
                    rtsConnectionList.push_back(it->second);
                break;
        }
    }
}

map<string, RTSCompExtPtr>& RTSystemExtItem::rtsComps()
{
    return impl->rtsComps;
}

RTSystemExtItem::RTSConnectionMap& RTSystemExtItem::rtsConnections()
{
    return impl->rtsConnections;
}

void RTSystemExtItem::disconnectAndRemoveConnection(RTSConnectionExt* connection)
{
    connection->disconnect();
    impl->removeConnection(connection);
}

void RTSystemExtItemImpl::removeConnection(RTSConnectionExt* connection)
{
    RTSystemExtItem::RTSPortPair pair(connection->sourcePort, connection->targetPort);
    if (rtsConnections.erase(pair) > 0) {
        self->suggestFileUpdate();
    }
}

void RTSystemExtItem::doPutProperties(PutPropertyFunction& putProperty)
{
    impl->doPutProperties(putProperty);
}

void RTSystemExtItemImpl::doPutProperties(PutPropertyFunction& putProperty)
{
    DDEBUG("RTSystemItemImpl::doPutProperties");
    putProperty(_("Auto Connection"), autoConnection, changeProperty(autoConnection));
    putProperty(_("Vendor Name"), vendorName, changeProperty(vendorName));
    putProperty(_("Version"), version, changeProperty(version));
    putProperty(_("State Check"), stateCheck,
                [&](int value) { setStateCheckMethod(value); return true; });
    putProperty(_("Polling Cycle"), pollingCycle,
                [&](int value) { changePollingPeriod(value); return true; });
    putProperty(_("CheckAtLoading"), checkAtLoading, changeProperty(checkAtLoading));

#if defined(OPENRTM_VERSION12)
    putProperty(_("HeartBeat Period"), heartBeatPeriod, changeProperty(heartBeatPeriod));
#endif
}

void RTSystemExtItemImpl::changePollingPeriod(int value)
{
    DDEBUG_V("RTSystemItemImpl::changePollingPeriod=%d", value);
    if (pollingCycle != value) {
        pollingCycle = value;

        bool isStarted = timer.isActive();
        if( isStarted ) timer.stop();
        timer.setInterval(value);
        if( isStarted ) timer.start();
    }
}

void RTSystemExtItemImpl::setStateCheckMethod(int value)
{
    DDEBUG_V("RTSystemItemImpl::setStateCheckMethod=%d", value);
    stateCheck.selectIndex(value);
    changeStateCheck();
}

void RTSystemExtItemImpl::setStateCheckMethodByString(const string& value)
{
    DDEBUG_V("RTSystemItemImpl::setStateCheckMethodByString=%s", value.c_str());
    stateCheck.select(value);
    DDEBUG_V("RTSystemItemImpl::setStateCheckMethodByString=%d", stateCheck.selectedIndex());
    changeStateCheck();
}

void RTSystemExtItemImpl::changeStateCheck()
{
    int state = stateCheck.selectedIndex();
    DDEBUG_V("RTSystemItemImpl::changeStateCheck=%d", state);
    switch (state) {
        case MANUAL_CHECK:
            timer.stop();
            break;
#if defined(OPENRTM_VERSION12)
        case OBSERVER_CHECK:
            break;
#endif
        default:
            timer.start();
            break;
    }
}

bool RTSystemExtItem::loadRtsProfile(const string& filename)
{
    DDEBUG_V("RTSystemItem::loadRtsProfile=%s", filename.c_str());
    ProfileHandler::getRtsProfileInfo(filename, impl->vendorName, impl->version);
    if (ProfileHandlerExt::restoreRtsProfile(filename, this)) {
        impl->sigLoaded(false);
        return true;
    }
    return false;
}

bool RTSystemExtItem::saveRtsProfile(const string& filename)
{
    return impl->saveRtsProfile(filename);
}

bool RTSystemExtItemImpl::saveRtsProfile(const string& filename)
{
    if (vendorName.empty()) {
        vendorName = "Choreonoid";
    }
    if (version.empty()) {
        version = "1.0.0";
    }
    string systemId = "RTSystem:" + vendorName + ":" + self->name() + ":" + version;
    ProfileHandlerExt::saveRtsProfile(filename, systemId, rtsComps, rtsConnections, MessageView::mainInstance()->cout());

    return true;
}

void RTSystemExtItem::setVendorName(const std::string& name)
{
    impl->vendorName = name;
}

void RTSystemExtItem::setVersion(const std::string& version)
{
    impl->version = version;
}

int RTSystemExtItem::stateCheck() const
{
    return impl->stateCheck.selectedIndex();
}

void RTSystemExtItem::checkStatus()
{
    impl->checkStatus();
}

void RTSystemExtItemImpl::checkStatus()
{
    DDEBUG("RTSystemExtItemImpl::checkStatus");
    if( sigStatusUpdate.empty() ) {
        timer.stop();
    }

    bool modified = false;

    for (auto it = rtsComps.begin(); it != rtsComps.end(); it++) {
        if (compIsAlive(it->second)) {
            if (!it->second->isAlive_) {
                modified = true;
            }
            it->second->isAlive_ = true;
            RTC_STATUS status = it->second->getRTCState();
            DDEBUG_V("RTC State : %d, %d", it->second->rtc_status_, status);
            if( status != it->second->rtc_status_ ) {
                modified = true;
                it->second->rtc_status_ = status;
            }
        } else {
            if (it->second->isAlive_) {
                modified = true;
            }
            it->second->isAlive_ = false;
        }
    }
    //
    if (connectionCheck()) {
        modified = true;
    }
    DDEBUG_V("RTSystemExtItemImpl::checkStatus End : %d", modified);
    sigStatusUpdate(modified);
}
///////////
bool RTSystemExtItem::store(Archive& archive)
{
    if (overwrite()) {
        archive.writeRelocatablePath("filename", filePath());
        archive.write("format", fileFormat());

        archive.write("autoConnection", impl->autoConnection);
        archive.write("pollingCycle", impl->pollingCycle);
        archive.write("stateCheck", impl->stateCheck.selectedSymbol());
        archive.write("checkAtLoading", impl->checkAtLoading);

#if defined(OPENRTM_VERSION12)
        archive.write("HeartBeatPeriod", impl->heartBeatPeriod);
#endif
        return true;
    }

    return true;
}

bool RTSystemExtItem::restore(const Archive& archive)
{
    DDEBUG("RTSystemExtItem::restore");

    if (archive.read("autoConnection", impl->autoConnection) == false) {
        archive.read("AutoConnection", impl->autoConnection);
    }

    int pollingCycle = 1000;
    if( archive.read("pollingCycle", pollingCycle)==false) {
        archive.read("PollingCycle", pollingCycle);
    }
    if( archive.read("checkAtLoading", impl->checkAtLoading)==false) {
        archive.read("CheckAtLoading", impl->checkAtLoading);
    }

    impl->changePollingPeriod(pollingCycle);

#if defined(OPENRTM_VERSION12)
    if(archive.read("HeartBeatPeriod", impl->heartBeatPeriod) == false) {
        archive.read("heartBeatPeriod", impl->heartBeatPeriod);
    }
#endif

    /**
       The contents of RTSystemItem must be loaded after all the items are restored
       so that the states of the RTCs created by other items can be loaded.
    */
    std::string filename, formatId;
    if (archive.readRelocatablePath("filename", filename)) {
        if (archive.read("format", formatId)) {
            archive.addPostProcess(
                [this, filename, formatId]() { load(filename, formatId); });
        }
    } else {
        // old format data contained in a project file
        archive.addPostProcess([&]() { impl->restoreRTSystem(archive); });
    }

    string stateCheck;
    if (archive.read("StateCheck", stateCheck)) {
        DDEBUG_V("StateCheck:%s", stateCheck.c_str());
        impl->setStateCheckMethodByString(stateCheck);
        archive.addPostProcess([&]() { impl->changeStateCheck(); });
    }

    return true;
}

void RTSystemExtItemImpl::restoreRTSystem(const Archive& archive)
{
    DDEBUG("RTSystemItemImpl::restoreRTSystem");

    const Listing& compListing = *archive.findListing("RTSComps");
    if (compListing.isValid()) {
        for (int i = 0; i < compListing.size(); i++) {
            const Mapping& compMap = *compListing[i].toMapping();
            string name;
            Vector2 pos;
            compMap.read("name", name);
            read(compMap, "pos", pos);

            vector<pair<string, bool>> inPorts;
            vector<pair<string, bool>> outPorts;
            const Listing& inportListing = *compMap.findListing("InPorts");
            if (inportListing.isValid()) {
                for (int i = 0; i < inportListing.size(); i++) {
                    const Mapping& inMap = *inportListing[i].toMapping();
                    string portName;
                    bool isServicePort;
                    inMap.read("name", portName);
                    inMap.read("isServicePort", isServicePort);
                    inPorts.push_back(make_pair(portName, isServicePort));
                }
            }
            const Listing& outportListing = *compMap.findListing("OutPorts");
            if (outportListing.isValid()) {
                for (int i = 0; i < outportListing.size(); i++) {
                    const Mapping& outMap = *outportListing[i].toMapping();
                    string portName;
                    bool isServicePort;
                    outMap.read("name", portName);
                    outMap.read("isServicePort", isServicePort);
                    outPorts.push_back(make_pair(portName, isServicePort));
                }
            }
            restoreRTSComp(name, pos, inPorts, outPorts);
        }
    }

    if (autoConnection) {
        const Listing& connectionListing = *archive.findListing("RTSConnections");
        if (connectionListing.isValid()) {
            for (int i = 0; i < connectionListing.size(); i++) {
                const Mapping& connectMap = *connectionListing[i].toMapping();
                string name, sR, sP, tR, tP, dataflow, subscription;
                connectMap.read("name", name);
                connectMap.read("sourceRtcName", sR);
                connectMap.read("sourcePortName", sP);
                connectMap.read("targetRtcName", tR);
                connectMap.read("targetPortName", tP);
                connectMap.read("dataflow", dataflow);
                connectMap.read("subscription", subscription);
                VectorXd p(12);
                bool readPos = false;
                Vector2 pos[6];
                if (read(connectMap, "position", p)) {
                    readPos = true;
                    for (int i = 0; i < 6; i++) {
                        pos[i] << p(2 * i), p(2 * i + 1);
                    }
                }

                addRTSConnectionName("", name, sR, sP, tR, tP, dataflow, subscription, readPos, pos);
            }
        }
    }

    if (checkAtLoading) {
        checkStatus();
    }

    sigLoaded(true);
    DDEBUG("RTSystemItemImpl::restoreRTSystem End");
}

void RTSystemExtItemImpl::restoreRTSComp(const string& name, const Vector2& pos,
        const vector<pair<string, bool>>& inPorts, const vector<pair<string, bool>>& outPorts)
{
    DDEBUG("RTSystemItemImpl::restoreRTSComp");

    RTSCompExt* comp = addRTSComp(name, QPointF(pos(0), pos(1)));
    if (comp == 0) return;
    if (!comp->rtc_) {
        comp->inPorts.clear();
        comp->outPorts.clear();
        for (int i = 0; i < inPorts.size(); i++) {
            RTSPortExtPtr rtsPort = new RTSPortExt(inPorts[i].first, 0, comp);
            rtsPort->isInPort = true;
            rtsPort->isServicePort = inPorts[i].second;
            comp->inPorts.push_back(rtsPort);
        }
        for (int i = 0; i < outPorts.size(); i++) {
            RTSPortExtPtr rtsPort = new RTSPortExt(outPorts[i].first, 0, comp);
            rtsPort->isInPort = false;
            rtsPort->isServicePort = outPorts[i].second;
            comp->outPorts.push_back(rtsPort);
        }
    }
    DDEBUG("RTSystemItemImpl::restoreRTSComp End");
}

SignalProxy<void(bool)> RTSystemExtItem::sigLoaded()
{
    return impl->sigLoaded;
}

SignalProxy<void(bool)> RTSystemExtItem::sigStatusUpdate()
{
    return impl->sigStatusUpdate;
}


text:
#include <crow/app.h>

#include <ast_jpeg_decoder.hpp>
#include <ast_video_puller.hpp>
#include <boost/endian/arithmetic.hpp>
#include <string>

namespace crow
{
namespace kvm
{

static const std::string rfb33VersionString = "RFB 003.003\n";
static const std::string rfb37VersionString = "RFB 003.007\n";
static const std::string rfb38VersionString = "RFB 003.008\n";

enum class RfbAuthScheme : uint8_t
{
    connection_failed = 0,
    no_authentication = 1,
    vnc_authentication = 2
};

struct PixelFormatStruct
{
    boost::endian::big_uint8_t bitsPerPixel;
    boost::endian::big_uint8_t depth;
    boost::endian::big_uint8_t isBigEndian;
    boost::endian::big_uint8_t isTrueColor;
    boost::endian::big_uint16_t redMax;
    boost::endian::big_uint16_t greenMax;
    boost::endian::big_uint16_t blueMax;
    boost::endian::big_uint8_t redShift;
    boost::endian::big_uint8_t greenShift;
    boost::endian::big_uint8_t blueShift;
    boost::endian::big_uint8_t pad1;
    boost::endian::big_uint8_t pad2;
    boost::endian::big_uint8_t pad3;
};

struct ServerInitializationMsg
{
    boost::endian::big_uint16_t framebufferWidth;
    boost::endian::big_uint16_t framebufferHeight;
    PixelFormatStruct pixelFormat;
    boost::endian::big_uint32_t nameLength;
};

enum class client_to_server_msg_type : uint8_t
{
    set_pixel_format = 0,
    fix_color_map_entries = 1,
    set_encodings = 2,
    framebuffer_update_request = 3,
    key_event = 4,
    pointer_event = 5,
    client_cut_text = 6
};

enum class server_to_client_message_type : uint8_t
{
    framebuffer_update = 0,
    set_color_map_entries = 1,
    bell_message = 2,
    server_cut_text = 3
};

struct SetPixelFormatMsg
{
    boost::endian::big_uint8_t pad1;
    boost::endian::big_uint8_t pad2;
    boost::endian::big_uint8_t pad3;
    PixelFormatStruct pixelFormat;
};

struct FrameBufferUpdateReq
{
    boost::endian::big_uint8_t incremental;
    boost::endian::big_uint16_t xPosition;
    boost::endian::big_uint16_t yPosition;
    boost::endian::big_uint16_t width;
    boost::endian::big_uint16_t height;
};

struct KeyEventMsg
{
    boost::endian::big_uint8_t downFlag;
    boost::endian::big_uint8_t pad1;
    boost::endian::big_uint8_t pad2;
    boost::endian::big_uint32_t key;
};

struct PointerEventMsg
{
    boost::endian::big_uint8_t buttonMask;
    boost::endian::big_uint16_t xPosition;
    boost::endian::big_uint16_t yPosition;
};

struct ClientCutTextMsg
{
    std::vector<uint8_t> data;
};

enum class encoding_type : uint32_t
{
    raw = 0x00,
    copy_rectangle = 0x01,
    rising_rectangle = 0x02,
    corre = 0x04,
    hextile = 0x05,
    zlib = 0x06,
    tight = 0x07,
    zlibhex = 0x08,
    ultra = 0x09,
    zrle = 0x10,
    zywrle = 0x011,
    cache_enable = 0xFFFF0001,
    xor_enable = 0xFFFF0006,
    server_state_ultranvc = 0xFFFF8000,
    enable_keepAlive = 0xFFFF8001,
    enableftp_protocol_version = 0xFFFF8002,
    tight_compress_level_0 = 0xFFFFFF00,
    tight_compress_level_9 = 0xFFFFFF09,
    x_cursor = 0xFFFFFF10,
    rich_cursor = 0xFFFFFF11,
    pointer_pos = 0xFFFFFF18,
    last_rect = 0xFFFFFF20,
    new_framebuffer_size = 0xFFFFFF21,
    tight_quality_level_0 = 0xFFFFFFE0,
    tight_quality_level_9 = 0xFFFFFFE9
};

struct FramebufferRectangle
{
    boost::endian::big_uint16_t x{};
    boost::endian::big_uint16_t y{};
    boost::endian::big_uint16_t width{};
    boost::endian::big_uint16_t height{};
    boost::endian::big_uint32_t encoding{};
    std::vector<uint8_t> data;
};

struct FramebufferUpdateMsg
{
    boost::endian::big_uint8_t messageType{};
    std::vector<FramebufferRectangle> rectangles;
};

inline std::string serialize(const FramebufferUpdateMsg& msg)
{
    // calculate the size of the needed vector for serialization
    size_t vectorSize = 4;
    for (const auto& rect : msg.rectangles)
    {
        vectorSize += 12 + rect.data.size();
    }

    std::string serialized(vectorSize, 0);

    size_t i = 0;
    serialized[i++] = static_cast<char>(
        server_to_client_message_type::framebuffer_update); // Type
    serialized[i++] = 0;                                    // Pad byte
    boost::endian::big_uint16_t numberOfRectangles = msg.rectangles.size();
    std::memcpy(&serialized[i], &numberOfRectangles,
                sizeof(numberOfRectangles));
    i += sizeof(numberOfRectangles);

    for (const auto& rect : msg.rectangles)
    {
        // copy the first part of the struct
        size_t bufferSize =
            sizeof(FramebufferRectangle) - sizeof(std::vector<uint8_t>);
        std::memcpy(&serialized[i], &rect, bufferSize);
        i += bufferSize;

        std::memcpy(&serialized[i], rect.data.data(), rect.data.size());
        i += rect.data.size();
    }

    return serialized;
}

enum class VncState
{
    UNSTARTED,
    AWAITING_CLIENT_VERSION,
    AWAITING_CLIENT_AUTH_METHOD,
    AWAITING_CLIENT_INIT_msg,
    MAIN_LOOP
};

class ConnectionMetadata
{
  public:
    ConnectionMetadata(){};

    VncState vncState{VncState::UNSTARTED};
};

using meta_list = std::vector<ConnectionMetadata>;
meta_list connectionStates(10);

ConnectionMetadata meta;

template <typename... Middlewares> void requestRoutes(Crow<Middlewares...>& app)
{
    BMCWEB_ROUTE(app, "/kvmws")
        .websocket()
        .onopen([&](crow::websocket::Connection& conn) {
            if (meta.vncState == VncState::UNSTARTED)
            {
                meta.vncState = VncState::AWAITING_CLIENT_VERSION;
                conn.sendBinary(rfb38VersionString);
            }
            else
            { // SHould never happen
                conn.close();
            }
        })
        .onclose(
            [&](crow::websocket::Connection& conn, const std::string& reason) {
                meta.vncState = VncState::UNSTARTED;
            })
        .onmessage([&](crow::websocket::Connection& conn,
                       const std::string& data, bool is_binary) {
            switch (meta.vncState)
            {
                case VncState::AWAITING_CLIENT_VERSION:
                {
                    std::cout << "Client sent: " << data;
                    if (data == rfb38VersionString ||
                        data == rfb37VersionString)
                    {
                        std::string authTypes{
                            1, (uint8_t)RfbAuthScheme::no_authentication};
                        conn.sendBinary(authTypes);
                        meta.vncState = VncState::AWAITING_CLIENT_AUTH_METHOD;
                    }
                    else if (data == rfb33VersionString)
                    {
                        // TODO(ed)  Support older protocols
                        meta.vncState = VncState::UNSTARTED;
                        conn.close();
                    }
                    else
                    {
                        // TODO(ed)  Support older protocols
                        meta.vncState = VncState::UNSTARTED;
                        conn.close();
                    }
                }
                break;
                case VncState::AWAITING_CLIENT_AUTH_METHOD:
                {
                    std::string securityResult{{0, 0, 0, 0}};
                    if (data[0] == (uint8_t)RfbAuthScheme::no_authentication)
                    {
                        meta.vncState = VncState::AWAITING_CLIENT_INIT_msg;
                    }
                    else
                    {
                        // Mark auth as failed
                        securityResult[3] = 1;
                        meta.vncState = VncState::UNSTARTED;
                    }
                    conn.sendBinary(securityResult);
                }
                break;
                case VncState::AWAITING_CLIENT_INIT_msg:
                {
                    // Now send the server initialization
                    ServerInitializationMsg serverInitMsg{};
                    serverInitMsg.framebufferWidth = 800;
                    serverInitMsg.framebufferHeight = 600;
                    serverInitMsg.pixelFormat.bitsPerPixel = 32;
                    serverInitMsg.pixelFormat.isBigEndian = 0;
                    serverInitMsg.pixelFormat.isTrueColor = 1;
                    serverInitMsg.pixelFormat.redMax = 255;
                    serverInitMsg.pixelFormat.greenMax = 255;
                    serverInitMsg.pixelFormat.blueMax = 255;
                    serverInitMsg.pixelFormat.redShift = 16;
                    serverInitMsg.pixelFormat.greenShift = 8;
                    serverInitMsg.pixelFormat.blueShift = 0;
                    serverInitMsg.nameLength = 0;
                    std::cout << "size: " << sizeof(serverInitMsg);
                    // TODO(ed) this is ugly.  Crow should really have a span
                    // type interface to avoid the copy, but alas, today it does
                    // not.
                    std::string s(reinterpret_cast<char*>(&serverInitMsg),
                                  sizeof(serverInitMsg));
                    std::cout << "s.size() " << s.size();
                    conn.sendBinary(s);
                    meta.vncState = VncState::MAIN_LOOP;
                }
                break;
                case VncState::MAIN_LOOP:
                {
                    if (data.size() >= sizeof(client_to_server_msg_type))
                    {
                        auto type =
                            static_cast<client_to_server_msg_type>(data[0]);
                        std::cout << "Received client message type "
                                  << static_cast<std::size_t>(type) << "\n";
                        switch (type)
                        {
                            case client_to_server_msg_type::set_pixel_format:
                            {
                            }
                            break;

                            case client_to_server_msg_type::
                                fix_color_map_entries:
                            {
                            }
                            break;
                            case client_to_server_msg_type::set_encodings:
                            {
                            }
                            break;
                            case client_to_server_msg_type::
                                framebuffer_update_request:
                            {
                                // Make sure the buffer is long enough to handle
                                // what we're about to do
                                if (data.size() >=
                                    sizeof(FrameBufferUpdateReq) +
                                        sizeof(client_to_server_msg_type))
                                {
                                    auto msg = reinterpret_cast<
                                        const FrameBufferUpdateReq*>(
                                        data.data() + // NOLINT
                                        sizeof(client_to_server_msg_type));
                                    // TODO(ed) find a better way to do this
                                    // deserialization

                                    // Todo(ed) lifecycle of the video puller
                                    // and decoder should be with the websocket,
                                    // not recreated every time
                                    ast_video::SimpleVideoPuller p;
                                    p.initialize();
                                    auto out = p.readVideo();
                                    ast_video::AstJpegDecoder d;
                                    d.decode(out.buffer, out.width, out.height,
                                             out.mode, out.ySelector,
                                             out.uvSelector);

                                    FramebufferUpdateMsg bufferUpdateMsg;

                                    // If the viewer is requesting a full
                                    // update, force write of all pixels

                                    FramebufferRectangle thisRect;
                                    thisRect.x = msg->xPosition;
                                    thisRect.y = msg->yPosition;
                                    thisRect.width = out.width;
                                    thisRect.height = out.height;
                                    thisRect.encoding = static_cast<uint8_t>(
                                        encoding_type::raw);
                                    std::cout << "Encoding is "
                                              << thisRect.encoding;
                                    thisRect.data.reserve(
                                        static_cast<std::size_t>(
                                            thisRect.width) *
                                        static_cast<std::size_t>(
                                            thisRect.height) *
                                        4);
                                    std::cout << "Width " << out.width
                                              << " Height " << out.height;

                                    for (int i = 0; i < out.width * out.height;
                                         i++)
                                    {
                                        auto& pixel = d.outBuffer[i];
                                        thisRect.data.push_back(pixel.b);
                                        thisRect.data.push_back(pixel.g);
                                        thisRect.data.push_back(pixel.r);
                                        thisRect.data.push_back(0);
                                    }

                                    bufferUpdateMsg.rectangles.push_back(
                                        std::move(thisRect));
                                    auto serialized =
                                        serialize(bufferUpdateMsg);

                                    conn.sendBinary(serialized);

                                } // TODO(Ed) handle error
                            }

                            break;

                            case client_to_server_msg_type::key_event:
                            {
                            }
                            break;

                            case client_to_server_msg_type::pointer_event:
                            {
                            }
                            break;

                            case client_to_server_msg_type::client_cut_text:
                            {
                            }
                            break;

                            default:
                                break;
                        }
                    }
                }
                break;
                case VncState::UNSTARTED:
                    // Error?  TODO
                    break;
            }
        });
}
} // namespace kvm
} // namespace crow

max_stars_repo_name: hyche/bmcweb

max_issues_repo_name: hyche/bmcweb

max_forks_repo_name: hyche/bmcweb