text:
/*
 * common.hpp
 *
 *  Created on: Aug 26, 2013
 *      Author: mdantone
 */

#ifndef COMMON_HPP_
#define COMMON_HPP_

#include <opencv2/opencv.hpp>
#include "cpp/utils/serialization/opencv_serialization.hpp"
#include <fstream>
#include <boost/lexical_cast.hpp>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/convenience.hpp>
#include <boost/algorithm/string.hpp>
#include "cpp/body_pose/body_pose_types.hpp"
#include <boost/assign/std/vector.hpp>

using namespace boost::assign;

static const int NUM_ENTRIES = 26 + 4 + 1 + 1 + 1; //parts_coords +  bbox + cluster_id + num_parts + img_url

struct Annotation {
    Annotation() : flipped(false),
                   cluster_id(0),
                   center(),
                   nNeighbours(0),
                   neig_urls(),
                   weight(1),
                   best_scale(1),
                   neig_bboxs()
                   {};

    // number of parts
    std::vector<cv::Point> parts;

    // url to original image
    std::string url;

    // bounding box
    cv::Rect bbox;

    bool flipped;

    // cluster_id
    int cluster_id;

    cv::Point_<int> center;

    // number of neighbours from both sides
    int nNeighbours;

    // url to neighbours
    std::vector<std::string> neig_urls;

    // weight of the annotation
    double weight;

    // best scale for the annotation.
    double best_scale;

    // bounding boxes for the neigbours
    std::vector<cv::Rect> neig_bboxs; //left neighbours

    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive & ar, const unsigned int version) {
      ar & parts;
      ar & url;
      ar & bbox;
      ar & flipped;
      ar & cluster_id;
    }
};

struct SequenceInfo{
  SequenceInfo():path(), frame_count(0) {};
  SequenceInfo(std::string _path, int _frame_count):path(_path), frame_count(_frame_count){};

  std::string path;
  int frame_count;
};

struct Join{
  Join(int a, int b, cv::Scalar color_ ) :part_a(a), part_b(b), color(color_){};
  int part_a;
  int part_b;
  cv::Scalar color;
};

void inline _plot(cv::Mat& img, std::vector<cv::Point> ann, std::string path = "", int wait = 0 ){
    cv::Mat plot;

    if( path != "") {
      plot = img;
    }else{
      plot = img;
    }

    std::vector<Join> joints;

    joints.push_back( Join(0,2,cv::Scalar(0, 255, 0)) );
    joints.push_back( Join(1,0,cv::Scalar(0, 255, 0)) );
    joints.push_back( Join(2,4,cv::Scalar(0,255, 255)) );
    joints.push_back( Join(1,3,cv::Scalar(0,255, 255)) );

    joints.push_back( Join(1,5,cv::Scalar(255, 255, 0)) );
    joints.push_back( Join(5,6,cv::Scalar(255, 255, 0)) );

    joints.push_back( Join(2,7,cv::Scalar(255, 0, 255)) );
    joints.push_back( Join(7,8,cv::Scalar(255, 0, 255)) );

    joints.push_back( Join(4,11,cv::Scalar(255, 0, 0)) );
    joints.push_back( Join(11,12,cv::Scalar(255, 0, 0)) );

    joints.push_back( Join(3,9,cv::Scalar(0, 0, 255)) );
    joints.push_back( Join(9,10,cv::Scalar(0, 0, 255)) );

    for(int i=0; i < ann.size()-1; i++) {
      cv::Point a = ann[joints[i].part_a];
      cv::Point b = ann[joints[i].part_b];
      if(a.x >0 && b.x > 0 && a.y >0 && b.y > 0 && a.x < plot.cols && b.x < plot.cols ) {
        cv::line(plot, a, b, joints[i].color, 3);
      }
    }
    for (int i = 0; i < static_cast<int> (ann.size()); i++) {
      int x = ann[i].x;
      int y = ann[i].y;
      if (x > 0 and x < plot.cols and y > 0 and y < plot.rows) {
        if(i < 13){
          cv::circle(plot, cv::Point_<int>(x, y), 5, cv::Scalar(0, 0, 0, 0), -1 );
        }
        else if(i < 26){
          cv::circle(plot, cv::Point_<int>(x, y), 3, cv::Scalar(255, 0, 0, 0), -1 );
        }
        else{
          cv::circle(plot, cv::Point_<int>(x, y), 3, cv::Scalar(0, 0, 255, 0), -1 );
        }
      }
  //    rectangle(plot, ann.bbox, Scalar(0, 0, 255), 3);
    }

    if(path == "") {
      cv::imshow("Face", plot);
      cv::waitKey(wait);
    }else{
      cv::imwrite(path,plot);
    }
}

void inline _plot_7(cv::Mat& img, std::vector<cv::Point> ann, std::string path = "", int wait = 0 ){
    cv::Mat plot;

    if( path != "") {
      plot = img;
    }else{
      plot = img;
    }

    std::vector<Join> joints;

    joints.push_back( Join(1,0,cv::Scalar(0, 255, 0)) );
    joints.push_back( Join(0,2,cv::Scalar(0, 255, 0)) );
    joints.push_back( Join(1,3,cv::Scalar(0,255, 255)) );
    joints.push_back( Join(3,4,cv::Scalar(128,255, 128)) );

    joints.push_back( Join(2,5,cv::Scalar(255, 255, 0)) );
    joints.push_back( Join(5,6,cv::Scalar(255, 0, 255)) );

    for(int i=0; i < ann.size()-1; i++) {
      cv::Point a = ann[joints[i].part_a];
      cv::Point b = ann[joints[i].part_b];
      if(a.x >0 && b.x > 0 && a.y >0 && b.y > 0 && a.x < plot.cols && b.x < plot.cols ) {
        cv::line(plot, a, b, joints[i].color, 1);
      }
    }

    for (int i = 0; i < static_cast<int> (ann.size()); i++) {
      int x = ann[i].x;
      int y = ann[i].y;
      cv::circle(plot, cv::Point_<int>(x, y), 0.5, cv::Scalar(0, 0, 0, 0), -1 );
 //    rectangle(plot, ann.bbox, Scalar(0, 0, 255), 3);
    }

    if(path == "") {
      cv::imshow("Face", plot);
      cv::waitKey(wait);
    }else{
      cv::imwrite(path,plot);
    }
}

void inline _plot_9(cv::Mat& img, std::vector<cv::Point> ann, std::string path = "", int wait = 0 ){
    cv::Mat plot;

    if( path != "") {
      plot = img;
    }else{
      plot = img;
    }

    std::vector<Join> joints;

    joints.push_back( Join(1,0,cv::Scalar(0, 255, 0)) );
    joints.push_back( Join(0,2,cv::Scalar(0, 255, 0)) );
    joints.push_back( Join(1,3,cv::Scalar(0,255, 255)) );
    joints.push_back( Join(3,4,cv::Scalar(128,255, 128)) );
    joints.push_back( Join(4,5,cv::Scalar(128,255, 128)) );

    joints.push_back( Join(2,6,cv::Scalar(255, 255, 0)) );
    joints.push_back( Join(6,7,cv::Scalar(255, 0, 255)) );
    joints.push_back( Join(7,8,cv::Scalar(255, 0, 255)) );

    for(int i=0; i < ann.size()-1; i++) {
      cv::Point a = ann[joints[i].part_a];
      cv::Point b = ann[joints[i].part_b];
      if(a.x >0 && b.x > 0 && a.y >0 && b.y > 0 && a.x < plot.cols && b.x < plot.cols ) {
        cv::line(plot, a, b, joints[i].color, 1);
      }
    }

    for (int i = 0; i < static_cast<int> (ann.size()); i++) {
      int x = ann[i].x;
      int y = ann[i].y;
      cv::circle(plot, cv::Point_<int>(x, y), 0.5, cv::Scalar(0, 0, 0, 0), -1 );
 //    rectangle(plot, ann.bbox, Scalar(0, 0, 255), 3);
    }

    if(path == "") {
      cv::imshow("Face", plot);
      cv::waitKey(wait);
    }else{
      cv::imwrite(path,plot);
    }
}

void inline _plot_14(cv::Mat& img, std::vector<cv::Point> ann, std::string path = "", int wait = 0 ){
    cv::Mat plot;

    if( path != "") {
      plot = img;
    }else{
      //plot = img.clone();
      plot = img;
    }

    std::vector<Join> joints;

    joints.push_back( Join(1,0,cv::Scalar(0, 255, 0)) );
    joints.push_back( Join(1,3,cv::Scalar(0, 255, 0)) );
    joints.push_back( Join(2,1,cv::Scalar(0, 255, 0)) );
    joints.push_back( Join(3,5,cv::Scalar(0,255, 255)) );
    joints.push_back( Join(2,4,cv::Scalar(0,255, 255)) );

    joints.push_back( Join(2,6,cv::Scalar(255, 255, 0)) );
    joints.push_back( Join(6,7,cv::Scalar(255, 255, 0)) );

    joints.push_back( Join(3,8,cv::Scalar(255, 0, 255)) );
    joints.push_back( Join(8,9,cv::Scalar(255, 0, 255)) );

    joints.push_back( Join(5,12,cv::Scalar(255, 0, 0)) );
    joints.push_back( Join(12,13,cv::Scalar(255, 0, 0)) );

    joints.push_back( Join(4,10,cv::Scalar(0, 0, 255)) );
    joints.push_back( Join(10,11,cv::Scalar(0, 0, 255)) );

    for(int i=0; i < ann.size()-1; i++) {
      cv::Point a = ann[joints[i].part_a];
      cv::Point b = ann[joints[i].part_b];
      if(a.x >0 && b.x > 0 && a.y >0 && b.y > 0 && a.x < plot.cols && b.x < plot.cols ) {
        cv::line(plot, a, b, joints[i].color, 3);
      }
    }
    for (int i = 0; i < static_cast<int> (ann.size()); i++) {
      int x = ann[i].x;
      int y = ann[i].y;
      if (x > 0 and x < plot.cols and y > 0 and y < plot.rows) {
        if(i < 14){
          cv::circle(plot, cv::Point_<int>(x, y), 5, cv::Scalar(0, 0, 0, 0), -1 );
        }
        else if(i < 28){
          cv::circle(plot, cv::Point_<int>(x, y), 3, cv::Scalar(255, 0, 0, 0), -1 );
        }
        else{
          cv::circle(plot, cv::Point_<int>(x, y), 3, cv::Scalar(0, 0, 255, 0), -1 );
        }
      }
  //    rectangle(plot, ann.bbox, Scalar(0, 0, 255), 3);
    }

    if(path == "") {
      cv::imshow("Face", plot);
      cv::waitKey(wait);
    }else{
      cv::imwrite(path,plot);
    }
}

void inline _plot_17(cv::Mat& img, std::vector<cv::Point> ann, std::string path = "", int wait = 0 ){
    cv::Mat plot;

    if( path != "") {
      plot = img;
    }else{
      //plot = img.clone();
      plot = img;
    }

    std::vector<Join> joints;

    joints.push_back( Join(0,1,cv::Scalar(0, 255, 0)) );
    joints.push_back( Join(2,1,cv::Scalar(0, 255, 0)) );
    joints.push_back( Join(2,3,cv::Scalar(0, 255, 0)) );
    joints.push_back( Join(2,4,cv::Scalar(0, 255, 0)) );

    joints.push_back( Join(2,5,cv::Scalar(0, 255, 0)) );
    joints.push_back( Join(5,6,cv::Scalar(0, 255, 0)) );
    joints.push_back( Join(6,7,cv::Scalar(0, 255, 0)) );
    joints.push_back( Join(6,8,cv::Scalar(0, 255, 0)) );

    joints.push_back( Join(3,9,cv::Scalar(255, 255, 0)) );
    joints.push_back( Join(9,10,cv::Scalar(255, 255, 0)) );
    joints.push_back( Join(4,11,cv::Scalar(255, 0, 255)) );
    joints.push_back( Join(11,12,cv::Scalar(255, 0, 255)) );

    joints.push_back( Join(8,15,cv::Scalar(0, 0, 255)) );
    joints.push_back( Join(15,16,cv::Scalar(0, 0, 255)) );

    joints.push_back( Join(7,13,cv::Scalar(255, 0, 0)) );
    joints.push_back( Join(13,14,cv::Scalar(255, 0, 0)) );

    for(int i=0; i < joints.size(); i++) {
      cv::Point a = ann[joints[i].part_a];
      cv::Point b = ann[joints[i].part_b];
      if(a.x >0 && b.x > 0 && a.y >0 && b.y > 0 && a.x < plot.cols && b.x < plot.cols ) {
        cv::line(plot, a, b, joints[i].color, 3);
      }
    }
    for (int i = 0; i < static_cast<int> (ann.size()); i++) {
      int x = ann[i].x;
      int y = ann[i].y;
      if (x > 0 and x < plot.cols and y > 0 and y < plot.rows) {
        if(i < 17){
          cv::circle(plot, cv::Point_<int>(x, y), 5, cv::Scalar(0, 0, 0, 0), -1 );
        }
        else if(i < 34){
          cv::circle(plot, cv::Point_<int>(x, y), 3, cv::Scalar(255, 0, 0, 0), -1 );
        }
        else{
          cv::circle(plot, cv::Point_<int>(x, y), 3, cv::Scalar(0, 0, 255, 0), -1 );
        }
      }
  //    rectangle(plot, ann.bbox, Scalar(0, 0, 255), 3);
    }

    if(path == "") {
      cv::imshow("Face", plot);
      cv::waitKey(wait);
    }else{
      cv::imshow("Check", plot);
      //cv::imwrite(path,plot);
    }
}

