text:
#include "SecuredNetworkManager.h"
#include <boost/bind.hpp>
#include <iostream>

SecuredNetworkManager::SecuredNetworkManager(io_context& io_context, uint16_t port, MessageQueue<ReceivedMessage>& inbox)
: io_context_(io_context), ssl_context_(ssl::context::sslv23),
  acceptor_(io_context, tcp::endpoint(tcp::v4(), port)), maxConnectionID_(0), inbox_(inbox) {

    ssl_context_.set_options(ssl::context::default_workarounds |
                             ssl::context::no_sslv2 |
                             ssl::context::no_sslv3);
    ssl_context_.use_private_key_file("../cert/private.pem", ssl::context::pem);
    ssl_context_.use_certificate_chain_file("../cert/server_cert.pem");

    start_accept();
}

void SecuredNetworkManager::start_accept() {
    uint32_t connectionID = getConnectionID();
    auto new_connection = std::make_shared<P2PConnection>(connectionID, io_context_, ssl_context_, inbox_);
    acceptor_.async_accept(new_connection->socket().lowest_layer(),
                           boost::bind(&SecuredNetworkManager::accept_handler, this,
                                       placeholders::error, new_connection));
}

void SecuredNetworkManager::accept_handler(const boost::system::error_code& e, std::shared_ptr<P2PConnection> connection) {
    if(e) {
        std::cerr << "Accept Error:" << e.message() << std::endl;
    } else {
        connection->async_handshake();
        storeConnection(connection);
        storeNeighbor(connection->connectionID());
        start_accept();
    }
}

int SecuredNetworkManager::addNeighbor(const Node &node) {
    uint32_t connectionID = getConnectionID();
    auto connection = std::make_shared<P2PConnection>(connectionID, io_context_, ssl_context_, inbox_);

    for(int retryCount = 5; retryCount > 0; retryCount--) {
        if (connection->connect(node.ip_address(), node.port()) == 0) {
            storeConnection(connection);
            storeNeighbor(connectionID);
            return connectionID;
        }
        std::cout << "ConnectionID" << connectionID << std::endl;
        std::cout << "IP: " << node.ip_address().to_string() << " , Port: " << node.port() << std::endl;
        std::cout << "Connection refused: retrying after 200 milliseconds" << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(200));
    }

    return -1;
}