// displays the annotations
void inline plot(cv::Mat& img, std::vector<cv::Point> ann,
                 body_pose::BodyPoseTypes pose_type, std::string path = "", int wait = 0 ){

      if(pose_type == body_pose::FULL_BODY_J13 ||
            pose_type ==  body_pose::FULL_BODY_J13_TEMPORAL){
                  _plot(img, ann, path, wait);
      }
      else if(pose_type == body_pose::UPPER_BODY_J7){
        _plot_7(img, ann, path, wait);
      }
      else if(pose_type == body_pose::FULL_BODY_J14){
        _plot_14(img, ann, path, wait);
      }
      else if(pose_type == body_pose::FULL_BODY_J17){
        _plot_17(img, ann, path, wait);
      }
      else if(pose_type == body_pose::UPPER_BODY_J9){
        _plot_9(img, ann, path, wait);
      }

}

void inline _get_joint_constalation_J17(std::vector<int>& parents){
    parents.push_back(0);
    parents.push_back(0);
    parents.push_back(1);
    parents.push_back(2);
    parents.push_back(2);
    parents.push_back(2);
    parents.push_back(5);
    parents.push_back(6);
    parents.push_back(6);
    parents.push_back(3);
    parents.push_back(9);
    parents.push_back(4);
    parents.push_back(11);
    parents.push_back(7);
    parents.push_back(13);
    parents.push_back(8);
    parents.push_back(15);
}

void inline _get_joint_constalation_J14(std::vector<int>& parents){
    parents.push_back(0);
    parents.push_back(0);
    parents.push_back(1);
    parents.push_back(1);
    parents.push_back(2);
    parents.push_back(3);
    parents.push_back(2);
    parents.push_back(6);
    parents.push_back(3);
    parents.push_back(8);
    parents.push_back(4);
    parents.push_back(10);
    parents.push_back(5);
    parents.push_back(12);
}

void inline _get_joint_constalation_J13(std::vector<int>& parents){
    parents.push_back(0);
    parents.push_back(0);
    parents.push_back(0);
    parents.push_back(1);
    parents.push_back(2);
    parents.push_back(1);
    parents.push_back(5);
    parents.push_back(2);
    parents.push_back(7);
    parents.push_back(3);
    parents.push_back(9);
    parents.push_back(4);
    parents.push_back(11);
}

void inline _get_joint_constalation_J9(std::vector<int>& parents){

    // Normall Case
//    parents.push_back(0);
//    parents.push_back(0);
//    parents.push_back(0);
//    parents.push_back(1);
//    parents.push_back(2);
//    parents.push_back(1);
//    parents.push_back(5);
//    parents.push_back(2);
//    parents.push_back(7);

    // FixMe: Add a separate flag for TUM Kitchen Datasets
    // For MPII Cooking Dataset
    parents.push_back(0);
    parents.push_back(0);
    parents.push_back(0);
    parents.push_back(1);
    parents.push_back(3);
    parents.push_back(4);
    parents.push_back(2);
    parents.push_back(6);
    parents.push_back(7);

}

void inline _get_joint_constalation_J7(std::vector<int>& parents){
    parents.push_back(0);
    parents.push_back(0);
    parents.push_back(0);
    parents.push_back(1);
    parents.push_back(3);
    parents.push_back(2);
    parents.push_back(5);
}

void inline _get_joint_constalation_temporal(std::vector<int>& parents,
                          int nNeighbours) {

    static const int basic_parents[] = {0, 0, 0, 1, 2, 1, 5, 2, 7, 3, 9, 4, 11};

    int img_count = nNeighbours*2+1;
    for(int idx = 0; idx < img_count*13; idx++){

      int parent_id = 0;
      if(idx < 13){
        parent_id = basic_parents[idx];
      }
      else{
        parent_id = (idx%13);
      }

      parents.push_back(parent_id);

    }
}

void inline get_joint_constalation(std::vector<int>& parents,
                            body_pose::BodyPoseTypes pose_type,
                            int nNeigbours = 0) {

    switch(pose_type){
      case body_pose::FULL_BODY_J14:{
        _get_joint_constalation_J14(parents);
        break;
      }
      case body_pose::FULL_BODY_J13:{
        _get_joint_constalation_J13(parents);
        break;
      }
      case body_pose::FULL_BODY_J17:{
        _get_joint_constalation_J17(parents);
        break;
      }
      case body_pose::FULL_BODY_J13_TEMPORAL:{
        _get_joint_constalation_temporal(parents, nNeigbours);
      }
      case body_pose::UPPER_BODY_J7:{
        _get_joint_constalation_J7(parents);
        break;
      }
      case body_pose::UPPER_BODY_J9:{
        _get_joint_constalation_J9(parents);
        break;
      }
    }
}

void inline clean_annotations(const std::vector< Annotation>& annotations_org,
    std::vector< Annotation >& annotations) {
  for(int i=0; i < annotations_org.size(); i++) {
    bool all_parts_present = true;
    for(int j=0; j  < annotations_org[i].parts.size(); j++) {
      const cv::Point p = annotations_org[i].parts[j];
      if(p.x <= 0 || p.y <= 0 ) {
        all_parts_present = false;
      }
    }
    if(all_parts_present) {
      annotations.push_back(annotations_org[i]);
    }
  }
}

bool inline load_sequence_info(std::vector<SequenceInfo>& seq_infos, std::string url){
  if (boost::filesystem::exists(url.c_str())) {
    std::string filename(url.c_str());
    boost::iostreams::stream < boost::iostreams::file_source > file(
        filename.c_str());
    std::string line;
    while (std::getline(file, line)) {
      std::vector < std::string > strs;
      boost::split(strs, line, boost::is_any_of(" "));

      SequenceInfo info;
      info.path = strs[0];
      info.frame_count = boost::lexical_cast<int>(strs[1]);
      seq_infos.push_back(info);
    }
    return true;
  }
  return false;
}

/** The function takes the path to image index file and loads all image urls
 *  in a vector.
**/
bool inline load_images(std::vector<std::string>& images, std::string url) {
  if (boost::filesystem::exists(url.c_str())) {
    std::string filename(url.c_str());
    boost::iostreams::stream < boost::iostreams::file_source > file(
        filename.c_str());
    std::string line;
    while (std::getline(file, line)) {
      std::vector < std::string > strs;
      boost::split(strs, line, boost::is_any_of(" "));

      std::string path;

      path = strs[0];
      images.push_back(path);
    }
    return true;
  }
  std::cout << "file not found: " << url << std::endl;
  return false;
}

/** The function takes the path to image index file and loads the whole information
 into a vector of Annotation structure.
 The information contain url of the image, bounding box of the person and
 coordinates of the body joints.
**/
bool inline load_annotations(std::vector<Annotation>& annotations, std::string url, int cluster_id = -1) {
  if (boost::filesystem::exists(url.c_str())) {
    std::string filename(url.c_str());
    boost::iostreams::stream < boost::iostreams::file_source > file(
        filename.c_str());
    std::string line;
    while (std::getline(file, line)) {
      std::vector < std::string > strs;
      boost::split(strs, line, boost::is_any_of(" "));

      Annotation ann;

      ann.url = strs[0];

     // if (!boost::filesystem::exists(ann.url)){
     //   continue;
     // }

      ann.bbox.x = boost::lexical_cast<int>(strs[1]);
      ann.bbox.y = boost::lexical_cast<int>(strs[2]);
      ann.bbox.width = boost::lexical_cast<int>(strs[3]);
      ann.bbox.height = boost::lexical_cast<int>(strs[4]);

      ann.cluster_id = boost::lexical_cast<int>(strs[5]);

      if(cluster_id > 0){
        if(cluster_id != ann.cluster_id){
          continue;
        }
      }
      int num_points = boost::lexical_cast<int>(strs[6]);
      ann.parts.resize(num_points);
      for (int i = 0; i < num_points; i++) {
        ann.parts[i].x = boost::lexical_cast<int>(strs[7 + 2 * i]);
        ann.parts[i].y = boost::lexical_cast<int>(strs[8 + 2 * i]);
      }

      // check if more info is given in the annotation file
      // e.g. best scale of the image, any type of weight, etc.
      int rem = strs.size() - num_points*2 - 7;
      if(rem%2 == 0 && rem != 0){
        int index = num_points*2 + 7;
        for(int i=index; i<strs.size(); i=i+2){
          std::string flag = strs[i];
          if(!flag.compare("-bs"))
              ann.best_scale = boost::lexical_cast<double>(strs[i+1]);
          else if(!flag.compare("-w"))
              ann.weight = boost::lexical_cast<double>(strs[i+1]);
//          else
//              std::cout<<"WARNING: Unknown extra values exist in annotation file.";
          }
        }
      annotations.push_back(ann);

    }
    return true;
  }
  std::cout << "file not found: " << url << std::endl;
  return false;
}

bool inline load_annotations_temporal(std::vector<Annotation>& annotations, std::string url, int img_count = -1) {
  if (boost::filesystem::exists(url.c_str())) {
    std::string filename(url.c_str());
    boost::iostreams::stream < boost::iostreams::file_source > file(
        filename.c_str());
    std::string line;
    while (std::getline(file, line)) {
      std::vector < std::string > strs;
      boost::split(strs, line, boost::is_any_of(" "));

      if(strs.size() == NUM_ENTRIES){ //if file does not contain temporal annotations
          load_annotations(annotations, url);
          return true;
      }

      if(img_count < 1){
        img_count = strs.size()/NUM_ENTRIES;
      }

      Annotation ann;
      ann.url = strs[0];
      if (!boost::filesystem::exists(ann.url)){
        continue;
      }

      ann.bbox.x = boost::lexical_cast<int>(strs[1]);
      ann.bbox.y = boost::lexical_cast<int>(strs[2]);
      ann.bbox.width = boost::lexical_cast<int>(strs[3]);
      ann.bbox.height = boost::lexical_cast<int>(strs[4]);

      ann.cluster_id = boost::lexical_cast<int>(strs[5]);

      ann.nNeighbours = floor(img_count/2);

      for(int idx = 1; idx < img_count; idx++){

        std::string neig_url = strs[(idx*NUM_ENTRIES) + 0];

        cv::Rect neig_bbox;
        neig_bbox.x = boost::lexical_cast<int>(strs[(idx*NUM_ENTRIES) + 1]);
        neig_bbox.y = boost::lexical_cast<int>(strs[(idx*NUM_ENTRIES) + 2]);
        neig_bbox.width = boost::lexical_cast<int>(strs[(idx*NUM_ENTRIES) + 3]);
        neig_bbox.height = boost::lexical_cast<int>(strs[(idx*NUM_ENTRIES) + 4]);

        ann.neig_urls.push_back(neig_url);
        ann.neig_bboxs.push_back(neig_bbox);
      }

      int num_points = boost::lexical_cast<int>(strs[6]);

      ann.parts.resize(num_points*img_count);

      for(int idx = 0; idx < img_count; idx++){
        for (int i = 0; i < num_points; i++) {
            ann.parts[idx*num_points+i].x = boost::lexical_cast<int>(strs[(idx*NUM_ENTRIES) + 7 + 2 * i]);
            ann.parts[idx*num_points+i].y = boost::lexical_cast<int>(strs[(idx*NUM_ENTRIES) + 8 + 2 * i]);
//            std::cout<<i<<": ";
//            std::cout<<ann.parts[i].x<<" "<<ann.parts[i].y<<std::endl;
        }
      }
      annotations.push_back(ann);
    }
    return true;
  }
  std::cout << "file not found: " << url << std::endl;
  return false;
}

int inline get_upperbody_size( const std::vector<cv::Point> parts, body_pose::BodyPoseTypes pose_type ){

  cv::Point hip_center, shoulder_center;

  if(pose_type == body_pose::FULL_BODY_J13 || pose_type == body_pose::UPPER_BODY_J9){

    if( parts[4].x < 0 ||
        parts[3].x < 0 ||
        parts[2].x < 0 ||
        parts[1].x < 0) {
      return -1;
    }
    hip_center.x = (parts[4].x+ parts[3].x) /2;
    hip_center.y = (parts[4].y+ parts[3].y) /2;
    shoulder_center.x = (parts[2].x+ parts[1].x) /2;
    shoulder_center.y = (parts[2].y+ parts[1].y) /2;
  }
  else if(pose_type == body_pose::FULL_BODY_J14){
    if( parts[5].x < 0 ||
        parts[4].x < 0 ||
        parts[3].x < 0 ||
        parts[2].x < 0) {
      return -1;
    }
    hip_center.x = (parts[5].x+ parts[4].x) /2;
    hip_center.y = (parts[5].y+ parts[4].y) /2;
    shoulder_center.x = (parts[3].x+ parts[2].x) /2;
    shoulder_center.y = (parts[3].y+ parts[2].y) /2;
  }
  else if(pose_type == body_pose::FULL_BODY_J17){
      if( parts[8].x < 0 ||
        parts[7].x < 0 ||
        parts[4].x < 0 ||
        parts[3].x < 0) {
      return -1;
    }
    hip_center.x = (parts[7].x+ parts[8].x) /2;
    hip_center.y = (parts[7].y+ parts[8].y) /2;
    shoulder_center.x = (parts[4].x+ parts[3].x) /2;
    shoulder_center.y = (parts[4].y+ parts[3].y) /2;
  }

  return std::sqrt( (hip_center.x-shoulder_center.x)*(hip_center.x-shoulder_center.x) +
      (hip_center.y-shoulder_center.y)*(hip_center.y-shoulder_center.y) );
}

void inline get_limb_sizes(Annotation ann, std::vector<int>& selected_parts, std::vector<int>& parents,
               std::vector<int>& limb_sizes)
{
  for(unsigned int idx = 0; idx < selected_parts.size(); idx++){
    int part_id = selected_parts[idx];
    int parent = parents[part_id];
    cv::Point parent_loc = ann.parts[parent];
    cv::Point part_loc = ann.parts[part_id];

    int size = 0;
    if(part_loc.x < 0 || part_loc.y < 0 ||
       parent_loc.x < 0 || parent_loc.y < 0){
       size = -1;
    }else {
       size = ceil(std::sqrt( (parent_loc.x-part_loc.x)*(parent_loc.x-part_loc.x) +
            (parent_loc.y-part_loc.y)*(parent_loc.y-part_loc.y) ));
    }
    limb_sizes.push_back(size);
  }
}

float inline get_body_scale_factor(const Annotation ann){

  body_pose::BodyPoseTypes pose_type = body_pose::FULL_BODY_J13;

  std::vector<int> selected_parts;
  selected_parts += 1,2,3,4,5,6,7,8,9,10,11,12;

  std::vector<int> norm_sizes;
  norm_sizes  += 23,23,50,50,21,21,21,21,34, 34, 32, 32;

  std::vector<int> parents;
  get_joint_constalation(parents, pose_type);

  std::vector<int> limb_sizes;
  std::vector<float> scales(norm_sizes.size());

  get_limb_sizes(ann, selected_parts, parents, limb_sizes);

  for(unsigned int i=0; i<limb_sizes.size(); i++){
    scales[i] = static_cast<float>(norm_sizes[i])/limb_sizes[i];
  }

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

  float scale = scales[scales.size()/2];

  return scale;
}

int inline get_upperbody_size( const Annotation ann, body_pose::BodyPoseTypes pose_type ){
  return get_upperbody_size(ann.parts, pose_type);
}

int inline get_upperbody_size_temporal( const std::vector<cv::Point> parts, int nNeighbours){

  int img_count = nNeighbours*2+1;

  for(int idx = 0; idx < img_count; idx++){
    if( parts[idx*13+4].x < 0 ||
        parts[idx*13+3].x < 0 ||
        parts[idx*13+2].x < 0 ||
        parts[idx*13+1].x < 0) {
          return -1;
      }
  }

  int body_size = 0;

  for(int idx = 0; idx < img_count; idx++){
    cv::Point hip_center;
    hip_center.x = (parts[idx*13+4].x+ parts[idx*13+3].x) /2;
    hip_center.y = (parts[idx*13+4].y+ parts[idx*13+3].y) /2;
    cv::Point shoulder_center;
    shoulder_center.x = (parts[idx*13+2].x+ parts[idx*13+1].x) /2;
    shoulder_center.y = (parts[idx*13+2].y+ parts[idx*13+1].y) /2;

    body_size += std::sqrt( (hip_center.x-shoulder_center.x)*(hip_center.x-shoulder_center.x) +
      (hip_center.y-shoulder_center.y)*(hip_center.y-shoulder_center.y) );
  }

  body_size /= img_count; // average body size of all frames

  return body_size;
}

int inline get_upperbody_size_temporal( const Annotation ann ){

  return get_upperbody_size_temporal(ann.parts, ann.nNeighbours);
}

#endif /* COMMON_HPP_ */


text:
#include "dir/file.h"

#include "../mck/dir/fileMock.h"

#include <gtest/gtest.h>

#include <boost/filesystem.hpp>

namespace dir {

TEST(fileTest, square) {
    EXPECT_EQ(square(2), 4);
    EXPECT_EQ(square(3), 9);
    ;
}

TEST(fileTest, filesystem) {
    EXPECT_TRUE(boost::filesystem::is_regular_file(PROJECT_DIR "/CMakeLists.txt"));
}

using ::testing::Return;
TEST(fileTest, mocking) {
    const ::dir::mck::InterfaceMock interface;
    EXPECT_CALL(interface, function(3)).WillOnce(Return("some 3"));
    EXPECT_EQ(interface.function(3), "some 3");
}
}

ext: cpp


text:
#include <iostream>
#include <algorithm>
#include <iterator>
#include <cmath>

#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/io.hpp>
#include <boost/math/constants/constants.hpp>

#include "miMaS/field.h"
#include "miMaS/weno.h"
#include "miMaS/fft.h"
#include "miMaS/array_view.h"
#include "miMaS/poisson.h"

namespace math = boost::math::constants;

int main(int,char**)
{
	std::size_t Nx = 125, Nv = 64;
	field<double,1> f(boost::extents[Nv][Nx]);

	f.range.v_min = 0.; f.range.v_max = 2.*math::pi<double>();
	f.step.dv = (f.range.v_max-f.range.v_min)/Nv;
	f.range.x_min = 0.; f.range.x_max = 1.;
	f.step.dx = (f.range.x_max-f.range.x_min)/Nx;
	double dt = 0.5*f.step.dv;

  field<double,1> f_sol = f;

	ublas::vector<double> E (Nx);
  for ( std::size_t i=0 ; i<Nx ; ++i ) { E[i] = 1.; }

#define X(i) (i*f.step.dx+f.range.x_min)
#define V(k) (k*f.step.dv+f.range.v_min)
  for (field<double,2>::size_type k=0 ; k<f.size(0) ; ++k ) {
    for (field<double,2>::size_type i=0 ; i<f.size(1) ; ++i ) {
      f[k][i] = cos(V(k));
      f_sol[k][i] = cos(V(k)-dt*20);
    }
  }
#undef X
  f.write("init.dat");

  for ( auto t=0 ; t<20 ; ++t ) {
  	if (t%32==0) { std::cout<<"\r"<<t<<" "<<std::flush ; }
	  field<double,1> Edvf = weno::trp_v(f,E);

    for ( auto k=0 ; k<f.size(0) ; ++k ) {
      for ( auto i=0 ; i<f.size(1) ; ++i ) {
        f[k][i] = f[k][i] - dt*Edvf[k][i];
      }
    }
  }

  f_sol.write("sol.dat");
  f.write("vp.dat");

  return 0;
}

ext: cc

max_stars_repo_name: kivvix/vlasovpp

max_issues_repo_name: kivvix/vlasovpp

max_forks_repo_name: kivvix/vlasovpp


text:
//               Copyright Marek Dalewski 2017
// Distributed under the Boost Software License, Version 1.0.
//        (See accompanying file LICENSE.md or copy at
//           http://www.boost.org/LICENSE_1_0.txt)

#include <commander/algorithm.hpp>

#include <boost/test/unit_test.hpp>

#include <tuple>
#include <utility>
#include <vector>

BOOST_AUTO_TEST_CASE( tuple_visit_conjunction )
{
    std::vector<std::tuple<bool, uint32_t>> results;

    auto call_always_true = [&results](const auto& item) -> bool {
        results.emplace_back(true, item);
        return true;
    };
    auto call_not_4 = [&results](const auto& item) -> bool {
        results.emplace_back((uint32_t(item) != 4), item);
        return (uint32_t(item) != 4);
    };
    auto call_not_6 = [&results](const auto& item) -> bool {
        results.emplace_back((uint32_t(item) != 6), item);
        return (uint32_t(item) != 6);
    };

    std::tuple<uint8_t, uint16_t, uint32_t> tuple_of_ints   = {0, 1, 2};
    std::tuple<float, double, long double>  tuple_of_floats = {3.3, 4.4, 5.5};
    std::tuple<uint64_t>                    tuple_uint64_t  = {6};

    {
        results.clear();
        BOOST_CHECK(commander::tuple_visit_conjunction(call_always_true, tuple_of_ints) == true);
        BOOST_CHECK(results.size() == 3);
        BOOST_CHECK(results.at(0) == std::forward_as_tuple(true, 0));
        BOOST_CHECK(results.at(1) == std::forward_as_tuple(true, 1));
        BOOST_CHECK(results.at(2) == std::forward_as_tuple(true, 2));

        results.clear();
        BOOST_CHECK(commander::tuple_visit_conjunction(call_always_true, tuple_of_ints, tuple_of_floats) == true);
        BOOST_CHECK(results.size() == 6);
        BOOST_CHECK(results.at(0) == std::forward_as_tuple(true, 0));
        BOOST_CHECK(results.at(1) == std::forward_as_tuple(true, 1));
        BOOST_CHECK(results.at(2) == std::forward_as_tuple(true, 2));
        BOOST_CHECK(results.at(3) == std::forward_as_tuple(true, 3));
        BOOST_CHECK(results.at(4) == std::forward_as_tuple(true, 4));
        BOOST_CHECK(results.at(5) == std::forward_as_tuple(true, 5));
    }

    {
        results.clear();
        BOOST_CHECK(commander::tuple_visit_conjunction(call_not_4, tuple_of_ints) == true);
        BOOST_CHECK(results.size() == 3);
        BOOST_CHECK(results.at(0) == std::forward_as_tuple(true, 0));
        BOOST_CHECK(results.at(1) == std::forward_as_tuple(true, 1));
        BOOST_CHECK(results.at(2) == std::forward_as_tuple(true, 2));

        results.clear();
        BOOST_CHECK(commander::tuple_visit_conjunction(call_not_4, tuple_of_ints, tuple_of_floats) == false);
        BOOST_CHECK(results.size() == 5);
        BOOST_CHECK(results.at(0) == std::forward_as_tuple(true, 0));
        BOOST_CHECK(results.at(1) == std::forward_as_tuple(true, 1));
        BOOST_CHECK(results.at(2) == std::forward_as_tuple(true, 2));
        BOOST_CHECK(results.at(3) == std::forward_as_tuple(true, 3));
        BOOST_CHECK(results.at(4) == std::forward_as_tuple(false, 4));
    }

    {
        results.clear();
        BOOST_CHECK(commander::tuple_visit_conjunction(call_always_true, tuple_uint64_t) == true);
        BOOST_CHECK(results.size() == 1);
        BOOST_CHECK(results.at(0) == std::forward_as_tuple(true, 6));

        results.clear();
        BOOST_CHECK(commander::tuple_visit_conjunction(call_always_true, tuple_uint64_t, tuple_of_ints) == true);
        BOOST_CHECK(results.size() == 4);
        BOOST_CHECK(results.at(0) == std::forward_as_tuple(true, 6));
        BOOST_CHECK(results.at(1) == std::forward_as_tuple(true, 0));
        BOOST_CHECK(results.at(2) == std::forward_as_tuple(true, 1));
        BOOST_CHECK(results.at(3) == std::forward_as_tuple(true, 2));

        results.clear();
        BOOST_CHECK(commander::tuple_visit_conjunction(call_always_true, tuple_of_ints, tuple_uint64_t) == true);
        BOOST_CHECK(results.size() == 4);
        BOOST_CHECK(results.at(0) == std::forward_as_tuple(true, 0));
        BOOST_CHECK(results.at(1) == std::forward_as_tuple(true, 1));
        BOOST_CHECK(results.at(2) == std::forward_as_tuple(true, 2));
        BOOST_CHECK(results.at(3) == std::forward_as_tuple(true, 6));
    }

    {
        results.clear();
        BOOST_CHECK(commander::tuple_visit_conjunction(call_not_6, tuple_uint64_t) == false);
        BOOST_CHECK(results.size() == 1);
        BOOST_CHECK(results.at(0) == std::forward_as_tuple(false, 6));

        results.clear();
        BOOST_CHECK(commander::tuple_visit_conjunction(call_not_6, tuple_uint64_t, tuple_of_ints) == false);
        BOOST_CHECK(results.size() == 1);
        BOOST_CHECK(results.at(0) == std::forward_as_tuple(false, 6));

        results.clear();
        BOOST_CHECK(commander::tuple_visit_conjunction(call_not_6, tuple_of_ints, tuple_uint64_t) == false);
        BOOST_CHECK(results.size() == 4);
        BOOST_CHECK(results.at(0) == std::forward_as_tuple(true, 0));
        BOOST_CHECK(results.at(1) == std::forward_as_tuple(true, 1));
        BOOST_CHECK(results.at(2) == std::forward_as_tuple(true, 2));
        BOOST_CHECK(results.at(3) == std::forward_as_tuple(false, 6));
    }
}

max_stars_repo_name: daishe/commander

max_issues_repo_name: daishe/commander

max_forks_repo_name: daishe/commander


text:
#include "amqp_consumer.hpp"

#include <boost/format.hpp>

using namespace components;

std::string bytes_to_str(const amqp_bytes_t& bytes) {
    if (!bytes.len) {
        return "";
    }
    return static_cast<char*>(bytes.bytes);
}

std::string amqp_consumer::get_host() const {
    if (_url.host().size()) {
        return _url.host();
    }
    return "localhost";
}

int amqp_consumer::get_port() const {
    std::string port{_url.port()};
    if (port.size()) {
        return stoi(port);
    }
    return 5672;
}

std::string amqp_consumer::get_user() const {
    if (_url.user().size()) {
        return _url.user();
    }
    return "guest";
}

std::string amqp_consumer::get_password() const {
    if (_url.password().size()) {
        return _url.password();
    }
    return "guest";
}

amqp_err_reply amqp_consumer::get_amqp_error_reply(const amqp_rpc_reply_t& reply) const {
    auto* raw = static_cast<amqp_connection_close_t*>(reply.reply.decoded);
    return amqp_err_reply{raw->reply_code, static_cast<char*>(raw->reply_text.bytes)};
}