void SecuredNetworkManager::connectToCA(const std::string& ip_address, uint16_t port) {
    centralInstance_ = std::make_shared<P2PConnection>(CENTRAL, io_context_, ssl_context_, inbox_);
    while(centralInstance_->connect(ip::address_v4::from_string(ip_address), port) != 0) {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}

uint32_t SecuredNetworkManager::getConnectionID() {
    std::lock_guard<std::mutex> lock(connectionMutex_);
    uint32_t connectionID = maxConnectionID_;
    maxConnectionID_++;
    return connectionID;
}

int SecuredNetworkManager::sendMessage(OutgoingMessage msg) {
    std::lock_guard<std::mutex> lock(connectionMutex_);
    if(msg.receiverID() == BROADCAST) {
        for(auto& connection : connections_)
            if(connection.second->is_open())
                connection.second->send(msg);
    } else if(msg.receiverID() == SELF) {
        ReceivedMessage receivedMessage(SELF, msg.header()[0], SELF, msg.body());
        inbox_.push(std::move(receivedMessage));
    } else if(msg.receiverID() == CENTRAL) {
        if (!centralInstance_->is_open())
            return -1;
        centralInstance_->send(msg);
    } else {
        if(connections_.count(msg.receiverID()) < 1) {
            std::cout << msg.receiverID() << std::endl;
            return -1;
        }
        if(!connections_[msg.receiverID()]->is_open())
            return -1;
        connections_[msg.receiverID()]->send(msg);
    }
    return 0;
}

std::vector<uint32_t> SecuredNetworkManager::neighbors() {
    return neighbors_;
}

void SecuredNetworkManager::storeNeighbor(uint32_t connectionID) {
    std::lock_guard<std::mutex> lock(neighborMutex_);
    neighbors_.push_back(connectionID);
}

void SecuredNetworkManager::storeConnection(std::shared_ptr<P2PConnection> connection) {
    std::lock_guard<std::mutex> lock(connectionMutex_);
    connections_.insert(std::pair(connection->connectionID(), connection));
}

void SecuredNetworkManager::terminate() {
    for(auto& connection : connections_)
        connection.second->disconnect();
    centralInstance_->disconnect();
}

ext: cpp


text:
#ifndef TCONCURRENT_LAZY_SYNC_WAIT_HPP
#define TCONCURRENT_LAZY_SYNC_WAIT_HPP

#include <tconcurrent/detail/tvoid.hpp>
#include <tconcurrent/lazy/cancelation_token.hpp>
#include <tconcurrent/lazy/detail.hpp>
#include <tconcurrent/operation_canceled.hpp>

#include <boost/variant2/variant.hpp>

#include <condition_variable>
#include <mutex>

namespace tconcurrent
{
namespace lazy
{
namespace detail
{
template <typename T>
struct sync_state
{
  struct v_none
  {
  };
  struct v_value
  {
    T value;
  };
  struct v_exception
  {
    std::exception_ptr exc;
  };

  std::mutex mtx;
  std::condition_variable cv;
  boost::variant2::variant<v_none, v_exception, v_value> data;
};

template <class T>
struct sync_receiver_base
{
  sync_state<T>* _state;
  cancelation_token* _cancelation_token;
  auto get_cancelation_token()
  {
    return _cancelation_token;
  }
  template <typename V>
  void _set(V&& v)
  {
    _cancelation_token->reset();
    {
      auto lk = std::unique_lock<std::mutex>{_state->mtx};
      _state->data.template emplace<std::decay_t<V>>(std::forward<V>(v));
    }
    _state->cv.notify_one();
  }
  template <typename E>
  void set_error(E&& e)
  {
    _set(typename sync_state<T>::v_exception{std::forward<E>(e)});
  }
  void set_done()
  {
    _set(typename sync_state<T>::v_exception{
        std::make_exception_ptr(operation_canceled())});
  }
};

template <class T>
struct sync_receiver : sync_receiver_base<T>
{
  sync_receiver(sync_state<T>* state, cancelation_token* ctoken)
    : sync_receiver_base<T>{state, ctoken}
  {
  }

  void set_value(T&& v)
  {
    this->_set(typename sync_state<T>::v_value{std::forward<T>(v)});
  }
};

template <>
struct sync_receiver<void> : sync_receiver_base<tvoid>
{
  sync_receiver(sync_state<tvoid>* state, cancelation_token* ctoken)
    : sync_receiver_base<tvoid>{state, ctoken}
  {
  }

  void set_value()
  {
    this->_set(sync_state<tvoid>::v_value{{}});
  }
};

template <class T, class Sender>
struct do_sync_wait
{
  static T sync_wait(Sender sender, cancelation_token& c)
  {
    using state_t = detail::sync_state<T>;
    state_t state;

    sender.submit(detail::sync_receiver<T>{&state, &c});

    {
      auto lk = std::unique_lock<std::mutex>{state.mtx};
      state.cv.wait(lk, [&state] {
        return !boost::variant2::holds_alternative<typename state_t::v_none>(
            state.data);
      });
    }

    if (auto const exc =
            boost::variant2::get_if<typename state_t::v_exception>(&state.data))
      std::rethrow_exception(exc->exc);
    return std::move(
        boost::variant2::get<typename state_t::v_value>(state.data).value);
  }
};

template <class Sender>
struct do_sync_wait<void, Sender>
{
  static void sync_wait(Sender sender, cancelation_token& c)
  {
    using state_t = detail::sync_state<tvoid>;
    state_t state;

    sender.submit(detail::sync_receiver<void>{&state, &c});

    {
      auto lk = std::unique_lock<std::mutex>{state.mtx};
      state.cv.wait(lk, [&state] {
        return !boost::variant2::holds_alternative<typename state_t::v_none>(
            state.data);
      });
    }

    if (auto const exc =
            boost::variant2::get_if<typename state_t::v_exception>(&state.data))
      std::rethrow_exception(exc->exc);
  }
};
}

/** Run \p sender to its completion and return the result.
 */
template <class Sender>
auto sync_wait(Sender&& sender, cancelation_token& c)
{
  using return_type = detail::extract_single_value_type_t<std::decay_t<Sender>>;
  return detail::do_sync_wait<return_type, std::decay_t<Sender>>::sync_wait(
      std::forward<Sender>(sender), c);
}
}
}

#endif

ext: hpp

max_stars_repo_name: TankerHQ/tconcurrent

max_issues_repo_name: TankerHQ/tconcurrent

max_forks_repo_name: TankerHQ/tconcurrent


text:
//******************************************************************************
// RCF - Remote Call Framework
//
// Copyright (c) 2005 - 2019, Delta V Software. All rights reserved.
// http://www.deltavsoft.com
//
// RCF is distributed under dual licenses - closed source or GPL.
// Consult your particular license for conditions of use.
//
// If you have not purchased a commercial license, you are using RCF
// under GPL terms.
//
// Version: 3.1
// Contact: support <at> deltavsoft.com
//
//******************************************************************************

#ifndef INCLUDE_SF_QSTRING_HPP
#define INCLUDE_SF_QSTRING_HPP

#include <QString>

#include <boost/config.hpp>

#include <SF/Archive.hpp>
#include <SF/Stream.hpp>

#include <SF/QByteArray.hpp>

namespace SF {

    // QString
    inline void serialize(SF::Archive & ar, QString & qobj)
    {
        SERIALIZE_QT_OBJECT
    }

} // namespace SF

#endif // ! INCLUDE_SF_QSTRING_HPP


text:
// stdlib
#include <iostream>
#include <iomanip>
#include <map>
#include <future>
#include <thread>
#include <fstream>

// xerces
#include <xercesc/sax2/SAX2XMLReader.hpp>
#include <xercesc/sax2/XMLReaderFactory.hpp>
#include <xercesc/sax2/DefaultHandler.hpp>
#include <xercesc/util/XMLString.hpp>

#include <boost/algorithm/string/trim.hpp>

#include "../../../libs/cxxopts/include/cxxopts.hpp"

// local files
#include "countPagesXercesHandler.hpp"

namespace {
	class SingleFileCounter {
		public:
			SingleFileCounter(std::string path)
				:_path(path)
			{}

			std::size_t operator()(void)
			{
				xercesc::SAX2XMLReader* parser = xercesc::XMLReaderFactory::createXMLReader();
				parser->setFeature(xercesc::XMLUni::fgSAX2CoreValidation, true);
				parser->setFeature(xercesc::XMLUni::fgSAX2CoreNameSpaces, true);   // optional
				parser->setFeature(xercesc::XMLUni::fgXercesSchema , false);   // optional

				CountPagesXercesHandler handler;
				parser->setContentHandler(&handler);
				parser->setErrorHandler(&handler);

				parser->parse(_path.c_str());
				delete parser;

				return handler.count();
			}

		private:
			std::string _path;
	};

	std::vector<std::string> read_lines_from_file(std::istream& input)
	{
		std::vector<std::string> lines;
		std::string line;
		while(std::getline(input,line))
		{
			boost::trim(line);
			if(!line.empty() && line.front() != '#')
				lines.push_back(line);
		}

		return lines;
	}
}

int main(int argc, char* argv[])
{
	cxxopts::Options options("count_pages", "Counts the pages in a Wikipedia xml dump. Can be used for displaying progress in other parsers.");
	options.add_options()
		("help", "Produce this help message.")
		("i,input-paths-file", "File of which each line is absolute path to an xml file that is part of a Wikipedia dump.", cxxopts::value<std::string>())
		;
	auto parsed_options = options.parse(argc, argv);

	// display help if --help was specified
	if (parsed_options.count("help")){
		std::cout << options.help() << std::endl;
		return 0;
	}

	if(!parsed_options.count("input-paths-file"))
		throw std::logic_error("Please specify the parameter --input-paths-file.");

	const std::string input_paths_filepath = parsed_options["input-paths-file"].as<std::string>();
	std::ifstream input_paths_file(input_paths_filepath);
	const auto paths = read_lines_from_file(input_paths_file);

	if(paths.size() == 0)
		throw std::logic_error("Paths file does not contain any uncommented lines.");

	// init xerces
	xercesc::XMLPlatformUtils::Initialize();

	std::vector<std::future<std::size_t>> futures;
	futures.reserve(paths.size());
	for (auto path : paths)
		futures.emplace_back(std::async(std::launch::async, SingleFileCounter(path)));

	std::map<std::string, std::size_t> page_counts;
	for (std::size_t i = 0; i < futures.size(); i++)
		page_counts[paths[i]] = futures[i].get();

	xercesc::XMLPlatformUtils::Terminate();

	for (auto file : page_counts)
		std::cout << file.first << " " << file.second << std::endl;

	return 0;
}


text:
// This file is part of libigl, a simple c++ geometry processing library.
//
// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public License
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.
#include "arap_linear_block.h"
#include "verbose.h"
#include "cotmatrix_entries.h"
#include <Eigen/Dense>

template <typename MatV, typename MatF, typename Scalar>
IGL_INLINE void igl::arap_linear_block(
  const MatV & V,
  const MatF & F,
  const int d,
  const igl::ARAPEnergyType energy,
  Eigen::SparseMatrix<Scalar> & Kd)
{
  switch(energy)
  {
    case ARAP_ENERGY_TYPE_SPOKES:
      return igl::arap_linear_block_spokes(V,F,d,Kd);
      break;
    case ARAP_ENERGY_TYPE_SPOKES_AND_RIMS:
      return igl::arap_linear_block_spokes_and_rims(V,F,d,Kd);
      break;
    case ARAP_ENERGY_TYPE_ELEMENTS:
      return igl::arap_linear_block_elements(V,F,d,Kd);
      break;
    default:
      verbose("Unsupported energy type: %d\n",energy);
      assert(false);
  }
}

template <typename MatV, typename MatF, typename Scalar>
IGL_INLINE void igl::arap_linear_block_spokes(
  const MatV & V,
  const MatF & F,
  const int d,
  Eigen::SparseMatrix<Scalar> & Kd)
{
  using namespace std;
  using namespace Eigen;
  // simplex size (3: triangles, 4: tetrahedra)
  int simplex_size = F.cols();
  // Number of elements
  int m = F.rows();
  // Temporary output
  Matrix<int,Dynamic,2> edges;
  Kd.resize(V.rows(), V.rows());
  vector<Triplet<Scalar> > Kd_IJV;
  if(simplex_size == 3)
  {
    // triangles
    Kd.reserve(7*V.rows());
    Kd_IJV.reserve(7*V.rows());
    edges.resize(3,2);
    edges <<
      1,2,
      2,0,
      0,1;
  }else if(simplex_size == 4)
  {
    // tets
    Kd.reserve(17*V.rows());
    Kd_IJV.reserve(17*V.rows());
    edges.resize(6,2);
    edges <<
      1,2,
      2,0,
      0,1,
      3,0,
      3,1,
      3,2;
  }
  // gather cotangent weights
  Matrix<Scalar,Dynamic,Dynamic> C;
  cotmatrix_entries(V,F,C);
  // should have weights for each edge
  assert(C.cols() == edges.rows());
  // loop over elements
  for(int i = 0;i<m;i++)
  {
    // loop over edges of element
    for(int e = 0;e<edges.rows();e++)
    {
      int source = F(i,edges(e,0));
      int dest = F(i,edges(e,1));
      double v = 0.5*C(i,e)*(V(source,d)-V(dest,d));
      Kd_IJV.push_back(Triplet<Scalar>(source,dest,v));
      Kd_IJV.push_back(Triplet<Scalar>(dest,source,-v));
      Kd_IJV.push_back(Triplet<Scalar>(source,source,v));
      Kd_IJV.push_back(Triplet<Scalar>(dest,dest,-v));
    }
  }
  Kd.setFromTriplets(Kd_IJV.begin(),Kd_IJV.end());
  Kd.makeCompressed();
}

template <typename MatV, typename MatF, typename Scalar>
IGL_INLINE void igl::arap_linear_block_spokes_and_rims(
  const MatV & V,
  const MatF & F,
  const int d,
  Eigen::SparseMatrix<Scalar> & Kd)
{
  using namespace std;
  using namespace Eigen;
  // simplex size (3: triangles, 4: tetrahedra)
  int simplex_size = F.cols();
  // Number of elements
  int m = F.rows();
  // Temporary output
  Kd.resize(V.rows(), V.rows());
  vector<Triplet<Scalar> > Kd_IJV;
  Matrix<int,Dynamic,2> edges;
  if(simplex_size == 3)
  {
    // triangles
    Kd.reserve(7*V.rows());
    Kd_IJV.reserve(7*V.rows());
    edges.resize(3,2);
    edges <<
      1,2,
      2,0,
      0,1;
  }else if(simplex_size == 4)
  {
    // tets
    Kd.reserve(17*V.rows());
    Kd_IJV.reserve(17*V.rows());
    edges.resize(6,2);
    edges <<
      1,2,
      2,0,
      0,1,
      3,0,
      3,1,
      3,2;
    // Not implemented yet for tets
    assert(false);
  }
  // gather cotangent weights
  Matrix<Scalar,Dynamic,Dynamic> C;
  cotmatrix_entries(V,F,C);
  // should have weights for each edge
  assert(C.cols() == edges.rows());
  // loop over elements
  for(int i = 0;i<m;i++)
  {
    // loop over edges of element
    for(int e = 0;e<edges.rows();e++)
    {
      int source = F(i,edges(e,0));
      int dest = F(i,edges(e,1));
      double v = C(i,e)*(V(source,d)-V(dest,d))/3.0;
      // loop over edges again
      for(int f = 0;f<edges.rows();f++)
      {
        int Rs = F(i,edges(f,0));
        int Rd = F(i,edges(f,1));
        if(Rs == source && Rd == dest)
        {
          Kd_IJV.push_back(Triplet<Scalar>(Rs,Rd,v));
          Kd_IJV.push_back(Triplet<Scalar>(Rd,Rs,-v));
        }else if(Rd == source)
        {
          Kd_IJV.push_back(Triplet<Scalar>(Rd,Rs,v));
        }else if(Rs == dest)
        {
          Kd_IJV.push_back(Triplet<Scalar>(Rs,Rd,-v));
        }
      }
      Kd_IJV.push_back(Triplet<Scalar>(source,source,v));
      Kd_IJV.push_back(Triplet<Scalar>(dest,dest,-v));
    }
  }
  Kd.setFromTriplets(Kd_IJV.begin(),Kd_IJV.end());
  Kd.makeCompressed();
}

template <typename MatV, typename MatF, typename Scalar>
IGL_INLINE void igl::arap_linear_block_elements(
  const MatV & V,
  const MatF & F,
  const int d,
  Eigen::SparseMatrix<Scalar> & Kd)
{
  using namespace std;
  using namespace Eigen;
  // simplex size (3: triangles, 4: tetrahedra)
  int simplex_size = F.cols();
  // Number of elements
  int m = F.rows();
  // Temporary output
  Kd.resize(V.rows(), F.rows());
  vector<Triplet<Scalar> > Kd_IJV;
  Matrix<int,Dynamic,2> edges;
  if(simplex_size == 3)
  {
    // triangles
    Kd.reserve(7*V.rows());
    Kd_IJV.reserve(7*V.rows());
    edges.resize(3,2);
    edges <<
      1,2,
      2,0,
      0,1;
  }else if(simplex_size == 4)
  {
    // tets
    Kd.reserve(17*V.rows());
    Kd_IJV.reserve(17*V.rows());
    edges.resize(6,2);
    edges <<
      1,2,
      2,0,
      0,1,
      3,0,
      3,1,
      3,2;
  }
  // gather cotangent weights
  Matrix<Scalar,Dynamic,Dynamic> C;
  cotmatrix_entries(V,F,C);
  // should have weights for each edge
  assert(C.cols() == edges.rows());
  // loop over elements
  for(int i = 0;i<m;i++)
  {
    // loop over edges of element
    for(int e = 0;e<edges.rows();e++)
    {
      int source = F(i,edges(e,0));
      int dest = F(i,edges(e,1));
      double v = C(i,e)*(V(source,d)-V(dest,d));
      Kd_IJV.push_back(Triplet<Scalar>(source,i,v));
      Kd_IJV.push_back(Triplet<Scalar>(dest,i,-v));
    }
  }
  Kd.setFromTriplets(Kd_IJV.begin(),Kd_IJV.end());
  Kd.makeCompressed();
}

#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template IGL_INLINE void igl::arap_linear_block<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, int, igl::ARAPEnergyType, Eigen::SparseMatrix<double, 0, int>&);
#endif


text:
/* Copyright 2020 Norman J. Goldstein */
/*
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "IoGenOutput.h"
#include <memory>
#include <string>
#include <string.h>
#include <iostream>
#include <boost/filesystem.hpp>
#include "GenLogging.h"

GEN_IoOutput2::GEN_IoOutput2( bool doOps,
			      const std::string& outFileBaseName ) :
  GEN_IoOutput( doOps ),
  outFileBaseName_( outFileBaseName )
{
  using namespace std;

  // Do the H file
  string outHFileName( outFileBaseName );
  {
    outHFileName += ".h";
    ofh_.open( outHFileName );

    if( !ofh_ )
    {
      SLOG_EXCEPTION
	( "IoOutput::initialize: Error opening ouput h file \""
	  << outHFileName << "'" );
    }
  }

  // Do the CPP file
  {
    string outCxxFileName( outFileBaseName );
    outCxxFileName += ".cpp";
    ofc_.open( outCxxFileName );

    if( !ofc_ )
    {
      SLOG_EXCEPTION
	( "IoOutput2::initialize: Error opening ouput cpp file \""
	  << outCxxFileName << "'" );
    }

    ofc_<< "#include \""
	<< outHFileName
	<< '\"' << endl;

    if( !ofc_ )
    {
      SLOG_EXCEPTION
	( "IoOutput2::initialize: Error writing inclusion of output"
	  );
    }
  }
}// GEN_IoOutput2

bool GEN_IoOutput2::initialize( const char* inFileName,
				const char* )
{
  using namespace std;

  boost::filesystem::path inFilePath( inFileName );

  // Do the H file
  {
    const char* slash = strrchr( outFileBaseName_.c_str(), '/' );
    if( nullptr == slash ) {
      slash = outFileBaseName_.c_str();
    }
    else {
      ++slash;
    }

    string inclGuardName( slash );
    inclGuardName += "_H";

    ofh_ << "#ifndef "
	 << inclGuardName
	 << endl;

    ofh_ << "#define "
	 << inclGuardName
	 << endl
	 << endl;

    ofh_ << "#include <iosfwd>"
	 << "\n#include \"GenArchiveIO.h\""
	 << endl;

    ofh_ << "#include \"GenArchiveWriteDirector.h\""
	 << "\n#include \"GenArchiveReadDirector.h\""
	 << endl;

    if( !forwardDeclare_ )
    {
      ofh_<< "#include \"";

      if( 0 < headerPrefix_.size() )
      {
	ofh_ << headerPrefix_ << '/';
      }

      ofh_  << inFilePath.filename().string().c_str()
	    << "\"" << endl;
    }

    if( !ofh_ )
    {
      SLOG_ALERT( "Error writing to output h file " );

      return false;
    }
  }// H file

  // Do the CPP file
  {
    ofc_ << "#include <iostream>"
	   << endl;

    ofc_<< "#include \""
	<< inFilePath.filename().string()  // Otherwise includes quotes
	<< "\"" << endl;

    ofc_ << "#include \"GenArchiveIO.tpp\""
	 << endl;

    ofc_ << "#include \"GEN_Enum.h\""
	 << endl;

   if( !ofc_ )
   {
     SLOG_ALERT( "Error writing to output cpp file " );

     return false;
   }
  }// CPP file

  return true;
}// initialize

bool GEN_IoOutput2::finalize( void )
{
  using namespace std;

  // Complete the include guard
  ofh_ << "\n#endif"
       << endl;

  ofh_.close();

  if( !ofh_ )
  {
    SLOG_ALERT( "GEN_IoOutput2::finalize: Error closing H file" );

    return false;
  }

  ofc_.close();

  if( !ofc_ )
  {
    SLOG_ALERT( "GEN_IoOutput2::finalize: Error closing CPP file" );

    return false;
  }

  return true;
}// finalize

bool GEN_IoOutput2::initializeRecord( const char* tagName,
				      const char* recordName )
{
  using namespace std;
#if 1
  cout << "Initializing record: "
	       << tagName << ' '
       << recordName << endl;
#endif

  // Write to header file

  if( !forwardDeclare( tagName, recordName ) )
  {
    SLOG_ALERT( "Forward declaring "
		<< tagName << ' ' << recordName );

    return false;
  }

  ofh_ << "\nnamespace GenArchive\n{" << endl;

  ofh_ << "extern template\n "
       << "bool write( std::ostream& os, const "
       << recordName
       << "& var );"
       << endl;

  ofh_ << "extern template\n "
       << "bool read( std::istream& is, "
       << recordName
       << "& var );"
       << endl;

  ofh_ << "extern template\n "
       << "bool write( const char* fileName, const "
       << recordName
       << "& var );"
       << endl;

  ofh_ << "extern template\n "
       << "bool read( const char* fileName, "
       << recordName
       << "& var );"
       << endl;

  ofh_ << "\ntemplate< class RWD >\n "
       << "bool copy( RWD& rwd, "
       << "typename RWD::template IoRefrType< "
       << recordName
       << " > var );"
       << endl;

  ofh_ << "extern template\n "
       << "bool copy( WriteDirector& wd, const "
       << recordName
       << "& var );"
       << endl;

  ofh_ << "extern template\n "
       << "bool copy( ReadDirector& rd, "
       << recordName
       << "& var );"
       << endl;

  ofh_ << "}" << endl; // Close off GenArchive namespace

  if( doOps_ )
  {
    ofh_ << "\n"
	 << "std::ostream& operator<<( std::ostream& os, const "
	 << recordName
	 << "& var );"
	 << endl;

    ofh_ << "std::istream& operator>>( std::istream& is, "
	 << recordName
	 << "& var );"
	 << endl;
  }

  if( !ofh_ )
  {
    SLOG_ALERT( "initializeRecord: Error writing to header file" );

    return false;
  }

  // Write to source file

  ofc_
    << "\nusing namespace std;\n"
    << "\nnamespace GenArchive\n{" << endl
    << "template< class RWD >\n"
    << "bool copy( RWD& rwd, "
    << "typename RWD::template IoRefrType< "
    << recordName
    << " > var )\n"
    << '{' << endl;

  ofc_
    << "  readWrite( rwd, \"{\" );\n"
    << "  writeOnly( rwd, \"\\n\" );\n"
    << endl;

  if( !ofc_ )
  {
    SLOG_ALERT( "initializeRecord: Error writing to source file" );

    return false;
  }

  return true;
}// initializeRecord

bool GEN_IoOutput2::finalizeRecord( const char* recordName )
{
  using namespace std;

  ofc_
    << "  rwd.indent();\n"
    << endl;

  ofc_
    << "  return\n"
    << "  readWrite( rwd, \"}\" )"
    << endl;

  ofc_
    << "  && !rwd.sss().fail();\n"
    << "} // copy( "
    << recordName
    << " )"
    << endl;

  ofc_
    << "\ntemplate bool copy( WriteDirector& wd, const "
    << recordName
    << "& var );"
    << endl;

  ofc_
    << "template bool copy( ReadDirector& rd, "
    << recordName
    << "& var );"
    << endl;

  ofc_
    << "\ntemplate bool write( ostream& os, const "
    << recordName
    << "& var );"
    << endl;

  ofc_
    << "template bool read( istream& is, "
    << recordName
    << "& var );"
    << endl;

  ofc_
    << "template bool write( const char* fileName, const "
    << recordName
    << "& var );"
    << endl;

  ofc_
    << "template bool read( const char* fileName, "
    << recordName
    << "& var );"
    << endl;

  ofc_
    << "}" << endl;  // Close namespace GenArchive

  if( doOps_ )
  {
    ofc_
      << "\nostream& operator<<( ostream& os, const "
      << recordName
      << "& var )\n"
      << "{\n"
      << "  if( !GenArchive::write( os, var ) )\n"
      << "  {\n"
      << "    os.setstate( ios::failbit );\n"
      << "  }\n"
      << "  return os;\n"
      << "}// operator<<("
      << recordName
      << ")"
      << endl;

    ofc_
      << "\nistream& operator>>( istream& is, "
      << recordName
      << "& var )\n"
      << "{\n"
      << "  if( !GenArchive::read( is, var ) )\n"
      << "  {\n"
      << "    is.setstate( ios::failbit );\n"
      << "  }\n"
      << "  return is;\n"
      << "}// operator>>("
      << recordName
      << ")"
      << endl;
  }

  if( !ofc_ )
  {
    SLOG_ALERT( "finalizeRecord: Error writing to source file" );

    return false;
  }

  return true;
}// finalizeRecord

bool GEN_IoOutput2::writeField( const char* fieldName,
			       const char* recordName )
{
  using namespace std;

  ofc_
    << "  if( !copy( rwd, var."
    << fieldName
    << ", \""
    << fieldName
    << "\" ) )"
    << endl;

  ofc_
    << "  {\n"
    << "    cerr << \"copy<"
    << recordName
    << ">: Error at member name: "
    << fieldName << "\"\n"
    << "         << endl;"
    << endl;

  ofc_
    << "\n    return false;\n"
    << "  }\n"
    << endl;

  if( !ofc_ )
  {
    SLOG_ALERT( "writeField: Error writing to source file" );

    return false;
  }

  return true;
}// writeField

bool GEN_IoOutput2::initializeEnum( const char* recordName,
				    const char* integerName )
{
  using namespace std;

#if 0
  const char* tagName = "enum";

  // Does not work.  Forward declaring requires the underlying
  // integer type, which may be different for gcc and clang.
  // Moreover, declaring explicitly with the integer type
  // conflicts with the implict enum declaration
  //
  string trailer( ": " );
  trailer += integerName;

  if( !forwardDeclare( tagName,
		       recordName,
		       trailer.c_str() ) )
  {
    SLOG_ALERT( "Forward declaring "
		<< tagName << ' ' << recordName );

    return false;
  }

  ofh_ << "\nnamespace GenArchive{" << endl;

  ofh_ << "\nextern template\n "
       << "bool copy( WriteDirector& wd, const "
       << recordName
       << "& var );"
       << endl;

  ofh_ << "extern template\n "
       << "bool copy( ReadDirector& rd, "
       << recordName
       << "& var );"
       << endl;
#endif

 ofc_
   << "\ntemplate<>\n"
   << "const std::vector< GEN_Enum< "
   << recordName
   << " >::ValString > GEN_Enum< "
   << recordName
   << " >::vsVec_ = {\n" << flush;

 return !ofc_.fail();
}// initializeEnum

bool GEN_IoOutput2::finalizeEnum( const char* recordName )
{
  using namespace std;

  ofc_ << "\n};" << endl;

  ofc_
    << "template<>\n"
    << "typename GEN_Enum< "
    << recordName
    << " >::bm_type GEN_Enum< "
    << recordName
    << " >::bm_ = {};" << endl;

  ofc_
    << "static GEN_Enum< "
    << recordName
    << " > enumObject_"
    << enumObjectCount_++
    << ';'
    << endl;

  ofc_ << "\nnamespace GenArchive{" << endl;

  ofc_
    << "template bool copy( WriteDirector& wd, const "
    << recordName
    << "& var );"
    << endl;

  ofc_
    << "template bool copy( ReadDirector& rd, "
    << recordName
    << "& var );"
    << endl;

  ofc_
    << "template bool copy( WriteDirector& wd, const "
    << recordName
    << "& var, const char* memb );"
    << endl;

  ofc_
    << "template bool copy( ReadDirector& rd, "
    << recordName
    << "& var, const char* memb );"
    << endl;

  // Close off namespace GenArchive
  ofc_ << "}" << endl;

  return !ofc_.fail();
}// finalizeEnum

bool GEN_IoOutput2::writeEnumField( const char* fieldName,
				   const char* fieldValue,
				   const std::string& recordName )
{
  using namespace std;

  ofc_
    << '{'
    << fieldValue
    << ", \""
    << fieldName
    << "\"}, ";

    return !ofc_.fail();
}// writeEnumField

max_stars_repo_name: normvcr/Projects

max_issues_repo_name: normvcr/Projects

max_forks_repo_name: normvcr/Projects


text:
#include <boost/test/unit_test.hpp>
#include <boost/test/data/test_case.hpp>
#include <boost/test/data/monomorphic.hpp>
#include <boost/algorithm/string/split.hpp>

#include <string>
#include <vector>
#include <memory>

#include "../../include/ast.hpp"

#include "test_setup.hpp"

namespace data = boost::unit_test::data;
namespace ast = rhea::ast;

namespace {
    // Datasets

    // Test cases
    BOOST_AUTO_TEST_SUITE (AST_function)

    BOOST_AUTO_TEST_CASE (call_empty_ast)
    {
        auto fname = ast::make_identifier<ast::Identifier>("f");
        auto node = std::make_unique<ast::Call>(std::move(fname));

        BOOST_TEST_MESSAGE("Testing AST Node " << node->to_string());

        BOOST_TEST((node->to_string() == "(Call,(Identifier,f))"));
    }

    BOOST_AUTO_TEST_CASE (call_positional_ast)
    {
        auto fname = ast::make_identifier<ast::Identifier>("f");
        auto arg1 = ast::make_expression<ast::Integer>(42);
        auto arg2 = ast::make_expression<ast::String>("foo");

        ast::child_vector<ast::Expression> args;
        args.emplace_back(std::move(arg1));
        args.emplace_back(std::move(arg2));

        auto node = std::make_unique<ast::Call>(std::move(fname), args);

        BOOST_TEST_MESSAGE("Testing AST Node " << node->to_string());

        auto target = "(Call,(Identifier,f),(Integral,42,0),(String,\"foo\"))";
        BOOST_TEST((node->to_string() == target));
    }

    BOOST_AUTO_TEST_CASE (call_named_ast)
    {
        auto fname = ast::make_identifier<ast::Identifier>("f");

        auto arg1 = ast::make_expression<ast::Integer>(42);
        auto arg2 = ast::make_expression<ast::String>("foo");

        auto named1 = std::make_unique<ast::NamedArgument>("a", std::move(arg1));
        auto named2 = std::make_unique<ast::NamedArgument>("b", std::move(arg2));

        ast::child_vector<ast::NamedArgument> args;
        args.emplace_back(std::move(named1));
        args.emplace_back(std::move(named2));

        auto node = std::make_unique<ast::Call>(std::move(fname), args);
        BOOST_TEST((node->arguments.size() == 2));
        BOOST_TEST((node->arguments[0].index() == 1));
        auto a1 = boost::variant2::get<1>(node->arguments[0]).get();
        BOOST_TEST((a1->name == "a"));
        // auto a1 = boost::variant2::get_if<std::unique_ptr<ast::NamedArgument>>(&(node->arguments[0]));
        // BOOST_TEST((a1 != nullptr));

        BOOST_TEST_MESSAGE("Testing AST Node " << node->to_string());

        // auto target = "(Call,(Identifier,f),(NamedArgument,a,(Integral,42,0)),(NamedArgument,b,(String,\"foo\")))";
        // BOOST_TEST((node->to_string() == target));
    }

    BOOST_AUTO_TEST_CASE (generic_function_ast)
    {
        std::string fname { "f" };

        std::vector<std::unique_ptr<ast::Statement>> body_vector;
        auto body = std::make_unique<ast::Block>(body_vector);

        std::vector<std::unique_ptr<ast::Condition>> conditions_list;

        auto tid = ast::make_identifier<ast::Identifier>("T");
        auto tn = std::make_unique<ast::Typename>(std::move(tid));
        auto tp = std::make_unique<ast::TypePair>("t", std::move(tn));
        ast::GenericMatch gm { std::move(tp) };
        std::vector<ast::GenericMatch> generic_type_nodes;
        generic_type_nodes.emplace_back(std::move(gm));

        auto node = std::make_unique<ast::GenericDef>(
            ast::FunctionType::Basic,
            fname,
            generic_type_nodes,
            nullptr,
            nullptr,
            conditions_list,
            std::move(body)
        );

        BOOST_TEST_MESSAGE("Testing AST Node " << node->to_string());

        BOOST_TEST((node->type == ast::FunctionType::Basic));
        BOOST_TEST((node->name == fname));
        BOOST_TEST((node->generic_types.size() == generic_type_nodes.size()));

        BOOST_TEST((node->to_string() ==
        "(Def,0,f,(GenericTypes,(TypePair,t,(Typename,(Identifier,T),null,null))),null,null,(Conditions),(Block))"));
    }

    BOOST_AUTO_TEST_SUITE_END ()
}

max_stars_repo_name: momikey/rhea

max_issues_repo_name: momikey/rhea

max_forks_repo_name: momikey/rhea


text:
/*
 * patSampleChoiceSetWithObservations.cc
 *
 *  Created on: May 26, 2012
 *      Author: jchen
 */

#include "patSampleChoiceSetWithObservations.h"
#include "MHWeightFunction.h"
#include "MHPathGenerator.h"
#include "patNBParameters.h"
#include "patDisplay.h"
#include "patOd.h"
#include <boost/lexical_cast.hpp>
#include <set>
#include <unistd.h>

using namespace std;
//#include <thread>
patSampleChoiceSetWithObservations::patSampleChoiceSetWithObservations() {
	// TODO Auto-generated constructor stub

}

patSampleChoiceSetWithObservations::~patSampleChoiceSetWithObservations() {
	// TODO Auto-generated destructor stub
}

void patSampleChoiceSetWithObservations::averagePathProbas() {

	DEBUG_MESSAGE(
			"od counts"<<m_od_count.size()<<":"<<m_od_count.begin()->second);
	for (map<const patOd, map<const patMultiModalPath, double> >::const_iterator od_iter =
			m_od_path_probas.begin(); od_iter != m_od_path_probas.end();
			++od_iter) {
		for (map<const patMultiModalPath, double>::const_iterator path_iter =
				od_iter->second.begin(); path_iter != od_iter->second.end();
				++path_iter) {
			map<const patOd, int>::const_iterator find_od_count =
					m_od_count.find(od_iter->first);
			if (find_od_count == m_od_count.end()) {
				throw RuntimeException("not od count found");
			} else {

				m_path_obs_proba[path_iter->first] = path_iter->second
						/ (double) find_od_count->second;
			}
		}
	}
}

void patSampleChoiceSetWithObservations::sampleChoiceSet(
		MHPathGenerator* path_generator, string folder) {

	const string choice_set_folder = folder
			+ patNBParameters::the()->choiceSetFolder + "/";

	int num_threads = patNBParameters::the()->nbrOfThreads;
	if (m_observations.size() <= num_threads) {
		num_threads = m_observations.size();
	}
	DEBUG_MESSAGE( "threads: "<<num_threads<<", obs:"<<m_observations.size());

#pragma omp parallel num_threads( num_threads)

	{
#pragma omp for

		for (int j = 0; j < m_observations.size(); ++j) {
			cout << "START THREAD " << j;
			patNetworkBase* cloned_network =
					path_generator->getNetwork()->clone();

			MHPathGenerator* generator_clone = path_generator->clone();
			generator_clone->setNetwork(cloned_network);
			m_observations.at(j).sampleChoiceSet(generator_clone,
					choice_set_folder);

			delete generator_clone;
			generator_clone = NULL;
			delete cloned_network;
			cloned_network = NULL;
		}
	}
}
void patSampleChoiceSetWithObservations::addObservation(patObservation& obs,
		const bool& sample) {
	/**
	 * Get relevant OD first.
	 */
	if (obs.getId() == string("")) {
		obs.setId(boost::lexical_cast<string>(m_observations.size()));
	}

	map<const patMultiModalPath, double> path_probas =
			obs.getNormalizedPathProbas();
	set<patOd> od_set;

	unsigned long obs_id = 1;
	for (map<const patMultiModalPath, double>::const_iterator path_iter =
			path_probas.begin(); path_iter != path_probas.end(); ++path_iter) {
		patOd the_od(path_iter->first.getUpNode(),
				path_iter->first.getDownNode());
		pair<set<patOd>::const_iterator, bool> insert_result = od_set.insert(
				the_od);
		if (insert_result.second == true) {
//            DEBUG_MESSAGE("NEW OBSERVATION"<<obs.getId()+string("_")+boost::lexical_cast<string>(obs_id));
			if (sample == true) {
				patObservation new_obs;
				new_obs.setId(
						obs.getId() + string("_")
								+ boost::lexical_cast<string>(obs_id));
				new_obs.addPath(path_iter->first, path_iter->second);
				m_observations.push_back(new_obs);
				++obs_id;
			}
		}
		if (m_od_path_probas.find(the_od) == m_od_path_probas.end()) {
			m_od_path_probas[the_od];
			m_od_path_probas[the_od][path_iter->first] = 0.0;
		}
		m_od_path_probas[the_od][path_iter->first] += path_iter->second;
	}
	if (sample == false) {
		m_observations.push_back(obs);
	}
	for (set<patOd>::const_iterator od_iter = od_set.begin();
			od_iter != od_set.end(); ++od_iter) {
		if (m_od_count.find(*od_iter) == m_od_count.end()) {
			m_od_count[*od_iter] = 0;
		}
		++m_od_count[*od_iter];
	}
	//	DEBUG_MESSAGE("add a path finished");
}

ext: cc

max_stars_repo_name: godosou/smaroute

max_issues_repo_name: godosou/smaroute

max_forks_repo_name: godosou/smaroute


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

// See http://www.boost.org/libs/test for the library home page.
//
//! @file
//! An observer for monitoring the success/failure of the other observers
// ***************************************************************************

#ifndef BOOST_TEST_FRAMEWORK_INIT_OBSERVER_IPP_021105GER
#define BOOST_TEST_FRAMEWORK_INIT_OBSERVER_IPP_021105GER

// Boost.Test
#include <boost/test/test_framework_init_observer.hpp>
#include <boost/test/framework.hpp>
#include <boost/test/detail/suppress_warnings.hpp>

//____________________________________________________________________________//

namespace boost {
namespace unit_test {

//____________________________________________________________________________//

// ************************************************************************** //
// **************           framework_init_observer_t          ************** //
// ************************************************************************** //

void
framework_init_observer_t::clear()
{
    m_has_failure = false;
}

//____________________________________________________________________________//

void
framework_init_observer_t::test_start( counter_t, test_unit_id )
{
    clear();
}

//____________________________________________________________________________//

void
framework_init_observer_t::assertion_result( unit_test::assertion_result ar )
{
    switch( ar ) {
    case AR_FAILED: m_has_failure = true; break;
    default:
        break;
    }
}

//____________________________________________________________________________//

void
framework_init_observer_t::exception_caught( execution_exception const& )
{
    m_has_failure = true;
}

void
framework_init_observer_t::test_aborted()
{
    m_has_failure = true;
}

//____________________________________________________________________________//

bool
framework_init_observer_t::has_failed() const
{
    return m_has_failure;
}

//____________________________________________________________________________//

} // namespace unit_test
} // namespace boost

#include <boost/test/detail/enable_warnings.hpp>

#endif // BOOST_TEST_FRAMEWORK_INIT_OBSERVER_IPP_021105GER

ext: ipp


text:
#include <boost/pfr.hpp>

int
main ()
{
  return 0;
}


text:
/*
Title: Web API Client Library for Watch Inputs
Author: Matthew Stapleton (Capsicum Corporation) <matthew@capsicumcorp.com>
Description: This module connects to the ioMy Web API to pass various info back and forth
Copyright: Capsicum Corporation 2016-2017

This file is part of Watch Inputs which is part of the iOmy project.

iOmy is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

iOmy is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with iOmy.  If not, see <http://www.gnu.org/licenses/>.

*/

//Use Boost Chrono instead of C++11 chrono
#define BOOST_ASIO_DISABLE_STD_CHRONO

#include <stdio.h>
#include <cctype>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <istream>
#include <ostream>
#include <list>
#include <map>
#include <string>
#include <sstream>
#include <typeinfo>
#include <boost/chrono.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <boost/atomic/atomic.hpp>
#include <boost/asio.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/asio/system_timer.hpp>
#include <boost/bind.hpp>
#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/binary_from_base64.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include <boost/archive/iterators/remove_whitespace.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#ifdef __ANDROID__
#include <jni.h>
#endif
#include "moduleinterface.h"
#include "webapiclientlib.hpp"
#include "modules/commonlib/commonlib.h"
#include "modules/debuglib/debuglib.h"
#include "modules/dblib/dblib.h"
#include "modules/configlib/configlib.hpp"

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

static std::list<webapiclient_link_t *> webapi_links_queue;

//List is a pointer so can hold derived objects instead of just the base class
static std::list<webapiclient_comm_t *> webapi_comms_queue;

static std::list<webapiclient_thing_t *> webapi_things_queue;

static boost::recursive_mutex webapiclientlibmutex;

static boost::thread webapiclientlib_mainthread;

//Function Declarations
static bool webapiclientlib_add_zigbee_link_to_webapi_queue(const webapiclient_zigbeelink_t& zigbeelink);
static bool webapiclientlib_add_csrmesh_link_to_webapi_queue(const webapiclient_csrmeshlink_t& csrmeshlink);
static bool webapiclientlib_add_zigbee_comm_to_webapi_queue(const webapiclient_zigbeecomm_t& zigbeecomm);
static bool webapiclientlib_add_bluetooth_comm_to_webapi_queue(const webapiclient_bluetoothcomm_t& bluetoothcomm);
static bool webapiclientlib_add_csrmesh_thing_to_webapi_queue(const webapiclient_csrmeshthing_t& csrmeshthing);
static void webapiclientlib_setneedtoquit(bool val);
static int webapiclientlib_getneedtoquit();
static int webapiclientlib_start(void);
static void webapiclientlib_stop(void);
static int webapiclientlib_init(void);
static void webapiclientlib_shutdown(void);

//C Exports
extern "C" {

BOOST_SYMBOL_EXPORT moduleinfo_ver_generic_t *webapiclientlib_getmoduleinfo();

//JNI Exports
#ifdef __ANDROID__
JNIEXPORT jlong JNICALL Java_com_capsicumcorp_iomy_libraries_watchinputs_WebApiClientLib_jnigetmodulesinfo( JNIEnv* UNUSED(env), jobject UNUSED(obj));
#endif
}

//Module Interface Definitions

static webapiclientlib_ifaceptrs_ver_1_t webapiclientlib_ifaceptrs_ver_1={
  webapiclientlib_init,
  webapiclientlib_shutdown,
  webapiclientlib_add_zigbee_link_to_webapi_queue,
  webapiclientlib_add_csrmesh_link_to_webapi_queue,
  webapiclientlib_add_zigbee_comm_to_webapi_queue,
  webapiclientlib_add_bluetooth_comm_to_webapi_queue,
  webapiclientlib_add_csrmesh_thing_to_webapi_queue
};

static moduleiface_ver_1_t webapiclientlib_ifaces[]={
  {
    &webapiclientlib_ifaceptrs_ver_1,
    WEBAPICLIENTLIBINTERFACE_VER_1
  },
  {
    nullptr, 0
	}
};

static moduledep_ver_1_t webapiclientlib_deps[]={
  {
    "debuglib",
    nullptr,
    DEBUGLIBINTERFACE_VER_1,
    1
  },
  {
    "dblib",
		nullptr,
    DBLIBINTERFACE_VER_1,
    1
  },
  {
    "configlib",
		nullptr,
    CONFIGLIBINTERFACECPP_VER_1,
    1
  },
  {
    nullptr, nullptr, 0, 0
  }
};

//NOTE: Need to cast the deps as in this library it is defined as a fixed size
static const moduleinfo_ver_1_t webapiclientlib_moduleinfo_ver_1={
  MODULEINFO_VER_1,
  "webapiclientlib",
  webapiclientlib_init,
  webapiclientlib_shutdown,
  webapiclientlib_start,
  webapiclientlib_stop,
  nullptr,
  nullptr,
	(moduleiface_ver_1_t (* const)[]) &webapiclientlib_ifaces,
  (moduledep_ver_1_t (*)[]) &webapiclientlib_deps,
};

//Find a pointer to module interface pointer
//Returns the pointer to the interface or nullptr if not found
//NOTE: A little slower than referencing the array element directly, but less likely to cause a programming fault
//  due to rearranging depencencies
static const void *webapiclientlib_getmoduledepifaceptr(const char *modulename, unsigned ifacever) {
	int i=0;

	while (webapiclientlib_deps[i].modulename) {
		if (std::strcmp(webapiclientlib_deps[i].modulename, modulename)==0) {
			if (webapiclientlib_deps[i].ifacever==ifacever) {
				return webapiclientlib_deps[i].ifaceptr;
			}
		}
		++i;
	}
	return nullptr;
}

//Returns an encoded string from a unencoded string
//Based on http://stackoverflow.com/questions/10521581/base64-encode-using-boost-throw-exception/10973348#10973348
//The line break inserting at character 76 has been removed
static std::string base64_encode(const std::string& s) {
  typedef boost::archive::iterators::base64_from_binary<boost::archive::iterators::transform_width<std::string::const_iterator,6,8> > it_base64_t;

  unsigned int writePaddChars = (3-s.length()%3)%3;
  std::string base64(it_base64_t(s.begin()),it_base64_t(s.end()));
  base64.append(writePaddChars,'=');

	return base64;
}

//Returns a decoded string from a base64 encoded string
//Based on http://stackoverflow.com/questions/10521581/base64-encode-using-boost-throw-exception/10973348#10973348
static std::string base64_decode(const std::string& base64) {
	typedef boost::archive::iterators::transform_width< boost::archive::iterators::binary_from_base64<boost::archive::iterators::remove_whitespace<std::string::const_iterator> >, 8, 6 > it_binary_t;
	std::string tmps=base64;

	unsigned int paddChars = count(tmps.begin(), tmps.end(), '=');
  std::replace(tmps.begin(),tmps.end(),'=','A'); // replace '=' by base64 encoding of '\0'
  std::string result(it_binary_t(tmps.begin()), it_binary_t(tmps.end())); // decode
  result.erase(result.end()-paddChars,result.end());  // erase padding '\0' characters

	return result;
}

//From http://stackoverflow.com/questions/154536/encode-decode-urls-in-c
static std::string url_encode(const std::string &value) {
    std::ostringstream escaped;
    escaped.fill('0');
    escaped << std::hex;

    for (auto const& it : value) {
        std::string::value_type c = it;

        // Keep alphanumeric and other accepted characters intact
        if (std::isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
            escaped << c;
            continue;
        }

        // Any other characters are percent-encoded
        escaped << std::uppercase;
        escaped << '%' << std::setw(2) << int((unsigned char) c);
        escaped << std::nouppercase;
    }

    return escaped.str();
}

std::string link_to_json(const webapiclient_link_t& link) {
	using boost::property_tree::ptree;
	ptree pt;
	std::ostringstream tmphexstr;

	pt.put("CommId", link.localpk);
  if (typeid(link)==typeid(webapiclient_zigbeelink_t)) {
    pt.put("Type", 2); //2=Zigbee device
  } else if (typeid(link)==typeid(webapiclient_csrmeshlink_t)) {
    pt.put("Type", 15); //15=Qualcomm CSRmesh Link
  } else {
    debuglib_ifaceptrs_ver_1_t *debuglibifaceptr=(debuglib_ifaceptrs_ver_1_t *) webapiclientlib_getmoduledepifaceptr("debuglib", DEBUGLIBINTERFACE_VER_1);

    debuglibifaceptr->debuglib_printf(1, "%s: Unknown Typeid=%s\n", __func__, typeid(link).name());
  }
	pt.put("InfoName", link.modelname);

	//Zigbee Addresses are 64-bit hexidecimal without the 0x part
	tmphexstr.width(16);
	tmphexstr.fill('0');
	tmphexstr << std::uppercase << std::hex << link.addr;
	pt.put("SerialCode", tmphexstr.str());
	pt.put("Displayname", link.userstr);
  if (typeid(link)==typeid(webapiclient_csrmeshlink_t)) {
    pt.put("State", 1);
    pt.put("InfoManufacturer", "Qualcomm");
    pt.put("InfoManufacturerUrl", "www.qualcomm.com");
    pt.put("ConnCryptTypeId", 1);
    pt.put("ConnUsername", "");
    pt.put("ConnPassword", dynamic_cast<const webapiclient_csrmeshlink&>(link).networkKey);
  }
  if (typeid(link)==typeid(webapiclient_zigbeelink_t)) {
    ptree thingspt;
    for (const auto &thingit : dynamic_cast<const webapiclient_zigbeelink_t&>(link).things) {
      ptree thingpt;

      thingpt.put("Type", thingit.second.type);
      thingpt.put("State", thingit.second.state);
      thingpt.put("HWId", thingit.first);

      ptree iospt;
      for (const auto &ioit : thingit.second.io) {
        ptree iopt;

        iopt.put("RSType", ioit.rstype);
        iopt.put("UoM", ioit.uom);
        iopt.put("Type", ioit.iotype);
        iopt.put("Name", ioit.name);
        iopt.put("BaseConvert", ioit.baseconvert);
        iopt.put("SampleRate", ioit.samplerate);

        iospt.push_back(std::make_pair("", iopt));
      }
      thingpt.put_child("IOs", iospt);

      thingspt.push_back(std::make_pair("", thingpt));
    }
    pt.put_child("Things", thingspt);
  }
	std::ostringstream streamstr;
	write_json(streamstr, pt);

	return streamstr.str();
}

std::string comm_to_json(const webapiclient_comm_t& comm) {
  using boost::property_tree::ptree;
  ptree pt;

  pt.put("HubId", comm.hubpk);
  pt.put("Type", comm.type);
  pt.put("Name", comm.name);

  //Zigbee Addresses are 64-bit hexidecimal without the 0x part
  std::ostringstream tmphexstr;
  tmphexstr.width(16);
  tmphexstr.fill('0');
  tmphexstr << std::uppercase << std::hex << comm.addr;
  pt.put("Address", tmphexstr.str());

  std::ostringstream streamstr;
  write_json(streamstr, pt);

  return streamstr.str();
}

std::string thing_to_json(const webapiclient_thing_t& thing) {
  using boost::property_tree::ptree;
  ptree pt;
  ptree thingpt;
  std::ostringstream tmphexstr;

  thingpt.put("LinkId", thing.linkpk);
  thingpt.put("Type", thing.type);
  thingpt.put("State", thing.state);
  thingpt.put("HWId", thing.hwid);
  thingpt.put("Name", thing.name);
  if (typeid(thing)==typeid(webapiclient_csrmeshthing_t)) {
    const webapiclient_csrmeshthing_t& csrmeshthing=dynamic_cast<const webapiclient_csrmeshthing_t&>(thing);

    thingpt.put("SerialCode", csrmeshthing.serialcode);
    ptree iospt;
    for (const auto &ioit : csrmeshthing.io) {
      ptree iopt;

      iopt.put("RSType", ioit.rstype);
      iopt.put("UoM", ioit.uom);
      iopt.put("Type", ioit.iotype);
      iopt.put("Name", ioit.name);
      iopt.put("BaseConvert", ioit.baseconvert);
      iopt.put("SampleRate", ioit.samplerate);

      iospt.push_back(std::make_pair("", iopt));
    }
    thingpt.put_child("IOs", iospt);
  }
  std::ostringstream streamstr;
  write_json(streamstr, thingpt);

  return streamstr.str();
}

//Add a link to a queue for adding via the web api
static bool webapiclientlib_add_link_to_webapi_queue(webapiclient_link_t* link) {
  debuglib_ifaceptrs_ver_1_t *debuglibifaceptr=(debuglib_ifaceptrs_ver_1_t *) webapiclientlib_getmoduledepifaceptr("debuglib", DEBUGLIBINTERFACE_VER_1);

  debuglibifaceptr->debuglib_printf(1, "Entering %s\n", __func__);

  debuglibifaceptr->debuglib_printf(1, "%s: Adding device with address: %016" PRIX64 " to webapi queue\n", __func__, link->addr);

  {
    boost::lock_guard<boost::recursive_mutex> guard(webapiclientlibmutex);

    //Just add to the queue and quickly exit as the list can be pruned later in the webapi thread
    webapi_links_queue.push_back(link);
  }

  //Testing Code
  debuglibifaceptr->debuglib_printf(1, "%s: SUPER DEBUG: JSON output: \"%s\"\n", __func__, link_to_json(*link).c_str());

  debuglibifaceptr->debuglib_printf(1, "Exiting %s\n", __func__);
  return true;
}

//Add a zigbee link to a queue for adding via the web api
static bool webapiclientlib_add_zigbee_link_to_webapi_queue(const webapiclient_zigbeelink_t& zigbeelink) {
  webapiclient_zigbeelink_t *link=new webapiclient_zigbeelink_t;
  *link=zigbeelink;
  return webapiclientlib_add_link_to_webapi_queue(link);
}

//Add a CSRMesh link to a queue for adding via the web api
static bool webapiclientlib_add_csrmesh_link_to_webapi_queue(const webapiclient_csrmeshlink_t& csrmeshlink) {
  webapiclient_csrmeshlink_t *link=new webapiclient_csrmeshlink_t;
  *link=csrmeshlink;
  return webapiclientlib_add_link_to_webapi_queue(link);
}

//Add a comm to a queue for adding via the web api
static bool webapiclientlib_add_comm_to_webapi_queue(webapiclient_comm_t* comm) {
  debuglib_ifaceptrs_ver_1_t *debuglibifaceptr=(debuglib_ifaceptrs_ver_1_t *) webapiclientlib_getmoduledepifaceptr("debuglib", DEBUGLIBINTERFACE_VER_1);

  debuglibifaceptr->debuglib_printf(1, "Entering %s\n", __func__);

  debuglibifaceptr->debuglib_printf(1, "%s: Adding Comm with address: %016" PRIX64 " to webapi queue\n", __func__, comm->addr);
  {
    boost::lock_guard<boost::recursive_mutex> guard(webapiclientlibmutex);

    //Just add to the queue and quickly exit as the list can be pruned later in the webapi thread
    webapi_comms_queue.push_back(comm);
  }
  //Testing Code
  debuglibifaceptr->debuglib_printf(1, "%s: SUPER DEBUG: JSON output: \"%s\"\n", __func__, comm_to_json(*comm).c_str());

  debuglibifaceptr->debuglib_printf(1, "Exiting %s\n", __func__);
  return true;
}

//Add a zigbee comm to a queue for adding via the web api
static bool webapiclientlib_add_zigbee_comm_to_webapi_queue(const webapiclient_zigbeecomm_t& zigbeecomm) {
  webapiclient_zigbeecomm_t *comm=new webapiclient_zigbeecomm_t;
  *comm=zigbeecomm;
  return webapiclientlib_add_comm_to_webapi_queue(comm);
}

//Add a bluetooth comm to a queue for adding via the web api
static bool webapiclientlib_add_bluetooth_comm_to_webapi_queue(const webapiclient_bluetoothcomm_t& bluetoothcomm) {
  webapiclient_bluetoothcomm_t *comm=new webapiclient_bluetoothcomm_t;
  *comm=bluetoothcomm;
  return webapiclientlib_add_comm_to_webapi_queue(comm);
}

//Add a thing to a queue for adding via the web api
static bool webapiclientlib_add_thing_to_webapi_queue(webapiclient_thing_t* thing) {
  debuglib_ifaceptrs_ver_1_t *debuglibifaceptr=(debuglib_ifaceptrs_ver_1_t *) webapiclientlib_getmoduledepifaceptr("debuglib", DEBUGLIBINTERFACE_VER_1);

  debuglibifaceptr->debuglib_printf(1, "Entering %s\n", __func__);

  debuglibifaceptr->debuglib_printf(1, "%s: Adding device with name: %s to webapi queue\n", __func__, thing->name.c_str());
  {
    boost::lock_guard<boost::recursive_mutex> guard(webapiclientlibmutex);

    //Just add to the queue and quickly exit as the list can be pruned later in the webapi thread
    webapi_things_queue.push_back(thing);
  }

  //Testing Code
  debuglibifaceptr->debuglib_printf(1, "%s: SUPER DEBUG: JSON output: \"%s\"\n", __func__, thing_to_json(*thing).c_str());

  debuglibifaceptr->debuglib_printf(1, "Exiting %s\n", __func__);
  return true;
}

//Add a CSRMesh thing to a queue for adding via the web api
static bool webapiclientlib_add_csrmesh_thing_to_webapi_queue(const webapiclient_csrmeshthing_t& csrmeshthing) {
  webapiclient_csrmeshthing_t *thing=new webapiclient_csrmeshthing_t;
  *thing=csrmeshthing;
  return webapiclientlib_add_thing_to_webapi_queue(thing);
}

//Setup a http request
//Only POST is supported at the moment
class httpclient {
private:
	//Name, Value pair
	std::map<std::string, std::string> headers;

	//Name, Value pair
	std::map<std::string, std::string> formfields;
	std::string httppath;
	bool haveHttpAuth=false;
	std::string httpusername;
	std::string httppassword;
public:
	httpclient() {
		addHeader("Accept", "*/*");
		addHeader("User-Agent", "HTTP-Client 1.0");
		addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
	}

	void addHeader(const std::string& name, const std::string& value) {
		headers[name]=value;
	}

	//Added an entire string as a header
	//Example: Host: www.example.com
	void addHeader(const std::string& str) {
		std::istringstream ss(str);
		std::string name, value;

		ss >> name;
		ss >> value;
		name.erase(name.end()-1); //Remove : at the end of the name
		addHeader(name, value);
	}

	void addFormField(const std::string& name, const std::string& value) {
		formfields[name]=value;
	}

	void addFormField(const std::string& name, const long int value) {
		std::ostringstream ss;

		ss << value;
		formfields[name]=ss.str();
	}

	void setPath(std::string path) {
		this->httppath=path;
	}

	void addHttpAuth(const std::string& username, const std::string& password) {
		this->httpusername=username;
		this->httppassword=password;
		haveHttpAuth=true;
	}

	std::string toString() {
		std::ostringstream stream;
		std::ostringstream body;

		//Generate the body from the form data
		bool firstfield=true;
		for (auto const& formfieldit : formfields) {
			if (!firstfield) {
				body << "&";
			}
			body << url_encode(formfieldit.first) << '=' << url_encode(formfieldit.second);
			firstfield=false;
		}
		stream << "POST " << httppath << " HTTP/1.0\r\n";
		if (haveHttpAuth) {
			std::ostringstream authstring;
			authstring << httpusername << ':' << httppassword;
			stream << "Authorization: Basic " << base64_encode(authstring.str()) << "\r\n";
		}
		for (auto const& headerit : headers) {
			stream << headerit.first << ": " << headerit.second << "\r\n";
		}
		stream << "Content-Length: " << body.str().size() << "\r\n";
		stream << "\r\n";
		stream << body.str();

		return stream.str();
	}
};

//Based on http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/example/cpp03/http/client/async_client.cpp
//  and http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/example/cpp03/timeouts/async_tcp_client.cpp
//NOTE: Android doesn't know about service: "http" so have to use 80 for the port
class asioclient {
private:
	boost::atomic<bool> stopped_;
	tcp::resolver resolver_;
  tcp::socket socket_;
  boost::asio::streambuf response_;
	boost::asio::system_timer deadline_;
	std::string httpserver;
	std::string httppath;
	std::string webapiport;
	std::string apiusername, apipassword;
	std::string httpusername;
	std::string httppassword;
  debuglib_ifaceptrs_ver_1_t *debuglibifaceptr;
	std::string http_version;
	unsigned httpstatuscode;
	long httpbodylen;
	std::list<webapiclient_link_t *>::iterator linksit;
	std::list<webapiclient_comm_t *>::iterator commsit;
  std::list<webapiclient_thing_t *>::iterator thingsit;
	int requestmode; //1=Adding Link, 2=Adding Comm, 3=Adding Thing

	//See http://stackoverflow.com/questions/21120361/boostasioasync-write-and-buffers-over-65536-bytes
	//These variables need to stay allocated while the asio request is active so can't be local to a single function
  httpclient hc;
  boost::asio::streambuf commrequest_;
  boost::asio::streambuf linkrequest_;
  boost::asio::streambuf thingrequest_;

public:
	asioclient(boost::asio::io_service& io_service)
		: stopped_(true), resolver_(io_service), socket_(io_service), deadline_(io_service) {
			//NOTE: When initialised globally, debuglibifaceptr won't be initialised yet
		}

	// Called by the user of the client class to initiate the connection process.
  // The endpoint iterator will have been obtained using a tcp::resolver.
  void start(const std::string& server, const std::string& webapiport, const std::string& path, const std::string& username, const std::string& password, const std::string &httpusername, const std::string &httppassword) {
		debuglibifaceptr=(debuglib_ifaceptrs_ver_1_t *) webapiclientlib_getmoduledepifaceptr("debuglib", DEBUGLIBINTERFACE_VER_1);

		// Form the request. We specify the "Connection: close" header so that the
    // server will close the socket after transmitting the response. This will
    // allow us to treat all data up until the EOF as the content.
		if (!stopped_) {
			return;
		}
		stopped_=false;
		httpserver=server;
		httppath=path;
		this->webapiport=webapiport;
		apiusername=username;
		apipassword=password;
		this->httpusername=httpusername;
		this->httppassword=httppassword;

		//NOTE: We set the Mode and Data later on when submitting the request
		hc.setPath(httppath);
		if (httpusername != "") {
			//Send the http password straight away to reduce the number of packets
			hc.addHttpAuth(httpusername, httppassword);
		}
		hc.addHeader("Host", httpserver);
		hc.addFormField("Version", "0.4.11");
		if (apiusername != "") {
			std::ostringstream tmpstr;
			tmpstr << "[\"" << apiusername << "\",\"" << apipassword << "\"]";
			hc.addFormField("Access", tmpstr.str());
		}
		//Loop through the zigbee comms and links queues adding each one at a time
		{
			boost::lock_guard<boost::recursive_mutex> guard(webapiclientlibmutex);
			if (webapi_links_queue.empty() && webapi_comms_queue.empty() && webapi_things_queue.empty()) {
				//No need to connect if the queue is empty
				return;
			}
			commsit=webapi_comms_queue.begin();
			linksit=webapi_links_queue.begin();
      thingsit=webapi_things_queue.begin();
		}
		// Start an asynchronous resolve to translate the server and service names
    // into a list of endpoints.
		tcp::resolver::query query(httpserver, this->webapiport);
		resolver_.async_resolve(query,
			boost::bind(&asioclient::handle_resolve, this,
				boost::asio::placeholders::error,
				boost::asio::placeholders::iterator));

		//Set a starting deadline timer
    deadline_.expires_from_now(boost::chrono::seconds(60));

		// Start the deadline actor
    deadline_.async_wait(boost::bind(&asioclient::check_deadline, this));
	}

	// This function terminates all the actors to shut down the connection. It
  // may be called by the user of the client class, or by the class itself in
  // response to graceful termination or an unrecoverable error.
  void stop() {
		debuglibifaceptr=(debuglib_ifaceptrs_ver_1_t *) webapiclientlib_getmoduledepifaceptr("debuglib", DEBUGLIBINTERFACE_VER_1);

		if (stopped_) {
			return;
		}
		stopped_ = true;
    boost::system::error_code ignored_ec;
		try {
			socket_.shutdown(tcp::socket::shutdown_both, ignored_ec);
		} catch (std::exception& e) {
			//Ignore errors from this function for now
		}
    socket_.close(ignored_ec);
		deadline_.cancel();
		response_.consume(response_.size());
	}
private:
	void handle_resolve(const boost::system::error_code& err, tcp::resolver::iterator endpoint_iterator) {
		if (stopped_) {
			return;
		}
		if (!err)
    {
			std::stringstream tmps;
			tmps << endpoint_iterator->endpoint();
			debuglibifaceptr->debuglib_printf(1, "%s: Trying %s...\n", __func__, tmps.str().c_str());

			// Set a deadline for the connect operation.
      deadline_.expires_from_now(boost::chrono::seconds(60));

      // Attempt a connection to each endpoint in the list until we
      // successfully establish a connection.
      boost::asio::async_connect(socket_, endpoint_iterator,
          boost::bind(&asioclient::handle_connect, this,
            boost::asio::placeholders::error));
    }
    else
    {
			debuglibifaceptr->debuglib_printf(1, "%s: Error: %s, Hostname: %s, Port: %s\n", __func__, err.message().c_str(), this->httpserver.c_str(), this->webapiport.c_str());
			stop();
    }
  }

  void reset_http_body() {
    http_version="";
		httpstatuscode=0;
		httpbodylen=0;
	}

	void handle_connect(const boost::system::error_code& err) {
		if (stopped_) {
			return;
		}
		if (!err)
    {
      // The connection was successful. Send the comm requests
			send_comm_request();
    }
    else
    {
			debuglibifaceptr->debuglib_printf(1, "%s: Error: %s\n", __func__, err.message().c_str());
			stop();
    }
  }

  void send_comm_request(void) {
		bool commokay;
		std::list<webapiclient_comm_t *>::iterator commsendit;

		//Send the next request or close connection if nothing else to send
		{
			boost::lock_guard<boost::recursive_mutex> guard(webapiclientlibmutex);
			commsendit=webapi_comms_queue.end();
		}
		//Don't send the zigbee comm until all checks pass
		commokay=false;
		while (!commokay && commsit!=commsendit) {
			if (!(*commsit)->hubpk || !(*commsit)->okaytoadd) {
				//Step to next comm
				++commsit;

				continue;
			}
			commokay=true;
		}
		if (commokay && !webapiclientlib_getneedtoquit()) {
			reset_http_body();

			hc.addFormField("Mode", "AddComm");
			hc.addFormField("Data", comm_to_json(**commsit).c_str());
			std::ostream request_stream(&commrequest_);
			debuglibifaceptr->debuglib_printf(1, "%s: SUPER DEBUG: Sending comm request: %s\n", __func__, hc.toString().c_str());
			request_stream << hc.toString();

			requestmode=2;
			boost::asio::async_write(socket_, commrequest_,
					boost::bind(&asioclient::handle_write_request, this,
						boost::asio::placeholders::error));
		} else if (!webapiclientlib_getneedtoquit()) {
			send_link_request();
		} else {
			stop();
		}
	}

  void send_link_request(void) {
		bool linkokay;
		std::list<webapiclient_link_t *>::iterator linksendit;

		//Send the next request or close connection if nothing else to send
		{
			boost::lock_guard<boost::recursive_mutex> guard(webapiclientlibmutex);
			linksendit=webapi_links_queue.end();
		}
		//Don't send the link until all checks pass
    linkokay=false;
		while (!linkokay && linksit!=linksendit) {
			if (!(*linksit)->localpk || !(*linksit)->okaytoadd) {
				//Step to next link
				++linksit;

				continue;
			}
			linkokay=true;
		}
		if (linkokay && !webapiclientlib_getneedtoquit()) {
			reset_http_body();

			hc.addFormField("Mode", "AddLink");
			hc.addFormField("Data", link_to_json(**linksit));
			std::ostream request_stream(&linkrequest_);
			debuglibifaceptr->debuglib_printf(1, "%s: SUPER DEBUG: Sending link request: %s\n", __func__, hc.toString().c_str());
			request_stream << hc.toString();

			requestmode=1;
			boost::asio::async_write(socket_, linkrequest_,
					boost::bind(&asioclient::handle_write_request, this,
						boost::asio::placeholders::error));
    } else if (!webapiclientlib_getneedtoquit()) {
      send_thing_request();
		} else {
			stop();
		}
	}

  void send_thing_request(void) {
    bool thingokay;
    std::list<webapiclient_thing_t *>::iterator thingsendit;

    //Send the next request or close connection if nothing else to send
    {
      boost::lock_guard<boost::recursive_mutex> guard(webapiclientlibmutex);
      thingsendit=webapi_things_queue.end();
    }
    //Don't send the thing until all checks pass
    thingokay=false;
    while (!thingokay && thingsit!=thingsendit) {
      if (!(*thingsit)->linkpk || !(*thingsit)->okaytoadd) {
        //Step to next thing
        ++thingsit;

        continue;
      }
      thingokay=true;
    }
    if (thingokay && !webapiclientlib_getneedtoquit()) {
      reset_http_body();

      hc.addFormField("Mode", "AddThing");
      hc.addFormField("Data", thing_to_json(**thingsit));
      std::ostream request_stream(&thingrequest_);
      debuglibifaceptr->debuglib_printf(1, "%s: SUPER DEBUG: Sending thing request: %s\n", __func__, hc.toString().c_str());
      request_stream << hc.toString();

      requestmode=3;
      boost::asio::async_write(socket_, thingrequest_,
          boost::bind(&asioclient::handle_write_request, this,
            boost::asio::placeholders::error));
    } else {
      stop();
    }
  }

	void handle_write_request(const boost::system::error_code& err) {
		if (stopped_) {
			return;
		}
    if (!err)
    {
			// Set a deadline for the read operation.
      deadline_.expires_from_now(boost::chrono::seconds(60));

			// Read the response status line. The response_ streambuf will
      // automatically grow to accommodate the entire line. The growth may be
      // limited by passing a maximum size to the streambuf constructor.
      boost::asio::async_read_until(socket_, response_, "\r\n",
          boost::bind(&asioclient::handle_read_status_line, this,
            boost::asio::placeholders::error));
    }
    else
    {
			debuglibifaceptr->debuglib_printf(1, "%s: Error: %s\n", __func__, err.message().c_str());
			stop();
    }
  }

	void handle_read_status_line(const boost::system::error_code& err) {
		if (stopped_) {
			return;
		}
    if (!err) {
      // Check that response is OK.
      std::istream response_stream(&response_);
      response_stream >> http_version;
      response_stream >> httpstatuscode;
      std::string status_message;
      std::getline(response_stream, status_message);
      if (!response_stream || http_version.substr(0, 5) != "HTTP/") {
				debuglibifaceptr->debuglib_printf(1, "%s: Invalid response: %s\n", __func__, http_version.c_str());
				stop();
        return;
      } else if (httpstatuscode == 401) {
				//Abort as the password was incorrect
				debuglibifaceptr->debuglib_printf(1, "%s: Authentication Failure\n", __func__);
				stop();
				return;
			} else if (httpstatuscode != 200) {
				debuglibifaceptr->debuglib_printf(1, "%s: Response returned with status code: %u\n", __func__, httpstatuscode);
				stop();
        return;
			}
			// Set a deadline for the read operation.
      deadline_.expires_from_now(boost::chrono::seconds(60));

			// Read the response headers, which are terminated by a blank line.
      boost::asio::async_read_until(socket_, response_, "\r\n\r\n",
          boost::bind(&asioclient::handle_read_headers, this,
            boost::asio::placeholders::error));
    }
    else
    {
			debuglibifaceptr->debuglib_printf(1, "%s: Error: %s\n", __func__, err.message().c_str());
			stop();
    }
  }

	void handle_read_headers(const boost::system::error_code& err) {
		if (stopped_) {
			return;
		}
    if (!err)
    {
      // Process the response headers.
      std::istream response_stream(&response_);
      std::string header;
			bool havebodylen=false;
      while (std::getline(response_stream, header) && header != "\r") {
				if (header.substr(0, 15) == "Content-Length:") {
					std::stringstream contentlengthstr(header.substr(15));
					contentlengthstr >> httpbodylen;
					havebodylen=true;
					debuglibifaceptr->debuglib_printf(1, "%s: Content-Length=%ld\n", __func__, httpbodylen);
				}
				debuglibifaceptr->debuglib_printf(1, "%s: Header: %s\n", __func__, header.c_str());
			}
			if (!havebodylen) {
				//Can't continue without proper body length so abort
				debuglibifaceptr->debuglib_printf(1, "%s: Error: Failed to retrieve Content-Length\n", __func__);
				stop();
				return;
			}
			// Set a deadline for the read operation.
      deadline_.expires_from_now(boost::chrono::seconds(60));

      if (httpstatuscode == 401) {
				//Abort as the password was incorrect
				debuglibifaceptr->debuglib_printf(1, "%s: Authentication Failure\n", __func__);
				stop();
				return;
			} else if (httpstatuscode != 200) {
				debuglibifaceptr->debuglib_printf(1, "%s: Response returned with status code: %u\n", __func__, httpstatuscode);

        // Dummy read the body
        boost::asio::async_read(socket_, response_,
            boost::asio::transfer_exactly(httpbodylen-response_.size()),
            boost::bind(&asioclient::dummy_read_content, this,
              boost::asio::placeholders::error));
				stop();
				return;
			} else {
        // Read the body
        boost::asio::async_read(socket_, response_,
            boost::asio::transfer_exactly(httpbodylen-response_.size()),
            boost::bind(&asioclient::handle_read_content, this,
              boost::asio::placeholders::error));
			}
    }
    else
    {
			debuglibifaceptr->debuglib_printf(1, "%s: Error: %s\n", __func__, err.message().c_str());
			stop();
    }
  }

  int process_response(std::string body) {
		int errcode=0;

		try {
			boost::property_tree::ptree pt;
			std::istringstream streamstr(body);

			read_json(streamstr, pt);
			bool iserror=pt.get<bool>("Error");
			if (iserror) {
				errcode=pt.get<int>("ErrCode");
				std::string errorstr=pt.get<std::string>("ErrMesg");
				debuglibifaceptr->debuglib_printf(1, "%s: Webapi server returned error code: %d, error message: %s\n", __func__, errcode, errorstr.c_str());
				if (errcode==0) {
					//Error code 0 normally means success so if there was an error adjust to -1 for the return
					errcode=-1;
				}
			}
		} catch (boost::property_tree::ptree_error &e) {
			debuglibifaceptr->debuglib_printf(1, "%s: Webapi server returned an unknown result\n", __func__);
			return -1;
		}
		return errcode;
	}

	void dummy_read_content(const boost::system::error_code& err) {
		response_.consume(httpbodylen);
	}

  void handle_read_content(const boost::system::error_code& err) {
    if (!err || err == boost::asio::error::eof) {
      // Write all of the data that has been read so far.
			std::string httpbody;
			int c;
      while ( (c=response_.sbumpc())!=EOF ) {
				httpbody+=(char) c;
			}
			debuglibifaceptr->debuglib_printf(1, "%s: SUPER DEBUG: Body: \"%s\"\n", __func__, httpbody.c_str());

			int result=process_response(httpbody);

			if (result==0) {
				successful_send();
			} else {
				failed_send();
			}
    }
    else if (err != boost::asio::error::eof)
    {
			debuglibifaceptr->debuglib_printf(1, "%s: Error: %s\n", __func__, err.message().c_str());
			stop();
    }
  }

  //Do processing after the request has been sent and then send the next request
  void successful_send() {
		if (requestmode==1) {
			std::list<webapiclient_link_t *>::iterator linksprevit=linksit;

			debuglibifaceptr->debuglib_printf(1, "%s: SUPER DEBUG Removing Link from add queue due to success\n", __func__);

			//Step to next link before erasing the one that just got added
			++linksit;

			//Erase the link that just got added
      delete (*linksprevit);
			webapi_links_queue.erase(linksprevit);

      //Only send one request at a time for now until HTTP/1.1 with Chunked Transfer Encoding is implemented
      stop();
			//Send next request
			//send_link_request();
    } else if (requestmode==3) {
      std::list<webapiclient_thing_t *>::iterator thingsprevit=thingsit;

      debuglibifaceptr->debuglib_printf(1, "%s: SUPER DEBUG Removing Thing from add queue due to success\n", __func__);

      //Step to next thing before erasing the one that just got added
      ++thingsit;

      //Erase the thing that just got added
      delete (*thingsprevit);
      webapi_things_queue.erase(thingsprevit);

      //Only send one request at a time for now until HTTP/1.1 with Chunked Transfer Encoding is implemented
      stop();
      //Send next request
      //send_link_request();
		} else if (requestmode==2) {
			std::list<webapiclient_comm_t *>::iterator commsprevit=commsit;

			debuglibifaceptr->debuglib_printf(1, "%s: SUPER DEBUG Removing Comm from add queue due to success\n", __func__);

			//Step to next comm before erasing the one that just got added
			++commsit;

			//Erase the comm that just got added
      delete (*commsprevit);
			webapi_comms_queue.erase(commsprevit);

      //Only send one request at a time for now until HTTP/1.1 with Chunked Transfer Encoding is implemented
      stop();
			//Send next request
			//send_comm_request();
		}
	}

  //Do processing after the request has been sent and then send the next request
  void failed_send() {
		if (requestmode==1) {
			debuglibifaceptr->debuglib_printf(1, "%s: SUPER DEBUG Skipping adding Link for now due to error\n", __func__);

			//Skip the current link for now and step to next link
			++linksit;

			//Send next request
			send_link_request();
    } else if (requestmode==3) {
      debuglibifaceptr->debuglib_printf(1, "%s: SUPER DEBUG Skipping adding Thing for now due to error\n", __func__);

      //Skip the current thing for now and step to next link
      ++thingsit;

      //Send next request
      send_thing_request();
		} else if (requestmode==2) {
			debuglibifaceptr->debuglib_printf(1, "%s: SUPER DEBUG Skipping adding Comm for now due to error\n", __func__);

			//Skip the current comm link for now and step to next comm link
			++commsit;

			//Send next request
			send_comm_request();
		}
	}

  void check_deadline() {
    if (stopped_)
      return;

    // Check whether the deadline has passed. We compare the deadline against
    // the current time since a new asynchronous operation may have moved the
    // deadline before this actor had a chance to run.
    if (deadline_.expires_at() <= boost::chrono::system_clock::now())
    {
			debuglibifaceptr->debuglib_printf(1, "%s: Server took too long to respond\n", __func__);

			//Shutdown first as per Boost header file portability recommendation
			try {
				socket_.shutdown(tcp::socket::shutdown_both);
			} catch (std::exception& e) {
				//Ignore errors from this function for now
			}
      // The deadline has passed. The socket is closed so that any outstanding
      // asynchronous operations are cancelled.
      socket_.close();
    } else {
			// Put the actor back to sleep.
			deadline_.async_wait(boost::bind(&asioclient::check_deadline, this));
		}
  }
};

class webapiclientloop_asyncloop {
private:
	boost::mutex mtx_;
	boost::asio::io_service io_service;
	boost::asio::system_timer timer;
	asioclient client;

public:
	webapiclientloop_asyncloop()
	  : timer(io_service), client(io_service) {
		}

	void start() {
		debuglib_ifaceptrs_ver_1_t *debuglibifaceptr=(debuglib_ifaceptrs_ver_1_t *) webapiclientlib_getmoduledepifaceptr("debuglib", DEBUGLIBINTERFACE_VER_1);
		update_timer_loop();
		try {
			io_service.run();
			io_service.reset();
		} catch (std::exception& e) {
			debuglibifaceptr->debuglib_printf(1, "%s: Error while running service: %s\n", __func__, e.what());
		}
	}

	void stop() {
		boost::lock_guard<boost::mutex> guard(mtx_);
		client.stop();
		timer.expires_from_now(boost::chrono::seconds(0));
	}
private:
	//Get the hub pk for the comm devices from the configuration
	void set_hubpk_for_comm_devices(void) {
		debuglib_ifaceptrs_ver_1_t *debuglibifaceptr=(debuglib_ifaceptrs_ver_1_t *) webapiclientlib_getmoduledepifaceptr("debuglib", DEBUGLIBINTERFACE_VER_1);
		configlib_ifaceptrs_ver_1_cpp_t *configlibifaceptr=(configlib_ifaceptrs_ver_1_cpp_t *) webapiclientlib_getmoduledepifaceptr("configlib", CONFIGLIBINTERFACECPP_VER_1);
		std::string hubpkstr;

		bool result=configlibifaceptr->getnamevalue_cpp("general", "hubpk", hubpkstr);
		if (!result) {
			return;
		}
		std::int64_t hubpk=std::atol(hubpkstr.c_str());

		//Once we have begin and end iterators we shouldn't need a lock to traverse the list unless we modify the contents
		webapiclientlibmutex.lock();
		auto webapi_comms_queueitbegin=webapi_comms_queue.begin();
		auto webapi_comms_queueitend=webapi_comms_queue.end();
		webapiclientlibmutex.unlock();

		for (auto &it=webapi_comms_queueitbegin; it!=webapi_comms_queueitend; it++) {
			webapiclientlibmutex.lock();
            (*it)->hubpk=hubpk;
			webapiclientlibmutex.unlock();
			debuglibifaceptr->debuglib_printf(1, "%s: Found Hub PK: %" PRId64 " for Queued device: %016" PRIX64 "\n", __func__, hubpk, (*it)->addr);
		}
	}

	//Get the local pk for links based on the local address
	void set_locakpk_for_links(void) {
		debuglib_ifaceptrs_ver_1_t *debuglibifaceptr=(debuglib_ifaceptrs_ver_1_t *) webapiclientlib_getmoduledepifaceptr("debuglib", DEBUGLIBINTERFACE_VER_1);
		dblib_ifaceptrs_ver_1_t *dblibifaceptr=(dblib_ifaceptrs_ver_1_t *) webapiclientlib_getmoduledepifaceptr("dblib", 	DBLIBINTERFACE_VER_1);;
    int result;

		//Once we have begin and end iterators we shouldn't need a lock to traverse the list unless we modify the contents
		webapiclientlibmutex.lock();
		auto webapi_links_queueitbegin=webapi_links_queue.begin();
		auto webapi_links_queueitend=webapi_links_queue.end();
		webapiclientlibmutex.unlock();

    result=dblibifaceptr->begin();
    if (result<0) {
      debuglibifaceptr->debuglib_printf(1, "%s: Failed to start database transaction\n", __func__);
      return;
    }
		for (auto &it=webapi_links_queueitbegin; it!=webapi_links_queueitend; it++) {
			int result;
			int64_t commpk;

			//Check the database to see if the link is linked to a comm
			debuglibifaceptr->debuglib_printf(1, "%s: Searching for Comm PK from address: %016" PRIX64 " for Queued Link: %016" PRIX64 "\n", __func__, (*it)->localaddr, (*it)->addr);
			result=dblibifaceptr->getcommpk((*it)->localaddr, &commpk);
			if (result==0) {
				webapiclientlibmutex.lock();
				(*it)->localpk=commpk;
				webapiclientlibmutex.unlock();
				debuglibifaceptr->debuglib_printf(1, "%s: Found Comm PK: %" PRId64 " from address: %016" PRIX64 " for Queued Link: %016" PRIX64 "\n", __func__, commpk, (*it)->localaddr, (*it)->addr);
			}
		}
		result=dblibifaceptr->end();
    if (result<0) {
      dblibifaceptr->rollback();
    }
	}

//Get the link pk for things based on the local address
  void set_linkpk_for_things(void) {
    debuglib_ifaceptrs_ver_1_t *debuglibifaceptr=(debuglib_ifaceptrs_ver_1_t *) webapiclientlib_getmoduledepifaceptr("debuglib", DEBUGLIBINTERFACE_VER_1);
    dblib_ifaceptrs_ver_1_t *dblibifaceptr=(dblib_ifaceptrs_ver_1_t *) webapiclientlib_getmoduledepifaceptr("dblib",  DBLIBINTERFACE_VER_1);;
    int result;

    //Once we have begin and end iterators we shouldn't need a lock to traverse the list unless we modify the contents
    webapiclientlibmutex.lock();
    auto webapi_things_queueitbegin=webapi_things_queue.begin();
    auto webapi_things_queueitend=webapi_things_queue.end();
    webapiclientlibmutex.unlock();

    result=dblibifaceptr->begin();
    if (result<0) {
      debuglibifaceptr->debuglib_printf(1, "%s: Failed to start database transaction\n", __func__);
      return;
    }
    for (auto &it=webapi_things_queueitbegin; it!=webapi_things_queueitend; it++) {
      int result;
      int64_t linkpk;

      //Check the database to see if the link is linked to a comm
      debuglibifaceptr->debuglib_printf(1, "%s: Searching for Link PK from address: %016" PRIX64 " for Queued Thing: %08" PRIX32 "\n", __func__, (*it)->localaddr, (*it)->hwid);
      result=dblibifaceptr->getlinkpk((*it)->localaddr, &linkpk);
      if (result==0) {
        webapiclientlibmutex.lock();
        (*it)->linkpk=linkpk;
        webapiclientlibmutex.unlock();
        debuglibifaceptr->debuglib_printf(1, "%s: Found Link PK: %" PRId64 " from address: %016" PRIX64 " for Queued Thing: %08" PRIX32 "\n", __func__, linkpk, (*it)->localaddr, (*it)->hwid);
      }
    }
    result=dblibifaceptr->end();
    if (result<0) {
      dblibifaceptr->rollback();
    }
  }

	//Remove comm devices from the webapi queue that don't need to be re-added
	void remove_already_added_comm_devices(void) {
		debuglib_ifaceptrs_ver_1_t *debuglibifaceptr=(debuglib_ifaceptrs_ver_1_t *) webapiclientlib_getmoduledepifaceptr("debuglib", DEBUGLIBINTERFACE_VER_1);
		dblib_ifaceptrs_ver_1_t *dblibifaceptr=(dblib_ifaceptrs_ver_1_t *) webapiclientlib_getmoduledepifaceptr("dblib", 	DBLIBINTERFACE_VER_1);;
    int result;

		//debuglibifaceptr->debuglib_printf(1, "Entering %s\n", __func__);

		//Once we have begin and end iterators we shouldn't need a lock to traverse the list unless we modify the contents
		webapiclientlibmutex.lock();
		auto webapi_comms_queueitbegin=webapi_comms_queue.begin();
		auto webapi_comms_queueitend=webapi_comms_queue.end();
		webapiclientlibmutex.unlock();
		std::list< std::list<webapiclient_comm_t *>::iterator > comms_to_remove;

		result=dblibifaceptr->begin();
    if (result<0) {
      debuglibifaceptr->debuglib_printf(1, "%s: Failed to start database transaction\n", __func__);
      return;
    }
		for (auto &it=webapi_comms_queueitbegin; it!=webapi_comms_queueitend; it++) {
			int result;
			int64_t commpk;

			//Check the database to see if the link has already been added
			result=dblibifaceptr->getcommpk((*it)->addr, &commpk);
			if (result==0) {
				debuglibifaceptr->debuglib_printf(1, "%s: Going to remove Comm device from queue: %016" PRIX64 " as it is already in the database\n", __func__, (*it)->addr);
				comms_to_remove.push_back(it);
			} else if (result<-1) {
				debuglibifaceptr->debuglib_printf(1, "%s: Failed to check with database for Comm device: %016" PRIX64 ", postponing sending to webapi\n", __func__, (*it)->addr);
			} else {
                (*it)->okaytoadd=true;
			}
		}
		result=dblibifaceptr->end();
    if (result<0) {
      dblibifaceptr->rollback();
    }
		webapiclientlibmutex.lock();
		for (auto const &it : comms_to_remove) {
			debuglibifaceptr->debuglib_printf(1, "%s: Removing Comm device from queue: %016" PRIX64 "\n", __func__, (*it)->addr);
      delete (*it);
			webapi_comms_queue.erase(it);
		}
		webapiclientlibmutex.unlock();
		//debuglibifaceptr->debuglib_printf(1, "Exiting %s\n", __func__);
	}

	//Remove links from the webapi queue that don't need to be re-added
	void remove_already_added_links(void) {
		debuglib_ifaceptrs_ver_1_t *debuglibifaceptr=(debuglib_ifaceptrs_ver_1_t *) webapiclientlib_getmoduledepifaceptr("debuglib", DEBUGLIBINTERFACE_VER_1);
		dblib_ifaceptrs_ver_1_t *dblibifaceptr=(dblib_ifaceptrs_ver_1_t *) webapiclientlib_getmoduledepifaceptr("dblib", 	DBLIBINTERFACE_VER_1);;
    int result;

		//debuglibifaceptr->debuglib_printf(1, "Entering %s\n", __func__);

		//Once we have begin and end iterators we shouldn't need a lock to traverse the list unless we modify the contents
		webapiclientlibmutex.lock();
		auto webapi_links_queueitbegin=webapi_links_queue.begin();
		auto webapi_links_queueitend=webapi_links_queue.end();
		webapiclientlibmutex.unlock();
		std::list< std::list<webapiclient_link_t *>::iterator > links_to_remove;

		result=dblibifaceptr->begin();
    if (result<0) {
      debuglibifaceptr->debuglib_printf(1, "%s: Failed to start database transaction\n", __func__);
      return;
    }
		for (auto &it=webapi_links_queueitbegin; it!=webapi_links_queueitend; it++) {
			int result;
			int64_t linkpk;

			//Check the database to see if the link has already been added
			result=dblibifaceptr->getlinkpk((*it)->addr, &linkpk);
			if (result==0) {
				debuglibifaceptr->debuglib_printf(1, "%s: Going to remove Link from queue: %016" PRIX64 " as it is already in the database\n", __func__, (*it)->addr);
				links_to_remove.push_back(it);
			} else if (result<-1) {
				debuglibifaceptr->debuglib_printf(1, "%s: Failed to check with database for Link: %016" PRIX64 ", postponding sending to webapi\n", __func__, (*it)->addr);
			} else {
				(*it)->okaytoadd=true;
			}
		}
		result=dblibifaceptr->end();
    if (result<0) {
      dblibifaceptr->rollback();
    }
		webapiclientlibmutex.lock();
		for (auto const &it : links_to_remove) {
			debuglibifaceptr->debuglib_printf(1, "%s: Removing Link from queue: %016" PRIX64 "\n", __func__, (*it)->addr);
      delete (*it);
			webapi_links_queue.erase(it);
		}
		webapiclientlibmutex.unlock();
		//debuglibifaceptr->debuglib_printf(1, "Exiting %s\n", __func__);
	}

  //Remove things from the webapi queue that don't need to be re-added
  void remove_already_added_things(void) {
    debuglib_ifaceptrs_ver_1_t *debuglibifaceptr=(debuglib_ifaceptrs_ver_1_t *) webapiclientlib_getmoduledepifaceptr("debuglib", DEBUGLIBINTERFACE_VER_1);
    dblib_ifaceptrs_ver_1_t *dblibifaceptr=(dblib_ifaceptrs_ver_1_t *) webapiclientlib_getmoduledepifaceptr("dblib",  DBLIBINTERFACE_VER_1);;
    int result;

    //debuglibifaceptr->debuglib_printf(1, "Entering %s\n", __func__);

    //Once we have begin and end iterators we shouldn't need a lock to traverse the list unless we modify the contents
    webapiclientlibmutex.lock();
    auto webapi_things_queueitbegin=webapi_things_queue.begin();
    auto webapi_things_queueitend=webapi_things_queue.end();
    webapiclientlibmutex.unlock();
    std::list< std::list<webapiclient_thing_t *>::iterator > things_to_remove;

    result=dblibifaceptr->begin();
    if (result<0) {
      debuglibifaceptr->debuglib_printf(1, "%s: Failed to start database transaction\n", __func__);
      return;
    }
    for (auto &it=webapi_things_queueitbegin; it!=webapi_things_queueitend; it++) {
      int result;
      int64_t thingpk;

      //Check the database to see if the thing has already been added
      result=dblibifaceptr->getthingpk((*it)->serialcode, (*it)->hwid, &thingpk);
      if (result==0) {
        debuglibifaceptr->debuglib_printf(1, "%s: Going to remove Thing from queue: %08" PRIX32 " as it is already in the database\n", __func__, (*it)->hwid);
        things_to_remove.push_back(it);
      } else if (result<-1) {
        debuglibifaceptr->debuglib_printf(1, "%s: Failed to check with database for Thing: %08" PRIX32 ", postponding sending to webapi\n", __func__, (*it)->hwid);
      } else {
        (*it)->okaytoadd=true;
      }
    }
    result=dblibifaceptr->end();
    if (result<0) {
      dblibifaceptr->rollback();
    }
    webapiclientlibmutex.lock();
    for (auto const &it : things_to_remove) {
      debuglibifaceptr->debuglib_printf(1, "%s: Removing Thing from queue: %08" PRIX32 "\n", __func__, (*it)->hwid);
      delete (*it);
      webapi_things_queue.erase(it);
    }
    webapiclientlibmutex.unlock();
    //debuglibifaceptr->debuglib_printf(1, "Exiting %s\n", __func__);
  }

	void update_timer_loop() {
		dblib_ifaceptrs_ver_1_t *dblibifaceptr=(dblib_ifaceptrs_ver_1_t *) webapiclientlib_getmoduledepifaceptr("dblib", DBLIBINTERFACE_VER_1);;
		configlib_ifaceptrs_ver_1_cpp_t *configlibifaceptr=(configlib_ifaceptrs_ver_1_cpp_t *) webapiclientlib_getmoduledepifaceptr("configlib", CONFIGLIBINTERFACECPP_VER_1);
		debuglib_ifaceptrs_ver_1_t *debuglibifaceptr=(debuglib_ifaceptrs_ver_1_t *) webapiclientlib_getmoduledepifaceptr("debuglib", DEBUGLIBINTERFACE_VER_1);

	boost::lock_guard<boost::mutex> guard(mtx_);
		timer.expires_from_now(boost::chrono::seconds(5));
		timer.async_wait(boost::bind(&webapiclientloop_asyncloop::timer_handler, this, boost::asio::placeholders::error));

    if (dblibifaceptr->is_initialised()) {
			set_hubpk_for_comm_devices();
			remove_already_added_comm_devices();
			set_locakpk_for_links();
			remove_already_added_links();
      set_linkpk_for_things();
      remove_already_added_things();
			std::string webapihostname="", webapiport="80", webapiurl="", webapihttpuser="", webapihttppass="", webapiuser="", webapipass="";
			bool result, missingval=false;

			result=configlibifaceptr->getnamevalue_cpp("webapiconfig", "hostname", webapihostname);
			if (!result) {
				missingval=true;
			}
			result=configlibifaceptr->getnamevalue_cpp("webapiconfig", "port", webapiport);
			result=configlibifaceptr->getnamevalue_cpp("webapiconfig", "url", webapiurl);
			if (!result) {
				missingval=true;
			}
			configlibifaceptr->getnamevalue_cpp("webapiconfig", "httpusername", webapihttpuser);
			configlibifaceptr->getnamevalue_cpp("webapiconfig", "httppassword", webapihttppass);
			configlibifaceptr->getnamevalue_cpp("webapiconfig", "apiusername", webapiuser);
			configlibifaceptr->getnamevalue_cpp("webapiconfig", "apipassword", webapipass);
			if (!missingval && (!webapi_links_queue.empty() || !webapi_comms_queue.empty() || !webapi_things_queue.empty())) {
				debuglibifaceptr->debuglib_printf(1, "%s: Starting client connection\n", __func__);
				client.start(webapihostname, webapiport, webapiurl, webapiuser, webapipass, webapihttpuser, webapihttppass);
			}
		}
	}

	//Called every time the main timer triggers
	void timer_handler(const boost::system::error_code& error) {
		if (!webapiclientlib_getneedtoquit()) {
			update_timer_loop();
		}
	}
};

webapiclientloop_asyncloop gasyncloop;

static void webapiclientlib_mainloop(void) {
  debuglib_ifaceptrs_ver_1_t *debuglibifaceptr=(debuglib_ifaceptrs_ver_1_t *) webapiclientlib_getmoduledepifaceptr("debuglib", DEBUGLIBINTERFACE_VER_1);

  debuglibifaceptr->debuglib_printf(1, "Entering %s\n", __func__);

	while (!webapiclientlib_getneedtoquit()) {
		//Auto restart the loop if it crashes before we are ready to quit
		gasyncloop.start();
	}
	debuglibifaceptr->debuglib_printf(1, "Exiting %s\n", __func__);
}

static boost::atomic<bool> webapiclientlib_needtoquit(false);

static void webapiclientlib_setneedtoquit(bool val) {
  webapiclientlib_needtoquit.store(val);
}

static int webapiclientlib_getneedtoquit() {
  return webapiclientlib_needtoquit.load();
}

static bool webapiclientlib_havemainthread=false;

static int webapiclientlib_start(void) {
  debuglib_ifaceptrs_ver_1_t *debuglibifaceptr=(debuglib_ifaceptrs_ver_1_t *) webapiclientlib_getmoduledepifaceptr("debuglib", DEBUGLIBINTERFACE_VER_1);
	int result=0;

  debuglibifaceptr->debuglib_printf(1, "Entering %s\n", __func__);
	if (!webapiclientlib_havemainthread) {
		try {
			debuglibifaceptr->debuglib_printf(1, "%s: Starting the main thread\n", __func__);
			webapiclientlib_mainthread=boost::thread(webapiclientlib_mainloop);
			webapiclientlib_havemainthread=true;
		} catch (boost::thread_resource_error& e) {
			debuglibifaceptr->debuglib_printf(1, "%s: Failed to spawn main thread\n", __func__);
		}
	}
  debuglibifaceptr->debuglib_printf(1, "Exiting %s\n", __func__);

  return result;
}

static void webapiclientlib_stop(void) {
  debuglib_ifaceptrs_ver_1_t *debuglibifaceptr=(debuglib_ifaceptrs_ver_1_t *) webapiclientlib_getmoduledepifaceptr("debuglib", DEBUGLIBINTERFACE_VER_1);

  debuglibifaceptr->debuglib_printf(1, "Entering %s\n", __func__);
	if (webapiclientlib_havemainthread) {
		debuglibifaceptr->debuglib_printf(1, "%s: Cancelling the main thread\n", __func__);
    webapiclientlib_setneedtoquit(true);
		gasyncloop.stop();
		webapiclientlib_mainthread.interrupt();
    debuglibifaceptr->debuglib_printf(1, "%s: Waiting for main thread to exit\n", __func__);
    webapiclientlib_mainthread.join();
    webapiclientlib_havemainthread=false;
	}
  debuglibifaceptr->debuglib_printf(1, "Exiting %s\n", __func__);
}

static int webapiclientlib_inuse=0; //Only do full shutdown when inuse = 0
static bool webapiclientlib_shuttingdown=false;

static int webapiclientlib_init(void) {
  debuglib_ifaceptrs_ver_1_t *debuglibifaceptr=(debuglib_ifaceptrs_ver_1_t *) webapiclientlib_getmoduledepifaceptr("debuglib", DEBUGLIBINTERFACE_VER_1);
  dblib_ifaceptrs_ver_1_t *dblibifaceptr=(dblib_ifaceptrs_ver_1_t *) webapiclientlib_getmoduledepifaceptr("dblib", DBLIBINTERFACE_VER_1);;

  debuglibifaceptr->debuglib_printf(1, "Entering %s\n", __func__);

  if (webapiclientlib_shuttingdown) {
    debuglibifaceptr->debuglib_printf(1, "Exiting %s, already shutting down\n", __func__);
    return -1;
  }
  ++webapiclientlib_inuse;
  if (webapiclientlib_inuse>1) {
    //Already initialised
    debuglibifaceptr->debuglib_printf(1, "Exiting %s, already initialised, use count=%d\n", __func__, webapiclientlib_inuse);
    return -1;
  }
  //Let the database library know that we want to use it
  dblibifaceptr->init();

  webapiclientlib_needtoquit=false;
  debuglibifaceptr->debuglib_printf(1, "Exiting %s\n", __func__);

  return 0;
}

static void webapiclientlib_shutdown(void) {
  debuglib_ifaceptrs_ver_1_t *debuglibifaceptr=(debuglib_ifaceptrs_ver_1_t *) webapiclientlib_getmoduledepifaceptr("debuglib", DEBUGLIBINTERFACE_VER_1);
  dblib_ifaceptrs_ver_1_t *dblibifaceptr=(dblib_ifaceptrs_ver_1_t *) webapiclientlib_getmoduledepifaceptr("dblib", DBLIBINTERFACE_VER_1);;

  debuglibifaceptr->debuglib_printf(1, "Entering %s\n", __func__);
  if (webapiclientlib_inuse==0) {
    //Already uninitialised
    debuglibifaceptr->debuglib_printf(1, "WARNING: Exiting %s, Already shutdown\n", __func__);
    return;
  }
  --webapiclientlib_inuse;
  if (webapiclientlib_inuse>0) {
    //Module still in use
    debuglibifaceptr->debuglib_printf(1, "Exiting %s, Still in use, use count=%d\n", __func__, webapiclientlib_inuse);
    return;
  }
  //Start shutting down library
  webapiclientlib_shuttingdown=true;

  //Finished using the database library
  dblibifaceptr->shutdown();

  for (auto const &it : webapi_links_queue) {
    delete it;
  }
	webapi_links_queue.clear();

  for (auto const &it : webapi_comms_queue) {
    delete it;
  }
  webapi_comms_queue.clear();

	debuglibifaceptr->debuglib_printf(1, "Exiting %s\n", __func__);

  //Finished shutting down
  webapiclientlib_shuttingdown=false;
}

moduleinfo_ver_generic_t *webapiclientlib_getmoduleinfo() {
  return (moduleinfo_ver_generic_t *) &webapiclientlib_moduleinfo_ver_1;
}

#ifdef __ANDROID__
JNIEXPORT jlong JNICALL Java_com_capsicumcorp_iomy_libraries_watchinputs_WebApiClientLib_jnigetmodulesinfo( JNIEnv* UNUSED(env), jobject UNUSED(obj)) {
  return (jlong) webapiclientlib_getmoduleinfo();
}
#endif

max_stars_repo_name: CapsicumCorp/iOmy

max_issues_repo_name: CapsicumCorp/iOmy

max_forks_repo_name: CapsicumCorp/iOmy