void amqp_consumer::throw_on_amqp_error(const amqp_rpc_reply_t& reply, const std::string& context) const {
    switch (reply.reply_type) {
        case AMQP_RESPONSE_NORMAL:
            return;

        case AMQP_RESPONSE_NONE:
            throw std::runtime_error((boost::format("%s: missing RPC reply type!") % context).str());
            break;

        case AMQP_RESPONSE_LIBRARY_EXCEPTION:
            throw std::runtime_error((boost::format("%s: %s") % context % amqp_error_string2(reply.library_error)).str());
            break;

        case AMQP_RESPONSE_SERVER_EXCEPTION:
            switch (reply.reply.id) {
                case AMQP_CONNECTION_CLOSE_METHOD: {
                    auto err_reply = get_amqp_error_reply(reply);
                    throw std::runtime_error((boost::format("%s: server connection error %u, message: %s") %
                                    context % err_reply.code % err_reply.text).str());
                    break;
                }
                case AMQP_CHANNEL_CLOSE_METHOD: {
                    auto err_reply = get_amqp_error_reply(reply);
                    throw std::runtime_error((boost::format("%s: server channel error %u, message: %s") %
                                    context % err_reply.code % err_reply.text).str());
                    break;
                }
                default:
                    throw std::runtime_error((boost::format("%s: unknown server error, method id 0x%08X") %
                                    context % reply.reply.id).str());
                    break;
            }
            break;
    }
}

const amqp_table_entry_t* amqp_consumer::get_amqp_entry_by_key(const amqp_table_t& table, const std::string& key) {
    assert(table != nullptr);
    for (int i = 0; i < table.num_entries; ++i) {
        if (bytes_to_str(table.entries[i].key) == key) {
            return &table.entries[i];
        }
    }
    return nullptr;
}

const amqp_bytes_t& amqp_consumer::get_amqp_value_bytes(const amqp_field_value_t& value) const {
    return value.value.bytes;
}

amqp_consumer::amqp_consumer(const std::string& url, std::string queue, std::string exchange, std::string binding_key)
        : _url(url), _log(get_logger()) {
    if (_url.scheme() != "amqp") {
        throw std::runtime_error("URL scheme must be: amqp, provided: " + std::string{_url.scheme()});
    }

    _conn = amqp_new_connection();
    _socket = amqp_tcp_socket_new(_conn);
    if (!_socket) {
        throw std::runtime_error("Cannot create socket");
    }

    int error = 0;
    error = amqp_socket_open(_socket, get_host().c_str(), get_port());
    if (error) {
        throw std::runtime_error("Cannot connect to " + get_host() + ":" + std::to_string(get_port()));
    }

    throw_on_amqp_error(amqp_login(_conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, get_user().c_str(), get_password().c_str()), "Cannot login");

    amqp_channel_open(_conn, 1);
    throw_on_amqp_error(amqp_get_rpc_reply(_conn), "Cannot open channel");

    amqp_queue_declare_ok_t* declared = amqp_queue_declare(
        _conn, 1, amqp_cstring_bytes(queue.c_str()), false, true, false, false, amqp_empty_table);
    throw_on_amqp_error(amqp_get_rpc_reply(_conn), "Cannot declare queue");

    _queuename = amqp_bytes_malloc_dup(declared->queue);

    amqp_queue_bind(_conn, 1, _queuename, amqp_cstring_bytes(exchange.c_str()),
        amqp_cstring_bytes(binding_key.c_str()), amqp_empty_table);
    throw_on_amqp_error(amqp_get_rpc_reply(_conn), "Cannot bind queue");

    amqp_basic_consume(_conn, 1, _queuename, amqp_empty_bytes, false, true, false,
        amqp_empty_table);
    throw_on_amqp_error(amqp_get_rpc_reply(_conn), "Cannot consume queue");

    _log.info("Connected to " + get_host() + ":" + std::to_string(get_port()) + " and listening");
    _log.info("queue=" + queue + ", exchange=" + exchange + ", key=" + binding_key);
}

void amqp_consumer::start_loop() {
    if (!on_task) {
        throw std::runtime_error("No on_task handler set");
    }
    while (true) {
        amqp_rpc_reply_t ret;
        amqp_envelope_t envelope;

        amqp_maybe_release_buffers(_conn);
        ret = amqp_consume_message(_conn, &envelope, nullptr, 0);
        if (ret.reply_type != AMQP_RESPONSE_NORMAL) {
            amqp_bytes_free(_queuename);
            amqp_channel_close(_conn, 1, AMQP_REPLY_SUCCESS);
            amqp_connection_close(_conn, AMQP_REPLY_SUCCESS);
            amqp_destroy_connection(_conn);
            break;
        }

        auto ignore_msg_with_err = [&](const std::string& err) {
            _log.error(err);
            amqp_destroy_envelope(&envelope);
        };

        const auto& msg = envelope.message;

        const auto* task_en = get_amqp_entry_by_key(msg.properties.headers, "task");
        if (task_en == nullptr) {
            ignore_msg_with_err("Wrong message: no task property"); continue;
        }
        auto task = bytes_to_str(get_amqp_value_bytes(task_en->value));
        if (!task.size()) {
            ignore_msg_with_err("Wrong message: task property is empty"); continue;
        }

        //_log.info(bytes_to_str(msg.properties.content_type));

        auto body = bytes_to_str(msg.body);

        on_task(task, body);

        amqp_destroy_envelope(&envelope);
    }
}

max_stars_repo_name: cyberduckninja/RocketJoe

max_issues_repo_name: cyberduckninja/RocketJoe

max_forks_repo_name: cyberduckninja/RocketJoe


text:
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// 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)
//
// Official repository: https://github.com/CPPAlliance/url
//

#ifndef BOOST_URL_GRAMMAR_IMPL_PARSE_HPP
#define BOOST_URL_GRAMMAR_IMPL_PARSE_HPP

#include <boost/url/detail/except.hpp>
#include <boost/url/grammar/error.hpp>
#include <utility>

namespace boost {
namespace urls {
namespace grammar {

inline
void
tag_invoke(
    parse_tag const&,
    char const*& it,
    char const* const end,
    error_code& ec,
    char ch) noexcept
{
    if(it == end)
    {
        // end of input
        ec = error::incomplete;
        return;
    }
    if(*it != ch)
    {
        // expected ch
        ec = error::syntax;
        return;
    }
    ++it;
}

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

namespace detail {

inline
void
parse_impl(
    char const*&,
    char const*,
    error_code&) noexcept
{
}

// this is here to avoid
// having to clear `ec`
// for every call
template<
    class R0,
    class... Rn>
void
parse_impl(
    char const*& it,
    char const* const end,
    error_code& ec,
    R0&& r0,
    Rn&&... rn)
{
    using grammar::tag_invoke;
    tag_invoke(
        parse_tag{},
        it, end, ec,
        std::forward<R0>(r0));
    if(ec.failed())
        return;
    parse_impl(
        it, end, ec,
        std::forward<Rn>(rn)...);
}

} // detail

template<class... Rn>
bool
parse(
    char const*& it,
    char const* const end,
    error_code& ec,
    Rn&&... rn)
{
    ec = {};
    detail::parse_impl(
        it, end, ec,
        std::forward<Rn>(rn)...);
    return ! ec.failed();
}

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

template<class... Rn>
bool
parse_all(
    char const*& it,
    char const* const end,
    error_code& ec,
    Rn&&... rn)
{
    auto const it0 = it;
    if(! (parse)(it, end, ec,
        std::forward<Rn>(rn)...))
    {
        it = it0;
        return false;
    }
    return true;
}

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

template<class... Rn>
bool
parse_string(
    string_view s,
    error_code& ec,
    Rn&&... rn)
{
    auto it = s.data();
    auto const end = it + s.size();
    if(! (parse)(it, end, ec,
        std::forward<Rn>(rn)...))
        return false;
    if(it != end)
    {
        // input not consumed fully
        ec = error::leftover;
        return false;
    }
    return true;
}

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

template<class... Rn>
void
parse_string(
    string_view s,
    Rn&&... rn)
{
    error_code ec;
    if(! parse_string(s, ec,
        std::forward<Rn>(rn)...))
    {
        urls::detail::throw_system_error(
            ec, BOOST_CURRENT_LOCATION);
    }
    BOOST_ASSERT(! ec.failed());
}

} // grammar
} // urls
} // boost

#endif

ext: hpp

max_stars_repo_name: vgrigoriu/url

max_issues_repo_name: vgrigoriu/url

max_forks_repo_name: vgrigoriu/url


text:
/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2018 Sylko Olzscher
 *
 */

#include "forwarder.h"
#include "../../shared/db/db_schemes.h"
#include <smf/cluster/generator.h>
#include <cyng/table/key.hpp>
#include <cyng/io/serializer.h>
#include <cyng/vector_cast.hpp>
#include <cyng/tuple_cast.hpp>
#include <cyng/parser/buffer_parser.h>
#include <cyng/parser/mac_parser.h>
#include <cyng/xml.h>
#include <cyng/csv.h>

#include <boost/algorithm/string.hpp>
#include <boost/uuid/string_generator.hpp>
#include <boost/uuid/nil_generator.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/core/ignore_unused.hpp>

namespace node
{
	void fwd_insert(cyng::logging::log_ptr logger
		, cyng::context& ctx
		, cyng::reader<cyng::object> const& reader
		, boost::uuids::uuid tag)
	{
		//	{"cmd":"insert","channel":"config.device","rec":{"key":{"pk":"0b5c2a64-5c48-48f1-883b-e5be3a3b1e3d"},"data":{"name":"demo","msisdn":"demo","descr":"comment #55","enabled":true,"pwd":"secret","age":"2018-02-04T14:31:34.000Z"}}}
		const std::string channel = cyng::value_cast<std::string>(reader.get("channel"), "");
		CYNG_LOG_TRACE(logger, "ws.read - insert channel [" << channel << "]");
		if (boost::algorithm::starts_with(channel, "config.device"))
		{
			ctx.queue(bus_req_db_insert("TDevice"
				//	generate new key
				, cyng::table::key_generator(tag)
				//	build data vector
				, cyng::vector_t{ reader["rec"]["data"].get("name")
				, reader["rec"]["data"].get("pwd")
				, reader["rec"]["data"].get("msisdn")
				, reader["rec"]["data"].get("descr")
				, cyng::make_object("")	//	model
				, cyng::make_object("")	//	version
				, reader["rec"]["data"].get("enabled")
				, cyng::make_now()
				, cyng::make_object(static_cast<std::uint32_t>(6)) }
				, 0
				, ctx.tag()));
		}
		else
		{
			CYNG_LOG_WARNING(logger, "ws.read - unknown insert channel [" << channel << "]");
		}
	}

	void fwd_delete(cyng::logging::log_ptr logger
		, cyng::context& ctx
		, cyng::reader<cyng::object> const& reader)
	{
		//	[ce28c0c4-1914-45d1-bcf1-22bcbe461855,{("cmd":delete),("channel":config.device),("key":{("tag":a8b3d691-6ea9-40d3-83aa-b1e4dfbcb2f1)})}]
		const std::string channel = cyng::value_cast<std::string>(reader.get("channel"), "");
		CYNG_LOG_TRACE(logger, "ws.read - delete channel [" << channel << "]");
		if (boost::algorithm::starts_with(channel, "config.device"))
		{
			//
			//	TDevice key is of type UUID
			//
			try {
				cyng::vector_t vec;
				vec = cyng::value_cast(reader["key"].get("tag"), vec);
				BOOST_ASSERT_MSG(vec.size() == 1, "TDevice key has wrong size");
				auto key = cyng::table::key_generator(vec.at(0));
				ctx.queue(bus_req_db_remove("TDevice", key, ctx.tag()));
			}
			catch (std::exception const& ex) {
				CYNG_LOG_ERROR(logger, "ws.read - delete channel ["
					<< channel
					<< "] failed: "
					<< ex.what());
			}
		}
		else if (boost::algorithm::starts_with(channel, "config.gateway"))
		{
			//
			//	TGateway key is of type UUID
			//
			try {
				cyng::vector_t vec;
				vec = cyng::value_cast(reader["key"].get("tag"), vec);
				BOOST_ASSERT_MSG(vec.size() == 1, "TGateway key has wrong size");
				auto key = cyng::table::key_generator(vec.at(0));
				ctx.queue(bus_req_db_remove("TGateway", key, ctx.tag()));
			}
			catch (std::exception const& ex) {
				CYNG_LOG_ERROR(logger, "ws.read - delete channel ["
					<< channel
					<< "] failed: "
					<< ex.what());
			}
		}
		else if (boost::algorithm::starts_with(channel, "config.meter"))
		{
			//
			//	TDevice key is of type UUID
			//
			try {
				cyng::vector_t vec;
				vec = cyng::value_cast(reader["key"].get("tag"), vec);
				BOOST_ASSERT_MSG(vec.size() == 1, "TMeter key has wrong size");
				auto key = cyng::table::key_generator(vec.at(0));
				ctx.queue(bus_req_db_remove("TMeter", key, ctx.tag()));
			}
			catch (std::exception const& ex) {
				CYNG_LOG_ERROR(logger, "ws.read - delete channel ["
					<< channel
					<< "] failed: "
					<< ex.what());
			}
		}
		else if (boost::algorithm::starts_with(channel, "config.lora"))
		{
			//
			//	TLoRaDevice key is of type UUID
			//
			try {
				cyng::vector_t vec;
				vec = cyng::value_cast(reader["key"].get("tag"), vec);
				BOOST_ASSERT_MSG(vec.size() == 1, "TLoRaDevice key has wrong size");
				auto key = cyng::table::key_generator(vec.at(0));
				ctx.queue(bus_req_db_remove("TLoRaDevice", key, ctx.tag()));
			}
			catch (std::exception const& ex) {
				CYNG_LOG_ERROR(logger, "ws.read - delete channel ["
					<< channel
					<< "] failed: "
					<< ex.what());
			}
		}
		else
		{
			CYNG_LOG_WARNING(logger, "ws.read - unknown delete channel [" << channel << "]");
		}
	}

	void fwd_modify(cyng::logging::log_ptr logger
		, cyng::context& ctx
		, cyng::reader<cyng::object> const& reader)
	{
		const std::string channel = cyng::value_cast<std::string>(reader.get("channel"), "");
		CYNG_LOG_TRACE(logger, "ws.read - modify channel [" << channel << "]");
		if (boost::algorithm::starts_with(channel, "config.device"))
		{
			//
			//	TDevice key is of type UUID
			//	all values have the same key
			//
			try {

				cyng::vector_t vec;
				vec = cyng::value_cast(reader["rec"].get("key"), vec);
				BOOST_ASSERT_MSG(vec.size() == 1, "TDevice key has wrong size");

				//const std::string str = cyng::value_cast<std::string>(vec.at(0), "");
				//CYNG_LOG_DEBUG(logger, "TDevice key [" << str << "]");
				//auto key = cyng::table::key_generator(boost::uuids::string_generator()(str));
				auto key = cyng::table::key_generator(vec.at(0));

				cyng::tuple_t tpl;
				tpl = cyng::value_cast(reader["rec"].get("data"), tpl);
				for (auto p : tpl)
				{
					cyng::param_t param;
					ctx.queue(bus_req_db_modify("TDevice"
						, key
						, cyng::value_cast(p, param)
						, 0
						, ctx.tag()));
				}
			}
			catch (std::exception const& ex) {
				CYNG_LOG_ERROR(logger, "ws.read - modify channel ["
					<< channel <<
					"] failed:"
					<< ex.what());
			}
		}
		else if (boost::algorithm::starts_with(channel, "config.gateway"))
		{
			//
			//	TGateway key is of type UUID
			//	all values have the same key
			//
			try {

				cyng::vector_t vec;
				vec = cyng::value_cast(reader["rec"].get("key"), vec);
				BOOST_ASSERT_MSG(vec.size() == 1, "TGateway key has wrong size");
				auto key = cyng::table::key_generator(vec.at(0));

				cyng::tuple_t tpl;
				tpl = cyng::value_cast(reader["rec"].get("data"), tpl);
				for (auto p : tpl)
				{
					cyng::param_t param;
					param = cyng::value_cast(p, param);

					if (boost::algorithm::equals(param.first, "serverId")) {
						//
						//	to uppercase
						//
						std::string server_id;
						server_id = cyng::value_cast(param.second, server_id);
						boost::algorithm::to_upper(server_id);
						ctx.queue(bus_req_db_modify("TGateway"
							, key
							, cyng::param_factory("serverId", server_id)
							, 0
							, ctx.tag()));
					}
					else {
						ctx.queue(bus_req_db_modify("TGateway"
							, key
							, cyng::value_cast(p, param)
							, 0
							, ctx.tag()));
					}
				}
			}
			catch (std::exception const& ex) {
				CYNG_LOG_ERROR(logger, "ws.read - modify channel ["
					<< channel
					<< "] failed: "
					<< ex.what());
			}
		}
		else if (boost::algorithm::starts_with(channel, "config.system"))
		{
			//	{"cmd":"modify","channel":"config.system","rec":{"key":{"name":"connection-auto-login"},"data":{"value":true}}}
			const std::string name = cyng::value_cast<std::string>(reader["rec"]["key"].get("name"), "?");
			const cyng::object value = reader["rec"]["data"].get("value");
			ctx.queue(bus_req_db_modify("_Config"
				//	generate new key
				, cyng::table::key_generator(reader["rec"]["key"].get("name"))
				//	build parameter
				, cyng::param_t("value", value)
				, 0
				, ctx.tag()));

			std::stringstream ss;
			ss
				<< "system configuration changed "
				<< name
				<< " ["
				<< value.get_class().type_name()
				<< "] = "
				<< cyng::io::to_str(value)
				;

			ctx.queue(bus_insert_msg(cyng::logging::severity::LEVEL_WARNING, ss.str()));

		}
		else if (boost::algorithm::starts_with(channel, "config.meter"))
		{
			try {

				cyng::vector_t vec;
				vec = cyng::value_cast(reader["rec"].get("key"), vec);
				BOOST_ASSERT_MSG(vec.size() == 1, "TMeter key has wrong size");

				//const std::string str = cyng::value_cast<std::string>(vec.at(0), "");
				//CYNG_LOG_DEBUG(logger, "TDevice key [" << str << "]");
				//auto key = cyng::table::key_generator(boost::uuids::string_generator()(str));
				auto key = cyng::table::key_generator(vec.at(0));

				cyng::tuple_t tpl;
				tpl = cyng::value_cast(reader["rec"].get("data"), tpl);
				for (auto p : tpl)
				{
					cyng::param_t param;
					ctx.queue(bus_req_db_modify("TMeter"
						, key
						, cyng::value_cast(p, param)
						, 0
						, ctx.tag()));
				}
			}
			catch (std::exception const& ex) {
				CYNG_LOG_ERROR(logger, "ws.read - modify channel ["
					<< channel <<
					"] failed:"
					<< ex.what());
			}
		}
		else if (boost::algorithm::starts_with(channel, "config.lora"))
		{
			try {

				//	smf-form-lora-pk=96c24827-2847-4612-9982-ab5cb1e8dee7&smf-form-lora-address=&smf-form-lora-appuid=&smf-form-lora-gwuid=&smf-form-lora-DevEUI=0100%3A0302%3A0504%3A0706&smf-form-lora-aes=0000000000000000000000000000000000000000000000000000000000000000&smf-form-lora-driver%20=raw&smf-form-lora-activation=on&smf-form-lora-devaddr=&smf-form-lora-appeui=&smf-form-lora-gweui=
				//	 {"cmd":"modify","channel":"config.lora","rec":{"key":["96c24827-2847-4612-9982-ab5cb1e8dee7"],"data":{"DevEUI":"0100:0302:0504:0706","AESKey":"0000000000000000000000000000000000000000000000000000000000000000","driver":"raw","activation":"ABP","DevAddr":"20","AppEUI":"0100:0302:0604:0807","GatewayEUI":"0100:0302:0604:0807"}}}

				cyng::vector_t vec;
				vec = cyng::value_cast(reader["rec"].get("key"), vec);
				BOOST_ASSERT_MSG(vec.size() == 1, "TLoRaDevice key has wrong size");

				auto key = cyng::table::key_generator(vec.at(0));

				cyng::tuple_t tpl;
				tpl = cyng::value_cast(reader["rec"].get("data"), tpl);
				for (auto p : tpl)
				{
					cyng::param_t param;
					param = cyng::value_cast(p, param);

					if (boost::algorithm::equals(param.first, "activation")) {

						//
						//	convert value from radion button into bool
						//	OTAA == true
						//	ABP == false
						//
						auto const activation = cyng::value_cast<std::string>(reader["rec"]["data"].get("activation"), "OTAA");

						ctx.queue(bus_req_db_modify("TLoRaDevice"
							, key
							, cyng::param_factory(param.first, boost::algorithm::equals(activation, "OTAA"))
							, 0
							, ctx.tag()));

					}
					else if (boost::algorithm::equals(param.first, "DevEUI")) {

						//
						//	convert value to mac64
						//
						auto const eui = cyng::value_cast<std::string>(reader["rec"]["data"].get(param.first), "0000:0000:0000:0000");
						std::pair<cyng::mac64, bool > r = cyng::parse_mac64(eui);
						if (r.second) {
							ctx.queue(bus_req_db_modify("TLoRaDevice"
								, key
								, cyng::param_factory(param.first, r.first)
								, 0
								, ctx.tag()));
						}
						else {
							CYNG_LOG_WARNING(logger, "modify channel ["
								<< channel <<
								"] with invalid "
								<< param.first
								<< ": "
								<< eui);
						}
					}
					else if (boost::algorithm::equals(param.first, "AppEUI")) {

						//
						//	convert value to mac64
						//
						auto const eui = cyng::value_cast<std::string>(reader["rec"]["data"].get(param.first), "0000:0000:0000:0000");
						std::pair<cyng::mac64, bool > r = cyng::parse_mac64(eui);
						if (r.second) {
							ctx.queue(bus_req_db_modify("TLoRaDevice"
								, key
								, cyng::param_factory(param.first, r.first)
								, 0
								, ctx.tag()));
						}
						else {
							CYNG_LOG_WARNING(logger, "modify channel ["
								<< channel <<
								"] with invalid "
								<< param.first
								<< ": "
								<< eui);
						}
					}
					else if (boost::algorithm::equals(param.first, "GatewayEUI")) {

						//
						//	convert value to mac64
						//
						auto const eui = cyng::value_cast<std::string>(reader["rec"]["data"].get(param.first), "0000:0000:0000:0000");
						std::pair<cyng::mac64, bool > r = cyng::parse_mac64(eui);
						if (r.second) {
							ctx.queue(bus_req_db_modify("TLoRaDevice"
								, key
								, cyng::param_factory(param.first, r.first)
								, 0
								, ctx.tag()));
						}
						else {
							CYNG_LOG_WARNING(logger, "modify channel ["
								<< channel <<
								"] with invalid "
								<< param.first
								<< ": "
								<< eui);
						}
					}
					else {
						ctx.queue(bus_req_db_modify("TLoRaDevice"
							, key
							, param
							, 0
							, ctx.tag()));
					}
				}
			}
			catch (std::exception const& ex) {
				CYNG_LOG_ERROR(logger, "ws.read - modify channel ["
					<< channel <<
					"] failed:"
					<< ex.what());
			}
		}
		else
		{
			CYNG_LOG_WARNING(logger, "ws.read - unknown modify channel [" << channel << "]");
		}
	}

	void fwd_stop(cyng::logging::log_ptr logger
		, cyng::context& ctx
		, cyng::reader<cyng::object> const& reader)
	{
		const std::string channel = cyng::value_cast<std::string>(reader.get("channel"), "");
		CYNG_LOG_TRACE(logger, "ws.read - stop channel [" << channel << "]");
		if (boost::algorithm::starts_with(channel, "status.session"))
		{
			//
			//	TDevice key is of type UUID
			//	all values have the same key
			//
			try {

				cyng::vector_t vec;
				vec = cyng::value_cast(reader.get("key"), vec);
				BOOST_ASSERT_MSG(vec.size() == 1, "*Session key has wrong size");

				//const std::string str = cyng::value_cast<std::string>(vec.at(0), "");
				//CYNG_LOG_DEBUG(logger, "*Session key [" << str << "]");
				//auto key = cyng::table::key_generator(boost::uuids::string_generator()(str));
				auto key = cyng::table::key_generator(vec.at(0));
				ctx.queue(bus_req_stop_client(key, ctx.tag()));

			}
			catch (std::exception const& ex) {
				CYNG_LOG_ERROR(logger, "ws.read - modify channel ["
					<< channel <<
					"] failed: "
					<< ex.what());
			}
		}
		else
		{
			CYNG_LOG_WARNING(logger, "ws.read - unknown stop channel [" << channel << "]");
		}
	}

	void fwd_config_gateway(cyng::logging::log_ptr logger
		, cyng::context& ctx
		, boost::uuids::uuid tag_ws
		, std::string const& channel
		, cyng::reader<cyng::object> const& reader)
	{
		//	{"cmd":"config:gateway","channel":"get.proc.param","key":["fce4fe15-0756-4ae4-91e7-28dee59f07e6"],"params":[{"section":["op-log-status-word","root-visible-devices","root-active-devices","root-device-id","memory","root-wMBus-status","IF_wMBUS","root-ipt-state","root-ipt-param"]}]}
		//	{"cmd":"config:gateway","channel":"set.proc.param","key":["fce4fe15-0756-4ae4-91e7-28dee59f07e6"],"params":[{"name":"smf-form-gw-ipt-srv","value":"0500153B0223B3"},{"name":"smf-gw-ipt-host-1","value":"waiting..."},{"name":"smf-gw-ipt-local-1","value":""},{"name":"smf-gw-ipt-remote-1","value":""},{"name":"smf-gw-ipt-name-1","value":"waiting..."},{"name":"smf-gw-ipt-pwd-1","value":""},{"name":"smf-gw-ipt-host-2","value":"waiting..."},{"name":"smf-gw-ipt-local-2","value":""},{"name":"smf-gw-ipt-remote-2","value":""},{"name":"smf-gw-ipt-name-2","value":"waiting..."},{"name":"smf-gw-ipt-pwd-2","value":""},{"section":["ipt"]}]}
		//	{"cmd":"config:gateway","channel":"set.proc.param","key":["31cad258-45f1-4b1d-b131-8a55eb671bb1"],"params":[{"name":"meter-tag","value":"1a38ed66-bd25-4e34-827c-b1a62f09abf4"},{"name":"meter-id","value":"01-a815-74314505-01-02"}],"section":["query"]}
		cyng::vector_t key;
		key = cyng::value_cast(reader.get("key"), key);
		CYNG_LOG_INFO(logger, "ws tag: " << tag_ws << " - TGateway key" << cyng::io::to_str(key));
		BOOST_ASSERT_MSG(!key.empty(), "TGateway key is empty");
		if (!key.empty()) {

			cyng::vector_t vec;
			ctx.queue(bus_req_gateway_proxy(key	//	key into TGateway and TDevice table
				, tag_ws	//	web-socket tag
				, channel
				, cyng::value_cast(reader.get("section"), vec)
				, cyng::value_cast(reader.get("params"), vec)));	//	parameters, requests, commands

		}
	}

	forward::forward(cyng::logging::log_ptr logger
		, cyng::store::db& db
		, connection_manager_interface& cm)
	: logger_(logger)
		, db_(db)
		, connection_manager_(cm)
		, uidgen_()
	{}

	void forward::register_this(cyng::controller& vm)
	{
		vm.register_function("cfg.upload.devices", 2, std::bind(&forward::cfg_upload_devices, this, std::placeholders::_1));
		vm.register_function("cfg.upload.gateways", 2, std::bind(&forward::cfg_upload_gateways, this, std::placeholders::_1));
		vm.register_function("cfg.upload.meter", 2, std::bind(&forward::cfg_upload_meter, this, std::placeholders::_1));
		vm.register_function("cfg.upload.LoRa", 2, std::bind(&forward::cfg_upload_LoRa, this, std::placeholders::_1));

		vm.register_function("cfg.download.devices", 2, std::bind(&forward::cfg_download_devices, this, std::placeholders::_1));
		vm.register_function("cfg.download.gateways", 2, std::bind(&forward::cfg_download_gateways, this, std::placeholders::_1));
		vm.register_function("cfg.download.meters", 2, std::bind(&forward::cfg_download_meters, this, std::placeholders::_1));
		vm.register_function("cfg.download.messages", 2, std::bind(&forward::cfg_download_messages, this, std::placeholders::_1));
		vm.register_function("cfg.download.LoRa", 2, std::bind(&forward::cfg_download_LoRa, this, std::placeholders::_1));
		vm.register_function("cfg.download.uplink", 2, std::bind(&forward::cfg_download_uplink, this, std::placeholders::_1));

	}

	void forward::cfg_upload_devices(cyng::context& ctx)
	{
		//
		//	[181f86c7-23e5-4e01-a4d9-f6c9855962bf,
		//	%(
		//		("devConf_0":text/xml),
		//		("devices.xml":C:\\Users\\Pyrx\\AppData\\Local\\Temp\\smf-dash-ea2e-1fe1-6628-93ff.tmp),
		//		("smf-procedure":cfg.upload.devices),
		//		("smf-upload-config-device-version":v5.0),
		//		("target":/upload/config/device/)
		//	)]
		//
		const cyng::vector_t frame = ctx.get_frame();
		CYNG_LOG_TRACE(logger_, "cfg.upload.device - " << cyng::io::to_str(frame));

		auto const tpl = cyng::tuple_cast<
			boost::uuids::uuid,	//	[0] session tag
			cyng::param_map_t	//	[1] variables
		>(frame);

		auto file_name = cyng::value_cast<std::string>(cyng::find(std::get<1>(tpl), "dev-conf-0"), "");
		auto version = cyng::value_cast<std::string>(cyng::find(std::get<1>(tpl), "smf-upload-config-device-version"), "v0.5");
		auto merge = cyng::value_cast<std::string>(cyng::find(std::get<1>(tpl), "smf-upload-config-device-merge"), "insert");

		//
		//	get pointer to XML data
		//
		pugi::xml_document doc;
		const pugi::xml_parse_result result = doc.load_file(file_name.c_str());
		if (result) {

			if (boost::algorithm::equals(version, "v3.2")) {
				read_device_configuration_3_2(ctx, doc, boost::algorithm::equals(merge, "insert"));
			}
			else {
				read_device_configuration_5_x(ctx, doc, boost::algorithm::equals(merge, "insert"));
			}
		}
		else {
			std::stringstream ss;
			ss
				<< "XML ["
				<< file_name
				<< "] parsed with errors: ["
				<< result.description()
				<< "]\n"
				<< "Error offset: "
				<< result.offset
				;

			ctx.queue(bus_insert_msg(cyng::logging::severity::LEVEL_WARNING, ss.str()));
		}
	}

	void forward::cfg_upload_gateways(cyng::context& ctx)
	{
		const cyng::vector_t frame = ctx.get_frame();
		CYNG_LOG_TRACE(logger_, "cfg.upload.gateways - " << cyng::io::to_str(frame));

		auto const tpl = cyng::tuple_cast<
			boost::uuids::uuid,	//	[0] session tag
			cyng::param_map_t	//	[1] variables
		>(frame);

		auto const file_name = cyng::value_cast<std::string>(cyng::find(std::get<1>(tpl), "gw-conf-0"), "");

		//
		//	get pointer to XML data
		//
		pugi::xml_document doc;
		const pugi::xml_parse_result result = doc.load_file(file_name.c_str());
		if (result) {

			std::size_t counter{ 0 };
			pugi::xpath_node_set data = doc.select_nodes("/TGateway/record");

			//
			//	target scheme required
			//
			auto meta = create_meta("TGateway");
			for (pugi::xpath_node_set::const_iterator it = data.begin(); it != data.end(); ++it)
			{
				counter++;
				pugi::xml_node node = it->node();

				auto rec = cyng::xml::read(node, meta);

				CYNG_LOG_INFO(logger_, "session "
					<< ctx.tag()
					<< " - insert gateway #"
					<< counter
					<< " "
					<< cyng::value_cast(rec["pk"], boost::uuids::nil_uuid())
					<< " - "
					<< cyng::value_cast<std::string>(rec["serverId"], ""));

				ctx.queue(bus_req_db_insert("TGateway", rec.key(), rec.data(), rec.get_generation(), ctx.tag()));
			}

		}
		else {
			std::stringstream ss;
			ss
				<< "XML ["
				<< file_name
				<< "] parsed with errors: ["
				<< result.description()
				<< "]\n"
				<< "Error offset: "
				<< result.offset
				;

			ctx.queue(bus_insert_msg(cyng::logging::severity::LEVEL_WARNING, ss.str()));
		}
	}

	void forward::cfg_upload_meter(cyng::context& ctx)
	{
		const cyng::vector_t frame = ctx.get_frame();
		CYNG_LOG_TRACE(logger_, ctx.get_name() << " - " << cyng::io::to_str(frame));

		auto const tpl = cyng::tuple_cast<
			boost::uuids::uuid,	//	[0] session tag
			cyng::param_map_t	//	[1] variables
		>(frame);

		auto const file_name = cyng::value_cast<std::string>(cyng::find(std::get<1>(tpl), "gw-conf-0"), "");

		//
		//	get pointer to XML data
		//
		pugi::xml_document doc;
		const pugi::xml_parse_result result = doc.load_file(file_name.c_str());
		if (result) {

			std::size_t counter{ 0 };
			pugi::xpath_node_set data = doc.select_nodes("/TMeter/record");

			//
			//	target scheme required
			//
			auto meta = create_meta("TMeter");
			for (pugi::xpath_node_set::const_iterator it = data.begin(); it != data.end(); ++it)
			{
				counter++;
				pugi::xml_node node = it->node();

				auto rec = cyng::xml::read(node, meta);

				CYNG_LOG_INFO(logger_, "session "
					<< ctx.tag()
					<< " - insert meter #"
					<< counter
					<< " "
					<< cyng::value_cast(rec["pk"], boost::uuids::nil_uuid())
					<< " - "
					<< cyng::value_cast<std::string>(rec["serverId"], ""));

				ctx.queue(bus_req_db_insert("TMeter", rec.key(), rec.data(), rec.get_generation(), ctx.tag()));
			}

		}
		else {
			std::stringstream ss;
			ss
				<< "XML ["
				<< file_name
				<< "] parsed with errors: ["
				<< result.description()
				<< "]\n"
				<< "Error offset: "
				<< result.offset
				;

			ctx.queue(bus_insert_msg(cyng::logging::severity::LEVEL_WARNING, ss.str()));
		}
	}

	void forward::cfg_upload_LoRa(cyng::context& ctx)
	{
		const cyng::vector_t frame = ctx.get_frame();
		CYNG_LOG_TRACE(logger_, ctx.get_name() << " - " << cyng::io::to_str(frame));

		auto const tpl = cyng::tuple_cast<
			boost::uuids::uuid,	//	[0] session tag
			cyng::param_map_t	//	[1] variables
		>(frame);

		auto const file_name = cyng::value_cast<std::string>(cyng::find(std::get<1>(tpl), "gw-conf-0"), "");

		//
		//	get pointer to XML data
		//
		pugi::xml_document doc;
		const pugi::xml_parse_result result = doc.load_file(file_name.c_str());
		if (result) {

			std::size_t counter{ 0 };
			pugi::xpath_node_set data = doc.select_nodes("/TLoRaDevice/record");

			//
			//	target scheme required
			//
			auto meta = create_meta("TLoRaDevice");
			for (pugi::xpath_node_set::const_iterator it = data.begin(); it != data.end(); ++it)
			{
				counter++;
				pugi::xml_node node = it->node();

				auto rec = cyng::xml::read(node, meta);

				CYNG_LOG_INFO(logger_, "session "
					<< ctx.tag()
					<< " - insert LoRa device #"
					<< counter
					<< " "
					<< cyng::value_cast(rec["pk"], boost::uuids::nil_uuid())
					<< " - "
					<< cyng::value_cast<std::string>(rec["serverId"], ""));

				ctx.queue(bus_req_db_insert("TLoRaDevice", rec.key(), rec.data(), rec.get_generation(), ctx.tag()));
			}
		}
		else {
			std::stringstream ss;
			ss
				<< "XML ["
				<< file_name
				<< "] parsed with errors: ["
				<< result.description()
				<< "]\n"
				<< "Error offset: "
				<< result.offset
				;

			ctx.queue(bus_insert_msg(cyng::logging::severity::LEVEL_WARNING, ss.str()));
		}
	}

	void forward::read_device_configuration_3_2(cyng::context& ctx, pugi::xml_document const& doc, bool insert)
	{
		//
		//	example line:
		//	<device auto_update="false" description="BF Haus 18" enabled="true" expires="never" gid="2" latitude="0.000000" limit="no" locked="false" longitude="0.000000" monitor="00:00:12" name="a00153B018EEFen" number="20113083736" oid="2" pwd="aen_ict_1111" query="6" redirect="" watchdog="00:12:00">cc6a0256-5689-4804-a5fc-bf3599fac23a</device>
		//

		std::size_t counter{ 0 };
		pugi::xpath_node_set data = doc.select_nodes("config/units/device");
		for (pugi::xpath_node_set::const_iterator it = data.begin(); it != data.end(); ++it)
		{
			counter++;
			pugi::xml_node node = it->node();
			const std::string pk_val = node.child_value();
			const auto pk = (pk_val.size() == 36)
				? boost::uuids::string_generator()(pk_val)
				: uidgen_()
				;

			const std::string name = node.attribute("name").value();

			CYNG_LOG_TRACE(logger_, "session "
				<< ctx.tag()
				<< " - insert device "
				<< pk
				<< " - "
				<< name);

			//
			//	forward to process bus task
			//
			if (insert) {

				//
				//	merge
				//
				ctx.queue(bus_req_db_insert("TDevice"
					//	generate new key
					, cyng::table::key_generator(pk)
					//	build data vector
					, cyng::table::data_generator(name
						, node.attribute("pwd").value()
						, node.attribute("number").value()
						, node.attribute("description").value()
						, std::string("")	//	model
						, std::string("")	//	version
						, node.attribute("enabled").as_bool()
						, std::chrono::system_clock::now()
						, node.attribute("query").as_uint())
					, 0
					, ctx.tag()));
			}
			else {

				//
				//	merge
				//
				ctx.queue(bus_req_db_modify("TDevice"
					, cyng::table::key_generator(pk)
					, cyng::param_factory("pwd", node.attribute("pwd").value())
					, 0
					, ctx.tag()));
				ctx.queue(bus_req_db_modify("TDevice"
					, cyng::table::key_generator(pk)
					, cyng::param_factory("msisdn", node.attribute("number").value())
					, 0
					, ctx.tag()));
				ctx.queue(bus_req_db_modify("TDevice"
					, cyng::table::key_generator(pk)
					, cyng::param_factory("descr", node.attribute("description").value())
					, 0
					, ctx.tag()));
				ctx.queue(bus_req_db_modify("TDevice"
					, cyng::table::key_generator(pk)
					, cyng::param_factory("query", node.attribute("query").as_uint())
					, 0
					, ctx.tag()));
			}
		}

		std::stringstream ss;
		ss
			<< counter
			<< " device records (v3.2) uploaded"
			;
		ctx.queue(bus_insert_msg(cyng::logging::severity::LEVEL_INFO, ss.str()));

	}

	void forward::read_device_configuration_4_0(cyng::context& ctx, pugi::xml_document const& doc, bool insert)
	{
		std::size_t counter{ 0 };
		pugi::xpath_node_set data = doc.select_nodes("configuration/records/device");
		for (pugi::xpath_node_set::const_iterator it = data.begin(); it != data.end(); ++it)
		{
			counter++;
			pugi::xpath_node node = *it;
			const std::string name = node.node().child_value("name");

			CYNG_LOG_TRACE(logger_, "session "
				<< ctx.tag()
				<< " - insert device "
				<< name);

			//auto obj = cyng::traverse(node.node());
			//CYY_LOG_TRACE(logger_, "session "
			//	<< cyy::uuid_short_format(vm_.tag())
			//	<< " - "
			//	<< cyy::to_literal(obj, cyx::io::custom));

			//	("device":
			//	%(("age":"2016.11.24 14:48:09.00000000"ts),
			//	("config":%(("pwd":"LUsregnP"),("scheme":"plain"))),
			//	("descr":"-[0008]-"),
			//	("enabled":true),
			//	("id":""),
			//	("name":"oJtrQQfSCRrF"),
			//	("number":"609971066"),
			//	("revision":0u32),
			//	("source":"d365c4c7-e89d-4187-86ae-a143d54f4cfe"uuid),
			//	("tag":"e29938f5-71a9-4860-97e2-0a78097a6858"uuid),
			//	("ver":"")))

			//cyy::object_reader reader(obj);

			//
			//	collect data
			//	forward to process bus task
			//
			//insert("TDevice"
			//	, cyy::store::key_generator(reader["device"].get_uuid("tag"))
			//	, cyy::store::data_generator(reader["device"].get_object("revision")
			//		, reader["device"].get_object("name")
			//		, reader["device"].get_object("number")
			//		, reader["device"].get_object("descr")
			//		, reader["device"].get_object("id")	//	device ID
			//		, reader["device"].get_object("ver")	//	root-device-id
			//		, reader["device"].get_object("enabled")
			//		, reader["device"].get_object("age")

			//		//	configuration as parameter map
			//		, reader["device"].get_object("config")
			//		, reader["device"].get_object("source")));

			//ctx.queue(bus_req_db_insert("TDevice"
			//	//	generate new key
			//	, cyng::table::key_generator(boost::uuids::string_generator()(pk))
			//	//	build data vector
			//	, cyng::table::data_generator(name
			//		, node.attribute("pwd").value()
			//		, node.attribute("number").value()
			//		, node.attribute("description").value()
			//		, std::string("")	//	model
			//		, std::string("")	//	version
			//		, node.attribute("enabled").as_bool()
			//		, std::chrono::system_clock::now()
			//		, node.attribute("query").as_uint())
			//	, 0
			//	, ctx.tag()));
		}

		std::stringstream ss;
		ss
			<< counter
			<< " device records (v4.0) uploaded"
			;
		ctx.queue(bus_insert_msg(cyng::logging::severity::LEVEL_INFO, ss.str()));

	}

	void forward::read_device_configuration_5_x(cyng::context& ctx, pugi::xml_document const& doc, bool insert)
	{
		std::size_t counter{ 0 };
		pugi::xpath_node_set data = doc.select_nodes("TDevice/record");
		auto meta = db_.meta("TDevice");
		for (pugi::xpath_node_set::const_iterator it = data.begin(); it != data.end(); ++it)
		{
			counter++;
			pugi::xml_node node = it->node();

			auto rec = cyng::xml::read(node, meta);

			CYNG_LOG_TRACE(logger_, "session "
				<< ctx.tag()
				<< " - insert device #"
				<< counter
				<< " "
				<< cyng::value_cast(rec["pk"], boost::uuids::nil_uuid())
				<< " - "
				<< cyng::value_cast<std::string>(rec["name"], ""));

			ctx.queue(bus_req_db_insert("TDevice", rec.key(), rec.data(), rec.get_generation(), ctx.tag()));
		}
	}

	void forward::cfg_download_devices(cyng::context& ctx)
	{
		//
		//	example
		//	[%(("smf-procedure":cfg.download.devices),("smf-upload-config-device-version":v5.0),("target":/api/download/config/device))]
		//
		const cyng::vector_t frame = ctx.get_frame();
		CYNG_LOG_TRACE(logger_, "cfg.download.devices - " << cyng::io::to_str(frame));

		auto const tpl = cyng::tuple_cast<
			boost::uuids::uuid,	//	[0] session tag
			cyng::param_map_t	//	[1] variables
		>(frame);

		auto const reader = cyng::make_reader(std::get<1>(tpl));
		auto const fmt = cyng::value_cast<std::string>(reader.get("smf-download-device-format"), "XML");
		if (boost::algorithm::equals("CSV", fmt)) {
			trigger_download_csv(std::get<0>(tpl), "TDevice", "device.csv");
		}
		else {
			trigger_download_xml(std::get<0>(tpl), "TDevice", "device.xml");
		}
	}

	void forward::cfg_download_gateways(cyng::context& ctx)
	{
		//
		//	example
		//	[fd003d7f-43a5-4b3b-9dca-71c7584092a5,%(("smf-download-gw-format":CSV),("smf-procedure":cfg.download.gateways),("target":/config.download.html))]
		//
		const cyng::vector_t frame = ctx.get_frame();
		CYNG_LOG_TRACE(logger_, "cfg.download.gateways - " << cyng::io::to_str(frame));

		auto const tpl = cyng::tuple_cast<
			boost::uuids::uuid,	//	[0] session tag
			cyng::param_map_t	//	[1] variables
		>(frame);

		auto const reader = cyng::make_reader(std::get<1>(tpl));
		auto const fmt = cyng::value_cast<std::string>(reader.get("smf-download-gw-format"), "XML");
		if (boost::algorithm::equals("CSV", fmt)) {
			trigger_download_csv(std::get<0>(tpl), "TGateway", "gateway.csv");
		}
		else {
			trigger_download_xml(std::get<0>(tpl), "TGateway", "gateway.xml");
		}
	}

	void forward::cfg_download_meters(cyng::context& ctx)
	{
		//
		//	example
		//	[%(("smf-procedure":cfg.download.devices),("smf-upload-config-device-version":v5.0),("target":/api/download/config/device))]
		//
		const cyng::vector_t frame = ctx.get_frame();
		CYNG_LOG_TRACE(logger_, "cfg.download.meters - " << cyng::io::to_str(frame));

		auto const tpl = cyng::tuple_cast<
			boost::uuids::uuid,	//	[0] session tag
			cyng::param_map_t	//	[1] variables
		>(frame);

		auto const reader = cyng::make_reader(std::get<1>(tpl));
		auto const fmt = cyng::value_cast<std::string>(reader.get("smf-download-meter-format"), "XML");
		if (boost::algorithm::equals("CSV", fmt)) {
			trigger_download_csv(std::get<0>(tpl), "TMeter", "meter.csv");
		}
		else {
			trigger_download_xml(std::get<0>(tpl), "TMeter", "meter.xml");
		}
	}

	void forward::cfg_download_messages(cyng::context& ctx)
	{
		//
		//	example
		//	[%(("smf-procedure":cfg.download.devices),("smf-upload-config-device-version":v5.0),("target":/api/download/config/device))]
		//
		const cyng::vector_t frame = ctx.get_frame();
		CYNG_LOG_TRACE(logger_, "cfg.download.messages - " << cyng::io::to_str(frame));

		auto const tpl = cyng::tuple_cast<
			boost::uuids::uuid,	//	[0] session tag
			cyng::param_map_t	//	[1] variables
		>(frame);

		auto const reader = cyng::make_reader(std::get<1>(tpl));
		auto const fmt = cyng::value_cast<std::string>(reader.get("smf-download-msg-format"), "XML");
		if (boost::algorithm::equals("CSV", fmt)) {
			trigger_download_csv(std::get<0>(tpl), "_SysMsg", "messages.csv");
		}
		else {
			trigger_download_xml(std::get<0>(tpl), "_SysMsg", "messages.xml");
		}
	}

	void forward::cfg_download_LoRa(cyng::context& ctx)
	{
		const cyng::vector_t frame = ctx.get_frame();
		CYNG_LOG_TRACE(logger_, "cfg.download.LoRa - " << cyng::io::to_str(frame));

		auto const tpl = cyng::tuple_cast<
			boost::uuids::uuid,	//	[0] session tag
			cyng::param_map_t	//	[1] variables
		>(frame);

		trigger_download_xml(std::get<0>(tpl), "TLoRaDevice", "LoRa.xml");
	}

	void forward::cfg_download_uplink(cyng::context& ctx)
	{
		const cyng::vector_t frame = ctx.get_frame();
		CYNG_LOG_TRACE(logger_, ctx.get_name() << " - " << cyng::io::to_str(frame));

		auto const tpl = cyng::tuple_cast<
			boost::uuids::uuid,	//	[0] session tag
			cyng::param_map_t	//	[1] variables
		>(frame);

		auto const reader = cyng::make_reader(std::get<1>(tpl));
		auto const fmt = cyng::value_cast<std::string>(reader.get("smf-download-uplink-format"), "XML");
		if (boost::algorithm::equals("CSV", fmt)) {
			trigger_download_csv(std::get<0>(tpl), "_LoRaUplink", "LoRaUplink.csv");
		}
		else {
			trigger_download_xml(std::get<0>(tpl), "_LoRaUplink", "LoRaUplink.xml");
		}
	}

	void forward::trigger_download_xml(boost::uuids::uuid tag, std::string table, std::string filename)
	{
		//
		//	generate XML download file
		//
		pugi::xml_document doc_;
		auto declarationNode = doc_.append_child(pugi::node_declaration);
		declarationNode.append_attribute("version") = "1.0";
		declarationNode.append_attribute("encoding") = "UTF-8";
		declarationNode.append_attribute("standalone") = "yes";

		pugi::xml_node root = doc_.append_child(table.c_str());
		root.append_attribute("xmlns:xsi") = "w3.org/2001/XMLSchema-instance";
		db_.access([&](cyng::store::table const* tbl) {

			const auto counter = tbl->loop([&](cyng::table::record const& rec) -> bool {

				//
				//	write record
				//
				cyng::xml::write(root.append_child("record"), rec.convert());

				//	continue
				return true;
			});
			BOOST_ASSERT(counter == 0);
			boost::ignore_unused(counter);	//	release version
			CYNG_LOG_INFO(logger_, tbl->size() << ' ' << tbl->meta().get_name() << " records sent");

		}, cyng::store::read_access(table));

		//
		//	write XML file
		//
		auto out = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path("record-%%%%-%%%%-%%%%-%%%%.xml");
		if (doc_.save_file(out.c_str(), PUGIXML_TEXT("  "))) {

			//
			//	trigger download
			//
			connection_manager_.trigger_download(tag, out.string(), filename);
		}
		else {
			CYNG_LOG_ERROR(logger_, "cannot open file " << out);
		}
	}

	void forward::trigger_download_csv(boost::uuids::uuid tag, std::string table, std::string filename)
	{
		//
		//	generate CSV download file
		//
		auto out = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path("record-%%%%-%%%%-%%%%-%%%%.csv");

		db_.access([&](cyng::store::table const* tbl) {

			std::ofstream of(out.string(), std::ios::binary | std::ios::trunc | std::ios::out);

			if (of.is_open()) {
				auto vec = tbl->convert(true);
				cyng::csv::write(of, make_object(vec));
			}
			else {
				CYNG_LOG_ERROR(logger_, "cannot open file " << out);
			}

			//
			//	file closed implicit here
			//

		}, cyng::store::read_access(table));

		//
		//	trigger download
		//
		connection_manager_.trigger_download(tag, out, filename);
	}

}

max_stars_repo_name: solosTec/node

max_issues_repo_name: solosTec/node

max_forks_repo_name: solosTec/node


text:
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// 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)
//
// Official repository: https://github.com/CPPAlliance/url
//

#ifndef BOOST_URL_IMPL_PCT_ENCODED_BNF_HPP
#define BOOST_URL_IMPL_PCT_ENCODED_BNF_HPP

#include <boost/url/rfc/char_sets.hpp>
#include <boost/url/detail/pct_encoding.hpp>

namespace boost {
namespace urls {

template<class CharSet>
bool
parse(
    char const*& it,
    char const* const end,
    error_code& ec,
    pct_encoded_bnf<
        CharSet> const& t) noexcept
{
    auto const start = it;
    // VFALCO TODO
    // opt.plus_to_space?
    if(! detail::parse_pct_encoded(
        it, end, ec, CharSet{},
            t.v.decoded_size))
        return false;
    t.v.str = string_view(
        start, it - start);
    return true;
}

} // urls
} // boost

#endif

max_stars_repo_name: TankerHQ/url

max_issues_repo_name: TankerHQ/url

max_forks_repo_name: TankerHQ/url


text:
/*

Copyright (c) 2005-2015, University of Oxford.
All rights reserved.

University of Oxford means the Chancellor, Masters and Scholars of the
University of Oxford, having an administrative office at Wellington
Square, Oxford OX1 2JD, UK.

This file is part of Chaste.

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 University of Oxford 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.

*/

#ifndef MONODOMAINPROBLEM_HPP_
#define MONODOMAINPROBLEM_HPP_

#include "ChasteSerialization.hpp"
#include <boost/serialization/base_object.hpp>

#include "AbstractCardiacProblem.hpp"
#include "AbstractCardiacTissue.hpp"
#include "AbstractDynamicLinearPdeSolver.hpp"
#include "AbstractCardiacCellFactory.hpp"
#include "MonodomainTissue.hpp"

/**
 * Class which specifies and solves a monodomain problem.
 */
template<unsigned ELEMENT_DIM, unsigned SPACE_DIM = ELEMENT_DIM>
class MonodomainProblem : public AbstractCardiacProblem<ELEMENT_DIM, SPACE_DIM, 1>
{
    /** Needed for serialization. */
    friend class boost::serialization::access;
    /**
     * Archive the member variables.
     *
     * @param archive
     * @param version
     */
    template<class Archive>
    void serialize(Archive & archive, const unsigned int version)
    {
        archive & boost::serialization::base_object<AbstractCardiacProblem<ELEMENT_DIM, SPACE_DIM, 1> >(*this);
        archive & mpMonodomainTissue;
    }

protected:
    /** The monodomain tissue object. */
    MonodomainTissue<ELEMENT_DIM,SPACE_DIM>* mpMonodomainTissue;

public:
    /** @return Created monodomain tissue. */
    AbstractCardiacTissue<ELEMENT_DIM, SPACE_DIM>* CreateCardiacTissue();

    /** @return Created suitable solver for monodomain problems. */
    AbstractDynamicLinearPdeSolver<ELEMENT_DIM, SPACE_DIM, 1>* CreateSolver();

public:
    /**
     * Constructor
     * @param pCellFactory User defined cell factory which shows how the pde should
     *   create cells.
     */
    MonodomainProblem(AbstractCardiacCellFactory<ELEMENT_DIM,SPACE_DIM>* pCellFactory);

    /**
     * Constructor just used for archiving
     */
    MonodomainProblem();

    /**
     * Destructor
     */
    virtual ~MonodomainProblem();

    /** @return the monodomain PDE */
    MonodomainTissue<ELEMENT_DIM,SPACE_DIM> * GetMonodomainTissue();

    /**
     *  Print out time and max/min voltage values at current time.
     *
     * @param time  the current time
     */
    void WriteInfo(double time);

    /**
     * Define what variables are written to the primary results file.
     * @param extending  whether we are extending an existing results file
     */
    virtual void DefineWriterColumns(bool extending);

    /**
     * Write one timestep of output data to the primary results file.
     * Adds the voltage to the results.
     *
     * @param time  the current time
     * @param voltageVec  the solution vector to write
     */
    virtual void WriteOneStep(double time, Vec voltageVec);

};

#include "SerializationExportWrapper.hpp" // Must be last
EXPORT_TEMPLATE_CLASS2(MonodomainProblem, 1, 1)
EXPORT_TEMPLATE_CLASS2(MonodomainProblem, 1, 2)
EXPORT_TEMPLATE_CLASS2(MonodomainProblem, 1, 3)
EXPORT_TEMPLATE_CLASS2(MonodomainProblem, 2, 2)
EXPORT_TEMPLATE_CLASS2(MonodomainProblem, 3, 3)

#endif /*MONODOMAINPROBLEM_HPP_*/

max_stars_repo_name: ktunya/ChasteMod

max_issues_repo_name: ktunya/ChasteMod

max_forks_repo_name: ktunya/ChasteMod


text:
/*
 * Copyright (c) 2018, YOYOW Foundation PTE. LTD. and contributors.
 */
#include <graphene/chain/advertising_evaluator.hpp>
#include <graphene/chain/advertising_object.hpp>
#include <graphene/chain/exceptions.hpp>
#include <graphene/chain/hardfork.hpp>
#include <graphene/chain/is_authorized_asset.hpp>
#include <graphene/chain/protocol/chain_parameters.hpp>
#include <boost/multiprecision/cpp_int.hpp>

typedef boost::multiprecision::uint128_t uint128_t;

namespace graphene { namespace chain {

void_result advertising_create_evaluator::do_evaluate(const operation_type& op)
{
   try {
      const database& d = db();
      FC_ASSERT(d.head_block_time() >= HARDFORK_0_4_TIME, "Can only create advertising after HARDFORK_0_4_TIME");
      d.get_platform_by_owner(op.platform); // make sure platform exists
      platform_ant = &d.get_account_statistics_by_uid(op.platform);
      FC_ASSERT((platform_ant->last_advertising_sequence + 1) == op.advertising_aid, "advertising_aid ${pid} is invalid.", ("pid", op.advertising_aid));
      return void_result();
   }FC_CAPTURE_AND_RETHROW((op))
}

object_id_type advertising_create_evaluator::do_apply(const operation_type& op)
{
   try {
      database& d = db();
      d.modify(*platform_ant, [&](account_statistics_object& s) {
         s.last_advertising_sequence += 1;
      });
      const auto& advertising_obj = d.create<advertising_object>([&](advertising_object& obj)
      {
         obj.advertising_aid = op.advertising_aid;
         obj.platform = op.platform;
         obj.on_sell = true;
         obj.unit_time = op.unit_time;
         obj.unit_price = op.unit_price;
         obj.description = op.description;

         obj.publish_time = d.head_block_time();
         obj.last_update_time = d.head_block_time();
      });
      return advertising_obj.id;
   } FC_CAPTURE_AND_RETHROW((op))
}

void_result advertising_update_evaluator::do_evaluate(const operation_type& op)
{
   try {
      const database& d = db();
      FC_ASSERT(d.head_block_time() >= HARDFORK_0_4_TIME, "Can only update advertising after HARDFORK_0_4_TIME");
      d.get_platform_by_owner(op.platform); // make sure pid exists
      advertising_obj = d.find_advertising(op.platform, op.advertising_aid);
      FC_ASSERT(advertising_obj != nullptr, "advertising_object doesn`t exsit");

      if (op.on_sell.valid())
         FC_ASSERT(*(op.on_sell) != advertising_obj->on_sell, "advertising state needn`t update. ");

      return void_result();

   }FC_CAPTURE_AND_RETHROW((op))
}

void_result advertising_update_evaluator::do_apply(const operation_type& op)
{
   try {
      database& d = db();
      d.modify(*advertising_obj, [&](advertising_object& ad) {
         if (op.description.valid())
            ad.description = *(op.description);
         if (op.unit_price.valid())
            ad.unit_price = *(op.unit_price);
         if (op.unit_time.valid())
            ad.unit_time = *(op.unit_time);
         if (op.on_sell.valid())
            ad.on_sell = *(op.on_sell);
         ad.last_update_time = d.head_block_time();
      });

      return void_result();

   } FC_CAPTURE_AND_RETHROW((op))
}

void_result advertising_buy_evaluator::do_evaluate(const operation_type& op)
{
   try {
      const database& d = db();

      FC_ASSERT(d.head_block_time() >= HARDFORK_0_4_TIME, "Can only buy advertising after HARDFORK_0_4_TIME");
      advertising_obj = d.find_advertising(op.platform, op.advertising_aid);
      FC_ASSERT(advertising_obj != nullptr && advertising_obj->platform == op.platform,
         "advertising ${tid} on platform ${platform} is invalid.", ("tid", op.advertising_aid)("platform", op.platform));
      FC_ASSERT(advertising_obj->on_sell, "advertising ${id} on platform ${platform} not on sell", ("id", op.advertising_aid)("platform", op.platform));
      FC_ASSERT(op.start_time >= d.head_block_time() && op.start_time <= d.head_block_time() + 10 * 365 * 86400,
         "start time should be more than current time and not more than next ten years");
      FC_ASSERT((advertising_obj->last_order_sequence + 1) == op.advertising_order_oid, "advertising_order_oid ${pid} is invalid.", ("pid", op.advertising_order_oid));

      const auto& idx = d.get_index_type<advertising_order_index>().indices().get<by_advertising_order_state>();
      auto itr = idx.lower_bound(std::make_tuple(advertising_accepted, op.platform, op.advertising_aid));

      FC_ASSERT(advertising_obj->unit_time <= 10 * 365 * 86400 / op.buy_number, "advertising purchasing time should not more than ten years ");

      time_point_sec end_time = op.start_time + advertising_obj->unit_time * op.buy_number;
      while (itr != idx.end() && itr->advertising_aid == op.advertising_aid && itr->platform == op.platform && itr->status == advertising_accepted) {
         if (op.start_time >= itr->end_time || end_time <= itr->start_time) {
            ++itr;
            continue;
         }
         FC_ASSERT(false, "purchasing date have a conflict, buy advertising failed");
      }

      necessary_balance = advertising_obj->unit_price * op.buy_number;
      const auto& params = d.get_global_properties().parameters.get_award_params();
      FC_ASSERT(necessary_balance > params.advertising_confirmed_min_fee,
         "buy price is not enough to pay The lowest poundage ${fee}", ("fee", params.advertising_confirmed_min_fee));

      return void_result();

   }FC_CAPTURE_AND_RETHROW((op))
}

asset advertising_buy_evaluator::do_apply(const operation_type& op)
{
   try {
      database& d = db();
      d.modify(*advertising_obj, [&](advertising_object& s) {
         s.last_order_sequence += 1;
      });
      const auto& advertising_order_obj = d.create<advertising_order_object>([&](advertising_order_object& obj)
      {
         obj.advertising_order_oid = op.advertising_order_oid;
         obj.advertising_aid = advertising_obj->advertising_aid;
         obj.platform = op.platform;
         obj.user = op.from_account;
         obj.start_time = op.start_time;
         obj.end_time = op.start_time + advertising_obj->unit_time * op.buy_number;
         obj.buy_request_time = d.head_block_time();
         obj.status = advertising_undetermined;
         obj.released_balance = necessary_balance;
         obj.extra_data = op.extra_data;

         if (op.memo.valid())
            obj.memo = op.memo;
      });

      d.adjust_balance(op.from_account, -asset(necessary_balance));

      return asset(necessary_balance);

   } FC_CAPTURE_AND_RETHROW((op))
}

void_result advertising_confirm_evaluator::do_evaluate(const operation_type& op)
{
   try {
      const database& d = db();

      FC_ASSERT(d.head_block_time() >= HARDFORK_0_4_TIME, "Can only advertising confirm after HARDFORK_0_4_TIME");
      const auto& advertising_obj = d.find_advertising(op.platform, op.advertising_aid);
      FC_ASSERT(advertising_obj != nullptr && advertising_obj->platform == op.platform,
         "advertising ${tid} on platform ${platform} is invalid.", ("tid", op.advertising_aid)("platform", op.platform));

      advertising_order_obj = d.find_advertising_order(op.platform, op.advertising_aid, op.advertising_order_oid);
      FC_ASSERT(advertising_order_obj != nullptr, "order ${p}_${ad}_${order} is not existent", ("p", op.platform)("ad", op.advertising_aid)("order", op.advertising_order_oid));
      FC_ASSERT(advertising_order_obj->status == advertising_undetermined,
         "order ${p}_${ad}_${order} already effective or refused.", ("p", op.platform)("ad", op.advertising_aid)("order", op.advertising_order_oid));

      if (op.isconfirm) {
         const auto& params = d.get_global_properties().parameters.get_award_params();
         FC_ASSERT(advertising_order_obj->released_balance > params.advertising_confirmed_min_fee,
            "buy price is not enough to pay the lowest poundage ${fee}", ("fee", params.advertising_confirmed_min_fee));
      }

      return void_result();

   }FC_CAPTURE_AND_RETHROW((op))
}

advertising_confirm_result advertising_confirm_evaluator::do_apply(const operation_type& op)
{
   try {
      database& d = db();

      advertising_confirm_result result;
      if (op.isconfirm)
      {
         share_type released_balance = advertising_order_obj->released_balance;
         d.modify(*advertising_order_obj, [&](advertising_order_object& obj)
         {
            obj.status = advertising_accepted;
            obj.handle_time = d.head_block_time();
         });

         const auto& params = d.get_global_properties().parameters.get_award_params();
         share_type fee = ((uint128_t)(released_balance.value)* params.advertising_confirmed_fee_rate
            / GRAPHENE_100_PERCENT).convert_to<int64_t>();
         if (fee < params.advertising_confirmed_min_fee)
            fee = params.advertising_confirmed_min_fee;

         d.adjust_balance(op.platform, asset(released_balance - fee));
         const auto& core_asset = d.get_core_asset();
         const auto& core_dyn_data = core_asset.dynamic_data(d);
         d.modify(core_dyn_data, [&](asset_dynamic_data_object& dyn)
         {
            dyn.current_supply -= fee;
         });

         result.emplace(advertising_order_obj->user, 0);

         const auto& idx = d.get_index_type<advertising_order_index>().indices().get<by_advertising_order_state>();
         auto itr = idx.lower_bound(std::make_tuple(advertising_undetermined, op.platform, op.advertising_aid));

         vector<std::reference_wrapper<const advertising_order_object>> refs;
         while (itr != idx.end() && itr->platform == op.platform && itr->advertising_aid == op.advertising_aid && itr->status == advertising_undetermined)
         {
            if (itr->start_time >= advertising_order_obj->end_time || itr->end_time <= advertising_order_obj->start_time) {
               ++itr;
            }
            else
            {
               d.adjust_balance(itr->user, asset(itr->released_balance));
               result.emplace(itr->user, itr->released_balance);
               refs.emplace_back(std::cref(*itr));
               ++itr;
            }
         }

         std::for_each(refs.begin(), refs.end(), [&](const advertising_order_object& advertising_order)
         {
            d.modify(advertising_order, [&](advertising_order_object& obj)
            {
               obj.status = advertising_refused;
               obj.handle_time = d.head_block_time();
            });
         });
      }
      else
      {
         d.adjust_balance(advertising_order_obj->user, asset(advertising_order_obj->released_balance));
         result.emplace(advertising_order_obj->user, advertising_order_obj->released_balance);
         d.modify(*advertising_order_obj, [&](advertising_order_object& obj)
         {
            obj.status = advertising_refused;
            obj.handle_time = d.head_block_time();
         });
      }

      return result;

   } FC_CAPTURE_AND_RETHROW((op))
}

void_result advertising_ransom_evaluator::do_evaluate(const operation_type& op)
{
   try {
      const database& d = db();
      FC_ASSERT(d.head_block_time() >= HARDFORK_0_4_TIME, "Can only ransom advertising after HARDFORK_0_4_TIME");
      d.get_platform_by_owner(op.platform); // make sure platorm exists
      d.get_account_by_uid(op.from_account);
      const auto& advertising_obj = d.find_advertising(op.platform, op.advertising_aid);
      FC_ASSERT(advertising_obj != nullptr, "advertising object doesn`t exsit");

      advertising_order_obj = d.find_advertising_order(op.platform, op.advertising_aid, op.advertising_order_oid);
      FC_ASSERT(advertising_order_obj != nullptr, "order ${p}_${ad}_${order} is not existent", ("p", op.platform)("ad", op.advertising_aid)("order", op.advertising_order_oid));
      FC_ASSERT(advertising_order_obj->user == op.from_account, "your can only ransom your own order. ");
      FC_ASSERT(advertising_order_obj->buy_request_time + GRAPHENE_ADVERTISING_CONFIRM_TIME < d.head_block_time(),
         "it's not time to ransom, Can`t ransom now.");
      FC_ASSERT(advertising_order_obj->status == advertising_undetermined,
         "the buy advertising is not undetermined. Can`t ransom now.");

      return void_result();

   }FC_CAPTURE_AND_RETHROW((op))
}

void_result advertising_ransom_evaluator::do_apply(const operation_type& op)
{
   try {
      database& d = db();

      d.adjust_balance(op.from_account, asset(advertising_order_obj->released_balance));

      d.modify(*advertising_order_obj, [&](advertising_order_object& obj)
      {
         obj.status = advertising_ransom;
         obj.handle_time = d.head_block_time();
      });

      return void_result();

   } FC_CAPTURE_AND_RETHROW((op))
}

} } // graphene::chain

max_stars_repo_name: LianshuOne/yoyow-core

max_issues_repo_name: LianshuOne/yoyow-core

max_forks_repo_name: LianshuOne/yoyow-core