<commit_before>#include "AntGoalTestApp.hpp"
#include "../sim/worldobject/AntHome.hpp"
#include "../sim/nav/Node.hpp"
#include "../sim/agent/testagent/AntGoalTester.hpp"
#include "../sim/agent/testagent/AntEatAntTest.hpp"
#include "../sim/agent/testagent/AntExploreAntTest.hpp"
#include "../sim/agent/testagent/AntFindFoodAntTest.hpp"
#include "../sim/agent/testagent/AntForageAntTest.hpp"
#include "../sim/agent/testagent/AntGoHomeAntTest.hpp"
#include "../sim/agent/testagent/AntMoveToNodeAntTest.hpp"
#include "../sim/agent/testagent/AntFollowPathAntTest.hpp"
#include "../util/make_unique.hpp"
#include "../sim/knowledge/GenericPercept.hpp"

#include <iostream>
#include <vector>

// Christopher D. Canfield
// November 2013
// AntGoalTestApp.cpp

using namespace std;
using namespace cdc;

void createNavGraph1(vector<Node>& navGraph);
std::vector<unique_ptr<AntGoalTester>> getTestAnts(GuiEventManager& manager, AntHome& home, NavGraphHelper& navGraphHelper,
									 Node& startNode, Node& nearTarget, Node& farTarget);

AntGoalTestApp::AntGoalTestApp() :
	viewManager(eventManager, 1000, 1000, 800, 800, 200, 800),
	ticks(0)
{
}

AntGoalTestApp::~AntGoalTestApp()
{
}

void AntGoalTestApp::setup()
{
	createNavGraph1(navGraph);
	foodPile = new AntFoodPile(100, navGraph[11]);
	navGraphHelper = NavGraphHelper(navGraph);

	antHome = new AntHome(navGraph[10], navGraph, world);
	goalTestAnts = getTestAnts(eventManager, *antHome, navGraphHelper, navGraph[0], navGraph[1], navGraph.back());

	window = std::unique_ptr<sf::RenderWindow>(new sf::RenderWindow(sf::VideoMode(800, 800), "GUI Tests"));
	window->setFramerateLimit(60);

	viewManager.setWindow(*window);
	viewManager.getSimView().setViewport(sf::FloatRect(0.f, 0.f, 1.f, 1.f));
}

bool AntGoalTestApp::run()
{
	if (ant != nullptr && ant->isGoalFinished() && goalTestAnts.empty())
	{
		return false;
	}

	if (ant == nullptr || ant->isGoalFinished())
	{
		ant = move(goalTestAnts.back());
		goalTestAnts.pop_back();
		cout << "----------------------------------------" << endl;
		cout << "Running ant test: " << (typeid(*ant.get()).name()) << endl;
		cout << "----------------------------------------" << endl;
	}

	sf::Event event;
	while (window->pollEvent(event))
	{
		if (event.type == sf::Event::Closed)
		{
			window->close();
			return false;
		}
		else
		{
			eventManager.update(event, *window);
		}
	}

	GenericPercept percept;
	ant->update(ticks, percept);
	++ticks;

	window->clear(sf::Color::Green);

	for (auto& node : navGraph)
	{
		window->draw(node);
	}
	window->draw(*ant);
	window->draw(*foodPile);

	window->display();

	return true;
}

void AntGoalTestApp::teardown()
{

}

std::vector<unique_ptr<AntGoalTester>> getTestAnts(GuiEventManager& manager, AntHome& home, NavGraphHelper& navGraphHelper,
									 Node& startNode, Node& nearTarget, Node& farTarget)
{
	cout << "Ant goal tester type: " << endl;
	cout << "  1: AntEat" << endl;
	cout << "  2: AntExplore" << endl;
	cout << "  3: AntFindFood" << endl;
	cout << "  4: AntForage" << endl;
	cout << "  5: AntGoHome" << endl;
	cout << "  6: AntMoveToNode" << endl;
	cout << "  7: AntFollowPath" << endl;
	cout << "  8: Run all tests" << endl;
	cout << "Type: ";

	int goalType;
	cin >> goalType;

	std::vector<unique_ptr<AntGoalTester>> goals;

	switch (goalType)
	{
	case 1:
		goals.push_back(make_unique<AntEatAntTest>(manager, home, navGraphHelper, startNode));
		break;
	case 2:
		goals.push_back(make_unique<AntExploreAntTest>(manager, home, navGraphHelper, startNode));
		break;
	case 3:
		goals.push_back(make_unique<AntFindFoodAntTest>(manager, home, navGraphHelper, startNode));
		break;
	case 4:
		goals.push_back(make_unique<AntForageAntTest>(manager, home, navGraphHelper, startNode));
		break;
	case 5:
		goals.push_back(make_unique<AntGoHomeAntTest>(manager, home, navGraphHelper, startNode));
		break;
	case 6:
		goals.push_back(make_unique<AntMoveToNodeAntTest>(manager, home, navGraphHelper, startNode, nearTarget));
		break;
	case 7:
		goals.push_back(make_unique<AntFollowPathAntTest>(manager, home, navGraphHelper, startNode, farTarget));
		break;
	case 8:
		goals.push_back(make_unique<AntEatAntTest>(manager, home, navGraphHelper, startNode));
		goals.push_back(make_unique<AntExploreAntTest>(manager, home, navGraphHelper, startNode));
		goals.push_back(make_unique<AntFindFoodAntTest>(manager, home, navGraphHelper, startNode));
		goals.push_back(make_unique<AntForageAntTest>(manager, home, navGraphHelper, startNode));
		goals.push_back(make_unique<AntGoHomeAntTest>(manager, home, navGraphHelper, startNode));
		goals.push_back(make_unique<AntMoveToNodeAntTest>(manager, home, navGraphHelper, startNode, nearTarget));
		goals.push_back(make_unique<AntFollowPathAntTest>(manager, home, navGraphHelper, startNode, farTarget));
		break;
	default:
		throw runtime_error("Invalid goal selection");
	}

	return goals;
}

void createNavGraph1(vector<Node>& navGraph)
{
	navGraph.reserve(12);
	navGraph.push_back(Node(GridLocation(0, 0), 50, 50));	// 0
	navGraph.push_back(Node(GridLocation(0, 1), 150, 50));	// 1
	navGraph.push_back(Node(GridLocation(0, 2), 250, 50));	// 2
	navGraph.push_back(Node(GridLocation(0, 3), 350, 50));	// 3
	navGraph.push_back(Node(GridLocation(1, 0), 50, 150));	// 4
	navGraph.push_back(Node(GridLocation(1, 1), 150, 150));	// 5
	navGraph.push_back(Node(GridLocation(1, 2), 250, 150));	// 6
	navGraph.push_back(Node(GridLocation(1, 3), 350, 150));	// 7
	navGraph.push_back(Node(GridLocation(2, 0), 50, 250));	// 8
	navGraph.push_back(Node(GridLocation(2, 1), 150, 250));	// 9
	navGraph.push_back(Node(GridLocation(2, 2), 250, 250));	// 10
	navGraph.push_back(Node(GridLocation(2, 3), 350, 250));	// 11

	auto edge_00_01 = make_shared<Edge>(navGraph[0], navGraph[1], 1);
	auto edge_00_10 = make_shared<Edge>(navGraph[0], navGraph[4], 1);
	navGraph[0].addEdge(edge_00_01).addEdge(edge_00_10);

	auto edge_01_02 = make_shared<Edge>(navGraph[1], navGraph[2], 1);
	auto edge_01_11 = make_shared<Edge>(navGraph[1], navGraph[5], 1);
	navGraph[1].addEdge(edge_01_02).addEdge(edge_01_11);

	auto edge_02_03 = make_shared<Edge>(navGraph[2], navGraph[3], 1);
	auto edge_02_12 = make_shared<Edge>(navGraph[2], navGraph[6], 1);
	navGraph[2].addEdge(edge_02_03).addEdge(edge_02_12);

	auto edge_03_13 = make_shared<Edge>(navGraph[3], navGraph[7], 1);
	navGraph[3].addEdge(edge_03_13);

	auto edge_10_11 = make_shared<Edge>(navGraph[4], navGraph[5], 1);
	auto edge_10_20 = make_shared<Edge>(navGraph[4], navGraph[8], 1);
	navGraph[4].addEdge(edge_10_11).addEdge(edge_10_20);

	auto edge_11_12 = make_shared<Edge>(navGraph[5], navGraph[6], 1);
	auto edge_11_21 = make_shared<Edge>(navGraph[5], navGraph[9], 1);
	navGraph[5].addEdge(edge_11_12).addEdge(edge_11_21);

	auto edge_12_13 = make_shared<Edge>(navGraph[6], navGraph[7], 1);
	auto edge_12_22 = make_shared<Edge>(navGraph[6], navGraph[10], 1);
	navGraph[6].addEdge(edge_12_13).addEdge(edge_12_22);

	auto edge_13_23 = make_shared<Edge>(navGraph[7], navGraph[11], 1);
	navGraph[7].addEdge(edge_13_23);

	auto edge_20_21 = make_shared<Edge>(navGraph[8], navGraph[9], 1);
	navGraph[8].addEdge(edge_20_21);

	auto edge_21_22 = make_shared<Edge>(navGraph[9], navGraph[10], 1);
	navGraph[9].addEdge(edge_21_22);

	auto edge_22_23 = make_shared<Edge>(navGraph[10], navGraph[11], 1);
	navGraph[10].addEdge(edge_22_23);
}<commit_msg>Updated AntGoalTestApp<commit_after>#include "AntGoalTestApp.hpp"
#include "../sim/worldobject/AntHome.hpp"
#include "../sim/nav/Node.hpp"
#include "../sim/agent/testagent/AntGoalTester.hpp"
#include "../sim/agent/testagent/AntEatAntTest.hpp"
#include "../sim/agent/testagent/AntExploreAntTest.hpp"
#include "../sim/agent/testagent/AntFindFoodAntTest.hpp"
#include "../sim/agent/testagent/AntForageAntTest.hpp"
#include "../sim/agent/testagent/AntGoHomeAntTest.hpp"
#include "../sim/agent/testagent/AntMoveToNodeAntTest.hpp"
#include "../sim/agent/testagent/AntFollowPathAntTest.hpp"
#include "../util/make_unique.hpp"
#include "../sim/knowledge/GenericPercept.hpp"

#include <iostream>
#include <vector>

// Christopher D. Canfield
// November 2013
// AntGoalTestApp.cpp

using namespace std;
using namespace cdc;

void createNavGraph1(vector<Node>& navGraph);
std::vector<unique_ptr<AntGoalTester>> getTestAnts(GuiEventManager& manager, AntHome& home, NavGraphHelper& navGraphHelper,
									 Node& startNode, Node& nearTarget, Node& farTarget);

AntGoalTestApp::AntGoalTestApp() :
	viewManager(eventManager, 1000, 1000, 800, 800, 200, 800),
	ticks(0)
{
}

AntGoalTestApp::~AntGoalTestApp()
{
}

void AntGoalTestApp::setup()
{
	createNavGraph1(navGraph);
	foodPile = new AntFoodPile(100, navGraph[11]);
	navGraphHelper = NavGraphHelper(navGraph);

	antHome = new AntHome(navGraph[10], navGraph, world);
	goalTestAnts = getTestAnts(eventManager, *antHome, navGraphHelper, navGraph[0], navGraph[1], navGraph.back());

	window = std::unique_ptr<sf::RenderWindow>(new sf::RenderWindow(sf::VideoMode(800, 800), "GUI Tests"));
	window->setFramerateLimit(60);

	viewManager.setWindow(*window);
	viewManager.getSimView().setViewport(sf::FloatRect(0.f, 0.f, 1.f, 1.f));
}

bool AntGoalTestApp::run()
{
	if (ant != nullptr && ant->isGoalFinished() && goalTestAnts.empty())
	{
		return false;
	}

	if (ant == nullptr || ant->isGoalFinished())
	{
		ant = move(goalTestAnts.back());
		goalTestAnts.pop_back();
		cout << "----------------------------------------" << endl;
		cout << "Running ant test: " << (typeid(*ant.get()).name()) << endl;
		cout << "----------------------------------------" << endl;
	}

	sf::Event event;
	while (window->pollEvent(event))
	{
		if (event.type == sf::Event::Closed)
		{
			window->close();
			return false;
		}
		else
		{
			eventManager.update(event, *window);
		}
	}

	GenericPercept percept;
	ant->update(ticks, percept);
	++ticks;

	window->clear(sf::Color::Green);

	for (auto& node : navGraph)
	{
		window->draw(node);
	}
	for (auto& node : navGraph)
	{
		for (auto& edge : node.getEdgeList())
		{
			edge->drawPheromone(*window, sf::RenderStates::Default);
		}
	}

	window->draw(*ant);
	window->draw(*foodPile);

	window->display();

	return true;
}

void AntGoalTestApp::teardown()
{

}

std::vector<unique_ptr<AntGoalTester>> getTestAnts(GuiEventManager& manager, AntHome& home, NavGraphHelper& navGraphHelper,
									 Node& startNode, Node& nearTarget, Node& farTarget)
{
	cout << "Ant goal tester type: " << endl;
	cout << "  1: AntEat" << endl;
	cout << "  2: AntExplore" << endl;
	cout << "  3: AntFindFood" << endl;
	cout << "  4: AntForage" << endl;
	cout << "  5: AntGoHome" << endl;
	cout << "  6: AntMoveToNode" << endl;
	cout << "  7: AntFollowPath" << endl;
	cout << "  8: Run all tests" << endl;
	cout << "Type: ";

	int goalType;
	cin >> goalType;

	std::vector<unique_ptr<AntGoalTester>> goals;

	switch (goalType)
	{
	case 1:
		goals.push_back(make_unique<AntEatAntTest>(manager, home, navGraphHelper, startNode));
		break;
	case 2:
		goals.push_back(make_unique<AntExploreAntTest>(manager, home, navGraphHelper, startNode));
		break;
	case 3:
		goals.push_back(make_unique<AntFindFoodAntTest>(manager, home, navGraphHelper, startNode));
		break;
	case 4:
		goals.push_back(make_unique<AntForageAntTest>(manager, home, navGraphHelper, startNode));
		break;
	case 5:
		goals.push_back(make_unique<AntGoHomeAntTest>(manager, home, navGraphHelper, startNode));
		break;
	case 6:
		goals.push_back(make_unique<AntMoveToNodeAntTest>(manager, home, navGraphHelper, startNode, nearTarget));
		break;
	case 7:
		goals.push_back(make_unique<AntFollowPathAntTest>(manager, home, navGraphHelper, startNode, farTarget));
		break;
	case 8:
		goals.push_back(make_unique<AntEatAntTest>(manager, home, navGraphHelper, startNode));
		goals.push_back(make_unique<AntExploreAntTest>(manager, home, navGraphHelper, startNode));
		goals.push_back(make_unique<AntFindFoodAntTest>(manager, home, navGraphHelper, startNode));
		goals.push_back(make_unique<AntForageAntTest>(manager, home, navGraphHelper, startNode));
		goals.push_back(make_unique<AntGoHomeAntTest>(manager, home, navGraphHelper, startNode));
		goals.push_back(make_unique<AntMoveToNodeAntTest>(manager, home, navGraphHelper, startNode, nearTarget));
		goals.push_back(make_unique<AntFollowPathAntTest>(manager, home, navGraphHelper, startNode, farTarget));
		break;
	default:
		throw runtime_error("Invalid goal selection");
	}

	return goals;
}

void createNavGraph1(vector<Node>& navGraph)
{
	navGraph.reserve(12);
	navGraph.push_back(Node(GridLocation(0, 0), 50, 50));	// 0
	navGraph.push_back(Node(GridLocation(0, 1), 150, 50));	// 1
	navGraph.push_back(Node(GridLocation(0, 2), 250, 50));	// 2
	navGraph.push_back(Node(GridLocation(0, 3), 350, 50));	// 3
	navGraph.push_back(Node(GridLocation(1, 0), 50, 150));	// 4
	navGraph.push_back(Node(GridLocation(1, 1), 150, 150));	// 5
	navGraph.push_back(Node(GridLocation(1, 2), 250, 150));	// 6
	navGraph.push_back(Node(GridLocation(1, 3), 350, 150));	// 7
	navGraph.push_back(Node(GridLocation(2, 0), 50, 250));	// 8
	navGraph.push_back(Node(GridLocation(2, 1), 150, 250));	// 9
	navGraph.push_back(Node(GridLocation(2, 2), 250, 250));	// 10
	navGraph.push_back(Node(GridLocation(2, 3), 350, 250));	// 11

	auto edge_00_01 = make_shared<Edge>(navGraph[0], navGraph[1], 1);
	auto edge_00_10 = make_shared<Edge>(navGraph[0], navGraph[4], 1);
	navGraph[0].addEdge(edge_00_01).addEdge(edge_00_10);

	auto edge_01_02 = make_shared<Edge>(navGraph[1], navGraph[2], 1);
	auto edge_01_11 = make_shared<Edge>(navGraph[1], navGraph[5], 1);
	navGraph[1].addEdge(edge_01_02).addEdge(edge_01_11);

	auto edge_02_03 = make_shared<Edge>(navGraph[2], navGraph[3], 1);
	auto edge_02_12 = make_shared<Edge>(navGraph[2], navGraph[6], 1);
	navGraph[2].addEdge(edge_02_03).addEdge(edge_02_12);

	auto edge_03_13 = make_shared<Edge>(navGraph[3], navGraph[7], 1);
	navGraph[3].addEdge(edge_03_13);

	auto edge_10_11 = make_shared<Edge>(navGraph[4], navGraph[5], 1);
	auto edge_10_20 = make_shared<Edge>(navGraph[4], navGraph[8], 1);
	navGraph[4].addEdge(edge_10_11).addEdge(edge_10_20);

	auto edge_11_12 = make_shared<Edge>(navGraph[5], navGraph[6], 1);
	auto edge_11_21 = make_shared<Edge>(navGraph[5], navGraph[9], 1);
	navGraph[5].addEdge(edge_11_12).addEdge(edge_11_21);

	auto edge_12_13 = make_shared<Edge>(navGraph[6], navGraph[7], 1);
	auto edge_12_22 = make_shared<Edge>(navGraph[6], navGraph[10], 1);
	navGraph[6].addEdge(edge_12_13).addEdge(edge_12_22);

	auto edge_13_23 = make_shared<Edge>(navGraph[7], navGraph[11], 1);
	navGraph[7].addEdge(edge_13_23);

	auto edge_20_21 = make_shared<Edge>(navGraph[8], navGraph[9], 1);
	navGraph[8].addEdge(edge_20_21);

	auto edge_21_22 = make_shared<Edge>(navGraph[9], navGraph[10], 1);
	navGraph[9].addEdge(edge_21_22);

	auto edge_22_23 = make_shared<Edge>(navGraph[10], navGraph[11], 1);
	navGraph[10].addEdge(edge_22_23);
}<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "AbstractTransportFactory.h"

#include <memory>
#include <string>
#include <activemq/wireformat/WireFormat.h>
#include <activemq/wireformat/WireFormatRegistry.h>
#include <activemq/util/URISupport.h>
#include <activemq/transport/correlator/ResponseCorrelator.h>
#include <activemq/transport/logging/LoggingTransport.h>

using namespace std;
using namespace activemq;
using namespace activemq::transport;
using namespace activemq::transport::correlator;
using namespace activemq::transport::logging;
using namespace activemq::wireformat;
using namespace activemq::exceptions;
using namespace decaf;
using namespace decaf::lang;
using namespace decaf::lang::exceptions;
using namespace decaf::net;
using namespace decaf::util;

////////////////////////////////////////////////////////////////////////////////
Pointer<Transport> AbstractTransportFactory::create( const decaf::net::URI& location )
    throw ( exceptions::ActiveMQException ) {

    try{

        Properties properties =
            activemq::util::URISupport::parseQuery( location.getQuery() );

        Pointer<WireFormat> wireFormat = this->createWireFormat( properties );

        // Create the initial Transport, then wrap it in the normal Filters
        Pointer<Transport> transport( doCreateComposite( location, wireFormat, properties ) );

        // Create the Transport for response correlator
        transport.reset( new ResponseCorrelator( transport ) );

        // If command tracing was enabled, wrap the transport with a logging transport.
        if( properties.getProperty( "transport.commandTracingEnabled", "false" ) == "true" ) {
            // Create the Transport for response correlator
            transport.reset( new LoggingTransport( transport ) );
        }

        // If there is a negotiator need then we create and wrap here.
        if( wireFormat->hasNegotiator() ) {
            transport = wireFormat->createNegotiator( transport );
        }

        return transport;
    }
    AMQ_CATCH_RETHROW( ActiveMQException )
    AMQ_CATCH_EXCEPTION_CONVERT( Exception, ActiveMQException )
    AMQ_CATCHALL_THROW( ActiveMQException )
}

////////////////////////////////////////////////////////////////////////////////
Pointer<Transport> AbstractTransportFactory::createComposite( const decaf::net::URI& location )
    throw ( exceptions::ActiveMQException ) {

    try{

        Properties properties =
            activemq::util::URISupport::parseQuery( location.getQuery() );

        Pointer<WireFormat> wireFormat = this->createWireFormat( properties );

        // Create the initial Transport, then wrap it in the normal Filters
        Pointer<Transport> transport( doCreateComposite( location, wireFormat, properties ) );

        return transport;
    }
    AMQ_CATCH_RETHROW( ActiveMQException )
    AMQ_CATCH_EXCEPTION_CONVERT( Exception, ActiveMQException )
    AMQ_CATCHALL_THROW( ActiveMQException )
}

////////////////////////////////////////////////////////////////////////////////
Pointer<WireFormat> AbstractTransportFactory::createWireFormat(
    const decaf::util::Properties& properties )
        throw( decaf::lang::exceptions::NoSuchElementException ) {

    try{

        std::string wireFormat = properties.getProperty( "wireFormat", "openwire" );

        WireFormatFactory* factory =
            WireFormatRegistry::getInstance().findFactory( wireFormat );

        return Pointer<WireFormat>( factory->createWireFormat( properties ) );
    }
    AMQ_CATCH_RETHROW( NoSuchElementException )
    AMQ_CATCH_EXCEPTION_CONVERT( Exception, NoSuchElementException )
    AMQ_CATCHALL_THROW( NoSuchElementException )
}
<commit_msg>small cleanup<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "AbstractTransportFactory.h"

#include <memory>
#include <string>
#include <activemq/wireformat/WireFormat.h>
#include <activemq/wireformat/WireFormatRegistry.h>
#include <activemq/util/URISupport.h>
#include <activemq/transport/correlator/ResponseCorrelator.h>
#include <activemq/transport/logging/LoggingTransport.h>

using namespace std;
using namespace activemq;
using namespace activemq::transport;
using namespace activemq::transport::correlator;
using namespace activemq::transport::logging;
using namespace activemq::wireformat;
using namespace activemq::exceptions;
using namespace decaf;
using namespace decaf::lang;
using namespace decaf::lang::exceptions;
using namespace decaf::net;
using namespace decaf::util;

////////////////////////////////////////////////////////////////////////////////
Pointer<Transport> AbstractTransportFactory::create( const decaf::net::URI& location )
    throw ( exceptions::ActiveMQException ) {

    try{

        Properties properties =
            activemq::util::URISupport::parseQuery( location.getQuery() );

        Pointer<WireFormat> wireFormat = this->createWireFormat( properties );

        // Create the initial Transport, then wrap it in the normal Filters
        Pointer<Transport> transport( doCreateComposite( location, wireFormat, properties ) );

        // Create the Transport for response correlator
        transport.reset( new ResponseCorrelator( transport ) );

        // If command tracing was enabled, wrap the transport with a logging transport.
        if( properties.getProperty( "transport.commandTracingEnabled", "false" ) == "true" ) {
            // Create the Transport for response correlator
            transport.reset( new LoggingTransport( transport ) );
        }

        // If there is a negotiator need then we create and wrap here.
        if( wireFormat->hasNegotiator() ) {
            transport = wireFormat->createNegotiator( transport );
        }

        return transport;
    }
    AMQ_CATCH_RETHROW( ActiveMQException )
    AMQ_CATCH_EXCEPTION_CONVERT( Exception, ActiveMQException )
    AMQ_CATCHALL_THROW( ActiveMQException )
}

////////////////////////////////////////////////////////////////////////////////
Pointer<Transport> AbstractTransportFactory::createComposite( const decaf::net::URI& location )
    throw ( exceptions::ActiveMQException ) {

    try{

        Properties properties =
            activemq::util::URISupport::parseQuery( location.getQuery() );

        Pointer<WireFormat> wireFormat = this->createWireFormat( properties );

        // Create the initial Transport, then wrap it in the normal Filters
        return doCreateComposite( location, wireFormat, properties );
    }
    AMQ_CATCH_RETHROW( ActiveMQException )
    AMQ_CATCH_EXCEPTION_CONVERT( Exception, ActiveMQException )
    AMQ_CATCHALL_THROW( ActiveMQException )
}

////////////////////////////////////////////////////////////////////////////////
Pointer<WireFormat> AbstractTransportFactory::createWireFormat(
    const decaf::util::Properties& properties )
        throw( decaf::lang::exceptions::NoSuchElementException ) {

    try{

        std::string wireFormat = properties.getProperty( "wireFormat", "openwire" );

        WireFormatFactory* factory =
            WireFormatRegistry::getInstance().findFactory( wireFormat );

        return factory->createWireFormat( properties );
    }
    AMQ_CATCH_RETHROW( NoSuchElementException )
    AMQ_CATCH_EXCEPTION_CONVERT( Exception, NoSuchElementException )
    AMQ_CATCHALL_THROW( NoSuchElementException )
}
<|endoftext|>


<commit_before>#include "chromecast.hpp"
#include "cast_channel.pb.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <syslog.h>

ChromeCast::ChromeCast(const std::string& ip)
: m_ip(ip)
{
	if (!connect())
		throw std::runtime_error("could not connect");
}

ChromeCast::~ChromeCast()
{
	disconnect();
}

void ChromeCast::setMediaStatusCallback(std::function<void(const std::string&,
			const std::string&, const std::string&)> func)
{
	m_mediaStatusCallback = func;
}

unsigned int ChromeCast::_request_id()
{
	unsigned int request_id;
	m_mutex.lock();
	request_id = m_request_id++;
	m_mutex.unlock();
	return request_id;
}

bool ChromeCast::connect()
{
	m_s = socket(PF_INET, SOCK_STREAM, 0);
	if (m_s == -1)
		return false;
	struct sockaddr_in inaddr;
	memset(&inaddr, 0, sizeof inaddr);
	inaddr.sin_family = AF_INET;
	inaddr.sin_port = htons(8009);
	inaddr.sin_addr.s_addr = inet_addr(m_ip.c_str());
	if (::connect(m_s, (const struct sockaddr *)&inaddr,
				sizeof inaddr) != 0) {
		close(m_s);
		return false;
	}

	SSL_CTX* x = SSL_CTX_new(TLSv1_client_method());
	m_ssls = SSL_new(x);
	SSL_set_fd(m_ssls, m_s);
	SSL_set_mode(m_ssls, SSL_get_mode(m_ssls) | SSL_MODE_AUTO_RETRY);
	SSL_set_connect_state(m_ssls);
	if (SSL_connect(m_ssls) != 1) {
		SSL_free(m_ssls);
		m_ssls = NULL;
		close(m_s);
		return false;
	}
	m_tread = std::thread(&ChromeCast::_read, this);
	m_init = false;
	return true;
}

bool ChromeCast::init()
{
	static std::mutex m_init_mutex;
	std::lock_guard<std::mutex> lock(m_init_mutex);
	if (m_init)
		return true;

	if (!m_ssls)
		if (!connect())
			return false;

	m_destination_id = "receiver-0";
	m_session_id = "";
	Json::Value response;
	{
		Json::Value msg;
		msg["type"] = "CONNECT";
		msg["origin"] = Json::Value(Json::objectValue);
		send("urn:x-cast:com.google.cast.tp.connection", msg);
	}
	{
		Json::Value msg;
		msg["type"] = "GET_STATUS";
		msg["requestId"] = _request_id();
		response = send("urn:x-cast:com.google.cast.receiver", msg);
		bool isRunning = false;
		if (response.isMember("status") &&
			response["status"].isMember("applications") &&
			response["status"]["applications"].isValidIndex(0u)) {
			Json::Value& application = response["status"]["applications"][0u];
			if (application["appId"].asString() == "CC1AD845")
				isRunning = true;
		}
		if (!isRunning)
		{
			Json::Value msg;
			msg["type"] = "LAUNCH";
			msg["requestId"] = _request_id();
			msg["appId"] = "CC1AD845";
			response = send("urn:x-cast:com.google.cast.receiver", msg);
		}
	}
	if (response.isMember("status") &&
			response["status"].isMember("applications") &&
			response["status"]["applications"].isValidIndex(0u))
	{
		Json::Value& application = response["status"]["applications"][0u];
		m_destination_id = application["transportId"].asString();
		m_session_id = application["sessionId"].asString();
	}
	{
		Json::Value msg;
		msg["type"] = "CONNECT";
		msg["origin"] = Json::Value(Json::objectValue);
		send("urn:x-cast:com.google.cast.tp.connection", msg);
	}
	m_init = true;
	return true;
}

void ChromeCast::disconnect()
{
	m_tread.join();
	if (m_s != -1)
		close(m_s);
	if (m_ssls)
		SSL_free(m_ssls);
	m_s = -1;
	m_ssls = NULL;
	m_init = false;
}

Json::Value ChromeCast::send(const std::string& namespace_, const Json::Value& payload)
{
	Json::FastWriter fw;
	fw.omitEndingLineFeed();

	extensions::core_api::cast_channel::CastMessage msg;
	msg.set_payload_type(msg.STRING);
	msg.set_protocol_version(msg.CASTV2_1_0);
	msg.set_namespace_(namespace_);
	msg.set_source_id(m_source_id);
	msg.set_destination_id(m_destination_id);
	msg.set_payload_utf8(fw.write(payload));

	std::string data, foo;
	char pktlen[4];
	unsigned int len = htonl(msg.ByteSize());
	memcpy(&pktlen, &len, sizeof len);
	foo.append(pktlen, sizeof pktlen);
	msg.SerializeToString(&data);
	foo += data;

	std::condition_variable f;
	bool wait = false;
	unsigned int requestId;
	if (payload.isMember("requestId"))
	{
		requestId = payload["requestId"].asUInt();
		m_mutex.lock();
		m_wait[requestId] = std::make_pair(&f, std::string());
		wait = true;
		m_mutex.unlock();
	}

	syslog(LOG_DEBUG, "%s -> %s (%s): %s",
			msg.source_id().c_str(),
			msg.destination_id().c_str(),
			msg.namespace_().c_str(),
			msg.payload_utf8().c_str()
		  );

	int w;
	m_ssl_mutex.lock();
	if (m_ssls) {
		w = SSL_write(m_ssls, foo.c_str(), foo.size());
		if (w == -1) {
			syslog(LOG_DEBUG, "SSL_write eror");
			disconnect();
		}
	} else
		w = -1;
	m_ssl_mutex.unlock();

	if (wait && w == -1)
	{
		m_mutex.lock();
		m_wait.erase(requestId);
		m_mutex.unlock();
		wait = false;
	}

	Json::Value ret;
	if (wait) {
		std::unique_lock<std::mutex> wl(m_mutex);
		f.wait(wl);
		ret = m_wait[requestId].second;
		m_wait.erase(requestId);
		m_mutex.unlock();
	}

	return ret;
}

void ChromeCast::_read()
{
	while (true)
	{
		char pktlen[4];
		int r;
		for (r = 0; r < sizeof pktlen; ++r)
			if (SSL_read(m_ssls, pktlen + r, 1) < 1)
				break;
		if (r != sizeof pktlen) {
			syslog(LOG_ERR, "SSL_read error");
			m_mutex.lock();
			for (auto& item : m_wait) {
				item.second.second = Json::Value();
				item.second.first->notify_all();
			}
			m_mutex.unlock();
			return;
		}

		unsigned int len;
		memcpy(&len, pktlen, sizeof len);
		len = ntohl(len);

		std::string buf;
		while (buf.size() < len) {
			char b[2048];
			int r = SSL_read(m_ssls, b, sizeof b);
			if (r < 1)
				break;
			buf.append(b, r);
		}
		if (buf.size() != len) {
			syslog(LOG_ERR, "SSL_read error");
			m_mutex.lock();
			for (auto& item : m_wait) {
				item.second.second = Json::Value();
				item.second.first->notify_all();
			}
			m_mutex.unlock();
			return;
		}

		extensions::core_api::cast_channel::CastMessage msg;
		msg.ParseFromString(buf);

		syslog(LOG_DEBUG, "%s -> %s (%s): %s",
				msg.source_id().c_str(),
				msg.destination_id().c_str(),
				msg.namespace_().c_str(),
				msg.payload_utf8().c_str()
			  );

		Json::Value response;
		Json::Reader reader;
		if (!reader.parse(msg.payload_utf8(), response, false))
			continue;

		if (msg.namespace_() == "urn:x-cast:com.google.cast.tp.heartbeat")
		{
			Json::FastWriter fw;
			fw.omitEndingLineFeed();

			extensions::core_api::cast_channel::CastMessage reply(msg);
			Json::Value msg;
			msg["type"] = "PONG";
			reply.set_payload_utf8(fw.write(msg));
			std::string data;
			reply.SerializeToString(&data);
			unsigned int len = htonl(data.size());
			SSL_write(m_ssls, &len, sizeof len);
			SSL_write(m_ssls, data.c_str(), data.size());
			continue;
		}

		if (msg.namespace_() == "urn:x-cast:com.google.cast.tp.connection")
		{
			if (response["type"].asString() == "CLOSE")
			{
				m_mutex.lock();
				m_init = false;
				for (auto& item : m_wait) {
					item.second.second = Json::Value();
					item.second.first->notify_all();
				}
				m_mutex.unlock();
			}
		}

		if (msg.namespace_() == "urn:x-cast:com.google.cast.media")
		{
			if (response["type"].asString() == "MEDIA_STATUS")
			{
				if (response.isMember("status") &&
					response["status"].isValidIndex(0u))
				{
					Json::Value& status = response["status"][0u];
					m_media_session_id = status["mediaSessionId"].asUInt();
				}
			}
		}

		if (response.isMember("requestId"))
		{
			m_mutex.lock();
			auto waitIter = m_wait.find(response["requestId"].asUInt());
			if (waitIter != m_wait.end())
			{
				waitIter->second.second = response;
				waitIter->second.first->notify_all();
			}
			m_mutex.unlock();
		}

		if (msg.namespace_() == "urn:x-cast:com.google.cast.media")
		{
			if (response["type"].asString() == "MEDIA_STATUS")
			{
				if (response.isMember("status") &&
					response["status"].isValidIndex(0u))
				{
					std::string uuid = m_uuid;
					Json::Value& status = response["status"][0u];
					m_player_state = status["playerState"].asString();
					if (status["playerState"] == "IDLE")
						m_uuid = "";
					if (status["playerState"] == "BUFFERING")
						uuid = m_uuid = status["media"]["customData"]["uuid"].asString();
					if (m_mediaStatusCallback)
						m_mediaStatusCallback(status["playerState"].asString(),
								status["idleReason"].asString(),
								uuid);
				}
			}
		}
	}
}

const std::string& ChromeCast::getUUID() const
{
	return m_uuid;
}

const std::string& ChromeCast::getPlayerState() const
{
	return m_player_state;
}

std::string ChromeCast::getSocketName() const
{
	struct sockaddr_in addr;
    socklen_t len = sizeof(struct sockaddr);
	getsockname(m_s, (struct sockaddr*)&addr, &len);
	return inet_ntoa(addr.sin_addr);
}

bool isPlayerState(const Json::Value& response, const std::string& playerState)
{
	if (response.isMember("type") && response["type"].asString() == "MEDIA_STATUS")
	{
		if (response.isMember("status") &&
				response["status"].isValidIndex(0u))
		{
			const Json::Value& status = response["status"][0u];
			if (status.isMember("playerState") && status["playerState"].asString() == playerState)
				return true;
		}
	}
	return false;
}

bool ChromeCast::load(const std::string& url, const std::string& title, const std::string& uuid)
{
	if (!m_init && !init())
		return false;
	Json::Value msg, response;
	msg["type"] = "LOAD";
	msg["requestId"] = _request_id();
	msg["sessionId"] = m_session_id;
	msg["media"]["contentId"] = url;
	msg["media"]["streamType"] = "buffered";
	msg["media"]["contentType"] = "video/x-matroska";
	msg["media"]["customData"]["uuid"] = uuid;
	msg["media"]["metadata"]["title"] = title;
	msg["autoplay"] = true;
	msg["currentTime"] = 0;
	response = send("urn:x-cast:com.google.cast.media", msg);
	return isPlayerState(response, "BUFFERING") || isPlayerState(response, "PLAYING");
}

bool ChromeCast::pause()
{
	if (!m_init && !init())
		return false;
	Json::Value msg, response;
	msg["type"] = "PAUSE";
	msg["requestId"] = _request_id();
	msg["mediaSessionId"] = m_media_session_id;
	response = send("urn:x-cast:com.google.cast.media", msg);
	return isPlayerState(response, "PAUSED");
}

bool ChromeCast::play()
{
	if (!m_init && !init())
		return false;
	Json::Value msg, response;
	msg["type"] = "PLAY";
	msg["requestId"] = _request_id();
	msg["mediaSessionId"] = m_media_session_id;
	response = send("urn:x-cast:com.google.cast.media", msg);
	return isPlayerState(response, "BUFFERING") || isPlayerState(response, "PLAYING");
}

bool ChromeCast::stop()
{
	if (!m_init && !init())
		return false;
	Json::Value msg, response;
	msg["type"] = "STOP";
	msg["requestId"] = _request_id();
	msg["mediaSessionId"] = m_media_session_id;
	response = send("urn:x-cast:com.google.cast.media", msg);
	return isPlayerState(response, "IDLE");
}
<commit_msg>spelling<commit_after>#include "chromecast.hpp"
#include "cast_channel.pb.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <syslog.h>

ChromeCast::ChromeCast(const std::string& ip)
: m_ip(ip)
{
	if (!connect())
		throw std::runtime_error("could not connect");
}

ChromeCast::~ChromeCast()
{
	disconnect();
}

void ChromeCast::setMediaStatusCallback(std::function<void(const std::string&,
			const std::string&, const std::string&)> func)
{
	m_mediaStatusCallback = func;
}

unsigned int ChromeCast::_request_id()
{
	unsigned int request_id;
	m_mutex.lock();
	request_id = m_request_id++;
	m_mutex.unlock();
	return request_id;
}

bool ChromeCast::connect()
{
	m_s = socket(PF_INET, SOCK_STREAM, 0);
	if (m_s == -1)
		return false;
	struct sockaddr_in inaddr;
	memset(&inaddr, 0, sizeof inaddr);
	inaddr.sin_family = AF_INET;
	inaddr.sin_port = htons(8009);
	inaddr.sin_addr.s_addr = inet_addr(m_ip.c_str());
	if (::connect(m_s, (const struct sockaddr *)&inaddr,
				sizeof inaddr) != 0) {
		close(m_s);
		return false;
	}

	SSL_CTX* x = SSL_CTX_new(TLSv1_client_method());
	m_ssls = SSL_new(x);
	SSL_set_fd(m_ssls, m_s);
	SSL_set_mode(m_ssls, SSL_get_mode(m_ssls) | SSL_MODE_AUTO_RETRY);
	SSL_set_connect_state(m_ssls);
	if (SSL_connect(m_ssls) != 1) {
		SSL_free(m_ssls);
		m_ssls = NULL;
		close(m_s);
		return false;
	}
	m_tread = std::thread(&ChromeCast::_read, this);
	m_init = false;
	return true;
}

bool ChromeCast::init()
{
	static std::mutex m_init_mutex;
	std::lock_guard<std::mutex> lock(m_init_mutex);
	if (m_init)
		return true;

	if (!m_ssls)
		if (!connect())
			return false;

	m_destination_id = "receiver-0";
	m_session_id = "";
	Json::Value response;
	{
		Json::Value msg;
		msg["type"] = "CONNECT";
		msg["origin"] = Json::Value(Json::objectValue);
		send("urn:x-cast:com.google.cast.tp.connection", msg);
		if (!m_ssls) return false;
	}
	{
		Json::Value msg;
		msg["type"] = "GET_STATUS";
		msg["requestId"] = _request_id();
		response = send("urn:x-cast:com.google.cast.receiver", msg);
		bool isRunning = false;
		if (response.isMember("status") &&
			response["status"].isMember("applications") &&
			response["status"]["applications"].isValidIndex(0u)) {
			Json::Value& application = response["status"]["applications"][0u];
			if (application["appId"].asString() == "CC1AD845")
				isRunning = true;
		}
		if (!isRunning)
		{
			Json::Value msg;
			msg["type"] = "LAUNCH";
			msg["requestId"] = _request_id();
			msg["appId"] = "CC1AD845";
			response = send("urn:x-cast:com.google.cast.receiver", msg);
		}
	}
	if (response.isMember("status") &&
			response["status"].isMember("applications") &&
			response["status"]["applications"].isValidIndex(0u))
	{
		Json::Value& application = response["status"]["applications"][0u];
		m_destination_id = application["transportId"].asString();
		m_session_id = application["sessionId"].asString();
	}
	{
		Json::Value msg;
		msg["type"] = "CONNECT";
		msg["origin"] = Json::Value(Json::objectValue);
		send("urn:x-cast:com.google.cast.tp.connection", msg);
	}
	m_init = true;
	return true;
}

void ChromeCast::disconnect()
{
	m_tread.join();
	if (m_s != -1)
		close(m_s);
	if (m_ssls)
		SSL_free(m_ssls);
	m_s = -1;
	m_ssls = NULL;
	m_init = false;
}

Json::Value ChromeCast::send(const std::string& namespace_, const Json::Value& payload)
{
	Json::FastWriter fw;
	fw.omitEndingLineFeed();

	extensions::core_api::cast_channel::CastMessage msg;
	msg.set_payload_type(msg.STRING);
	msg.set_protocol_version(msg.CASTV2_1_0);
	msg.set_namespace_(namespace_);
	msg.set_source_id(m_source_id);
	msg.set_destination_id(m_destination_id);
	msg.set_payload_utf8(fw.write(payload));

	std::string data, foo;
	char pktlen[4];
	unsigned int len = htonl(msg.ByteSize());
	memcpy(&pktlen, &len, sizeof len);
	foo.append(pktlen, sizeof pktlen);
	msg.SerializeToString(&data);
	foo += data;

	std::condition_variable f;
	bool wait = false;
	unsigned int requestId;
	if (payload.isMember("requestId"))
	{
		requestId = payload["requestId"].asUInt();
		m_mutex.lock();
		m_wait[requestId] = std::make_pair(&f, std::string());
		wait = true;
		m_mutex.unlock();
	}

	syslog(LOG_DEBUG, "%s -> %s (%s): %s",
			msg.source_id().c_str(),
			msg.destination_id().c_str(),
			msg.namespace_().c_str(),
			msg.payload_utf8().c_str()
		  );

	int w;
	m_ssl_mutex.lock();
	if (m_ssls) {
		w = SSL_write(m_ssls, foo.c_str(), foo.size());
		if (w == -1) {
			syslog(LOG_DEBUG, "SSL_write reror");
			disconnect();
		}
	} else
		w = -1;
	m_ssl_mutex.unlock();

	if (wait && w == -1)
	{
		m_mutex.lock();
		m_wait.erase(requestId);
		m_mutex.unlock();
		wait = false;
	}

	Json::Value ret;
	if (wait) {
		std::unique_lock<std::mutex> wl(m_mutex);
		f.wait(wl);
		ret = m_wait[requestId].second;
		m_wait.erase(requestId);
		m_mutex.unlock();
	}

	return ret;
}

void ChromeCast::_read()
{
	while (true)
	{
		char pktlen[4];
		int r;
		for (r = 0; r < sizeof pktlen; ++r)
			if (SSL_read(m_ssls, pktlen + r, 1) < 1)
				break;
		if (r != sizeof pktlen) {
			syslog(LOG_ERR, "SSL_read error");
			m_mutex.lock();
			for (auto& item : m_wait) {
				item.second.second = Json::Value();
				item.second.first->notify_all();
			}
			m_mutex.unlock();
			return;
		}

		unsigned int len;
		memcpy(&len, pktlen, sizeof len);
		len = ntohl(len);

		std::string buf;
		while (buf.size() < len) {
			char b[2048];
			int r = SSL_read(m_ssls, b, sizeof b);
			if (r < 1)
				break;
			buf.append(b, r);
		}
		if (buf.size() != len) {
			syslog(LOG_ERR, "SSL_read error");
			m_mutex.lock();
			for (auto& item : m_wait) {
				item.second.second = Json::Value();
				item.second.first->notify_all();
			}
			m_mutex.unlock();
			return;
		}

		extensions::core_api::cast_channel::CastMessage msg;
		msg.ParseFromString(buf);

		syslog(LOG_DEBUG, "%s -> %s (%s): %s",
				msg.source_id().c_str(),
				msg.destination_id().c_str(),
				msg.namespace_().c_str(),
				msg.payload_utf8().c_str()
			  );

		Json::Value response;
		Json::Reader reader;
		if (!reader.parse(msg.payload_utf8(), response, false))
			continue;

		if (msg.namespace_() == "urn:x-cast:com.google.cast.tp.heartbeat")
		{
			Json::FastWriter fw;
			fw.omitEndingLineFeed();

			extensions::core_api::cast_channel::CastMessage reply(msg);
			Json::Value msg;
			msg["type"] = "PONG";
			reply.set_payload_utf8(fw.write(msg));
			std::string data;
			reply.SerializeToString(&data);
			unsigned int len = htonl(data.size());
			SSL_write(m_ssls, &len, sizeof len);
			SSL_write(m_ssls, data.c_str(), data.size());
			continue;
		}

		if (msg.namespace_() == "urn:x-cast:com.google.cast.tp.connection")
		{
			if (response["type"].asString() == "CLOSE")
			{
				m_mutex.lock();
				m_init = false;
				for (auto& item : m_wait) {
					item.second.second = Json::Value();
					item.second.first->notify_all();
				}
				m_mutex.unlock();
			}
		}

		if (msg.namespace_() == "urn:x-cast:com.google.cast.media")
		{
			if (response["type"].asString() == "MEDIA_STATUS")
			{
				if (response.isMember("status") &&
					response["status"].isValidIndex(0u))
				{
					Json::Value& status = response["status"][0u];
					m_media_session_id = status["mediaSessionId"].asUInt();
				}
			}
		}

		if (response.isMember("requestId"))
		{
			m_mutex.lock();
			auto waitIter = m_wait.find(response["requestId"].asUInt());
			if (waitIter != m_wait.end())
			{
				waitIter->second.second = response;
				waitIter->second.first->notify_all();
			}
			m_mutex.unlock();
		}

		if (msg.namespace_() == "urn:x-cast:com.google.cast.media")
		{
			if (response["type"].asString() == "MEDIA_STATUS")
			{
				if (response.isMember("status") &&
					response["status"].isValidIndex(0u))
				{
					std::string uuid = m_uuid;
					Json::Value& status = response["status"][0u];
					m_player_state = status["playerState"].asString();
					if (status["playerState"] == "IDLE")
						m_uuid = "";
					if (status["playerState"] == "BUFFERING")
						uuid = m_uuid = status["media"]["customData"]["uuid"].asString();
					if (m_mediaStatusCallback)
						m_mediaStatusCallback(status["playerState"].asString(),
								status["idleReason"].asString(),
								uuid);
				}
			}
		}
	}
}

const std::string& ChromeCast::getUUID() const
{
	return m_uuid;
}

const std::string& ChromeCast::getPlayerState() const
{
	return m_player_state;
}

std::string ChromeCast::getSocketName() const
{
	struct sockaddr_in addr;
    socklen_t len = sizeof(struct sockaddr);
	getsockname(m_s, (struct sockaddr*)&addr, &len);
	return inet_ntoa(addr.sin_addr);
}

bool isPlayerState(const Json::Value& response, const std::string& playerState)
{
	if (response.isMember("type") && response["type"].asString() == "MEDIA_STATUS")
	{
		if (response.isMember("status") &&
				response["status"].isValidIndex(0u))
		{
			const Json::Value& status = response["status"][0u];
			if (status.isMember("playerState") && status["playerState"].asString() == playerState)
				return true;
		}
	}
	return false;
}

bool ChromeCast::load(const std::string& url, const std::string& title, const std::string& uuid)
{
	if (!m_init && !init())
		return false;
	Json::Value msg, response;
	msg["type"] = "LOAD";
	msg["requestId"] = _request_id();
	msg["sessionId"] = m_session_id;
	msg["media"]["contentId"] = url;
	msg["media"]["streamType"] = "buffered";
	msg["media"]["contentType"] = "video/x-matroska";
	msg["media"]["customData"]["uuid"] = uuid;
	msg["media"]["metadata"]["title"] = title;
	msg["autoplay"] = true;
	msg["currentTime"] = 0;
	response = send("urn:x-cast:com.google.cast.media", msg);
	return isPlayerState(response, "BUFFERING") || isPlayerState(response, "PLAYING");
}

bool ChromeCast::pause()
{
	if (!m_init && !init())
		return false;
	Json::Value msg, response;
	msg["type"] = "PAUSE";
	msg["requestId"] = _request_id();
	msg["mediaSessionId"] = m_media_session_id;
	response = send("urn:x-cast:com.google.cast.media", msg);
	return isPlayerState(response, "PAUSED");
}

bool ChromeCast::play()
{
	if (!m_init && !init())
		return false;
	Json::Value msg, response;
	msg["type"] = "PLAY";
	msg["requestId"] = _request_id();
	msg["mediaSessionId"] = m_media_session_id;
	response = send("urn:x-cast:com.google.cast.media", msg);
	return isPlayerState(response, "BUFFERING") || isPlayerState(response, "PLAYING");
}

bool ChromeCast::stop()
{
	if (!m_init && !init())
		return false;
	Json::Value msg, response;
	msg["type"] = "STOP";
	msg["requestId"] = _request_id();
	msg["mediaSessionId"] = m_media_session_id;
	response = send("urn:x-cast:com.google.cast.media", msg);
	return isPlayerState(response, "IDLE");
}
<|endoftext|>


<commit_before>/*
 * IPAddress6.cpp
 *
 * Copyright (C) 2006 - 2008 by Universitaet Stuttgart (VIS).
 * Alle Rechte vorbehalten.
 * Copyright (C) 2008 by Christoph Mller. Alle Rechte vorbehalten.
 */

#include "vislib/IPAddress6.h"

#include <cstdlib>

#include "vislib/assert.h"
#include "vislib/DNS.h"
#include "vislib/IllegalStateException.h"
#include "vislib/OutOfRangeException.h"
#include "vislib/SocketException.h"
#include "vislib/Trace.h"

/*
 * vislib::net::IPAddress6::Create
 */
vislib::net::IPAddress6 vislib::net::IPAddress6::Create(
        const char *hostNameOrAddress) {
    IPAddress6 retval;
    DNS::GetHostAddress(retval, hostNameOrAddress);
    return retval;
}

/*
 * vislib::net::IPAddress6::Create
 */
vislib::net::IPAddress6 vislib::net::IPAddress6::Create(
        const wchar_t *hostNameOrAddress) {
    IPAddress6 retval;
    DNS::GetHostAddress(retval, hostNameOrAddress);
    return retval;
}

/*
 * vislib::net::IPAddress6::ALL_NODES_ON_LINK
 */
const vislib::net::IPAddress6 vislib::net::IPAddress6::ALL_NODES_ON_LINK(
#ifdef _WIN32
    ::in6addr_allnodesonlink);
#else /* _WIN32 */
    "ff02::1");
#endif /* _WIN32 */

/*
 * vislib::net::IPAddress6::ALL_ROUTERS_ON_LINK
 */
const vislib::net::IPAddress6 vislib::net::IPAddress6::ALL_ROUTERS_ON_LINK(
#ifdef _WIN32
    ::in6addr_allroutersonlink);
#else /* _WIN32 */
    "ff02::2");
#endif /* _WIN32 */

/*
 * vislib::net::IPAddress6::ALL_NODES_ON_NODE
 */
const vislib::net::IPAddress6 vislib::net::IPAddress6::ALL_NODES_ON_NODE(
#ifdef _WIN32
    ::in6addr_allnodesonnode);
#else /* _WIN32 */
    "ff01::1");
#endif /* _WIN32 */

/*
 * vislib::net::IPAddress6::ANY
 */
const vislib::net::IPAddress6 vislib::net::IPAddress6::ANY(::in6addr_any);

/*
 * vislib::net::IPAddress6::LOCALHOST
 */
const vislib::net::IPAddress6& vislib::net::IPAddress6::LOCALHOST
    = vislib::net::IPAddress6::LOOPBACK;

/*
 * vislib::net::IPAddress6::LOOPBACK
 */
const vislib::net::IPAddress6 vislib::net::IPAddress6::LOOPBACK(
    ::in6addr_loopback);

/*
 * vislib::net::IPAddress6::UNSPECIFIED
 */
const vislib::net::IPAddress6& vislib::net::IPAddress6::UNSPECIFIED
    = vislib::net::IPAddress6::ANY;

/*
 * vislib::net::IPAddress6::IPAddress6
 */
vislib::net::IPAddress6::IPAddress6(void) {
    *this = ::in6addr_loopback;
}

/*
 * vislib::net::IPAddress6::IPAddress6
 */
vislib::net::IPAddress6::IPAddress6(const struct in6_addr& address) {
    *this = address;
}

/*
 * vislib::net::IPAddress6::IPAddress6
 */
vislib::net::IPAddress6::IPAddress6(
        const BYTE b1, const BYTE b2, const BYTE b3, const BYTE b4,
        const BYTE b5, const BYTE b6, const BYTE b7, const BYTE b8,
        const BYTE b9, const BYTE b10, const BYTE b11, const BYTE b12,
        const BYTE b13, const BYTE b14, const BYTE b15, const BYTE b16) {
#define VLIPADDR5_INITBYTE(n) this->address.s6_addr[n - 1] = b##n
    VLIPADDR5_INITBYTE(1);
    VLIPADDR5_INITBYTE(2);
    VLIPADDR5_INITBYTE(3);
    VLIPADDR5_INITBYTE(4);
    VLIPADDR5_INITBYTE(5);
    VLIPADDR5_INITBYTE(6);
    VLIPADDR5_INITBYTE(7);
    VLIPADDR5_INITBYTE(8);
    VLIPADDR5_INITBYTE(9);
    VLIPADDR5_INITBYTE(10);
    VLIPADDR5_INITBYTE(11);
    VLIPADDR5_INITBYTE(12);
    VLIPADDR5_INITBYTE(13);
    VLIPADDR5_INITBYTE(14);
    VLIPADDR5_INITBYTE(15);
    VLIPADDR5_INITBYTE(16);
#undef VLIPADDR5_INITBYTE
}

/*
 * vislib::net::IPAddress6::IPAddress6
 */
vislib::net::IPAddress6::IPAddress6(const IPAddress& address) {
    this->MapV4Address(address);
}

/*
 * vislib::net::IPAddress6::IPAddress6
 */
vislib::net::IPAddress6::IPAddress6(const struct in_addr& address) {
    this->MapV4Address(address);
}

/*
 * vislib::net::IPAddress6::IPAddress6
 */
vislib::net::IPAddress6::IPAddress6(const IPAddress6& rhs) {
    *this = rhs;
}

/*
 * vislib::net::IPAddress6::~IPAddress6
 */
vislib::net::IPAddress6::~IPAddress6(void) {
}

/*
 * vislib::net::IPAddress6::GetPrefix
 */
vislib::net::IPAddress6
vislib::net::IPAddress6::GetPrefix(const ULONG prefixLength) const {
    IPAddress6 retval;
    int cntBytes = sizeof(retval.address.s6_addr);
    int cntPrefix = prefixLength > static_cast<ULONG>(8 * cntBytes)
        ? cntBytes : static_cast<int>(prefixLength);
    div_t cntCopy = ::div(cntPrefix, 8);

    /* Zero out everything. */
    ::ZeroMemory(retval.address.s6_addr, cntBytes);

    /* Copy complete bytes. */
    ::memcpy(retval.address.s6_addr, this->address.s6_addr, cntCopy.quot);

    /* Copy fraction of incomplete byte if necessary. */
    if (cntCopy.rem > 0) {
        retval.address.s6_addr[cntCopy.quot]
            = this->address.s6_addr[cntCopy.quot] << (8 - cntCopy.rem);
    }

    return retval;
}

/*
 * vislib::net::IPAddress6::MapV4Address
 */
void vislib::net::IPAddress6::MapV4Address(const struct in_addr& address) {
    /* Zero out first 80 bits. */
    for (int i = 0; i < 10; i++) {
        this->address.s6_addr[i] = 0;
    }

    /* Bits 80 to 95 must be all 1. */
    for (int i = 10; i < 12; i++) {
        this->address.s6_addr[i] = 0xff;
    }

    /* Embed IPv4 in the last 32 bits. */
    ASSERT(sizeof(in_addr) == 4);
    ::memcpy(this->address.s6_addr + 12, &address, sizeof(in_addr));

    ASSERT(this->IsV4Mapped());
}

/*
 * vislib::net::IPAddress6::ToStringA
 */
vislib::StringA vislib::net::IPAddress6::ToStringA(void) const {
    struct sockaddr_in6 addr;   // Dummy socket address used for lookup.
    char buffer[NI_MAXHOST];    // Receives the stringised address.
    int err = 0;                // OS operation return value.

    ::ZeroMemory(&addr, sizeof(addr));
    addr.sin6_family = AF_INET6;
    ::memcpy(&addr.sin6_addr, &this->address, sizeof(struct in6_addr));

    if ((err = ::getnameinfo(reinterpret_cast<struct sockaddr *>(&addr),
            sizeof(struct sockaddr_in6), buffer, sizeof(buffer), NULL, 0,
            NI_NUMERICHOST)) != 0) {
        VLTRACE(Trace::LEVEL_VL_ERROR, "::getnameinfo failed in "
            "IPAddress6::ToStringA(): %s\n",
#ifdef _WIN32
            ::gai_strerrorA(err)
#else /* _WIN32 */
            ::gai_strerror(err)
#endif /* _WIN32 */
        );
        buffer[0] = 0;
    }

    return StringA(buffer);
}

/*
 * vislib::net::IPAddress6::UnmapV4Address
 */
vislib::net::IPAddress vislib::net::IPAddress6::UnmapV4Address(void) const {
    if (this->IsV4Mapped()) {
        return IPAddress(*reinterpret_cast<const in_addr *>(
            this->address.s6_addr + 12));
    } else {
        throw IllegalStateException("The IPv6 address is not a mapped IPv4 "
            "address.", __FILE__, __LINE__);
    }
}

/*
 * vislib::net::IPAddress6::operator []
 */
BYTE vislib::net::IPAddress6::operator [](const int i) const {
    if ((i > 0) && (i < static_cast<int>(sizeof(this->address)))) {
        return reinterpret_cast<const BYTE *>(&this->address)[i];
    } else {
        throw OutOfRangeException(i, 0, sizeof(this->address), __FILE__,
            __LINE__);
    }
}

/*
 * vislib::net::IPAddress6::operator =
 */
vislib::net::IPAddress6& vislib::net::IPAddress6::operator =(
        const struct in6_addr& rhs) {
    if (&this->address != &rhs) {
        ::memcpy(&this->address, &rhs, sizeof(struct in6_addr));
    }

    return *this;
}

/*
 * vislib::net::IPAddress6::operator =
 */
vislib::net::IPAddress6& vislib::net::IPAddress6::operator =(
        const IPAddress& rhs) {
    this->MapV4Address(rhs);
    return *this;
}

/*
 * vislib::net::IPAddress6::operator ==
 */
bool vislib::net::IPAddress6::operator ==(const struct in6_addr& rhs) const {
#ifndef _WIN32
#define IN6_ADDR_EQUAL IN6_ARE_ADDR_EQUAL
#endif /* !_WIN32 */
    return (IN6_ADDR_EQUAL(&this->address, &rhs) != 0);
}

/*
 * vislib::net::IPAddress6::IPAddress
 */
vislib::net::IPAddress6::operator vislib::net::IPAddress(void) const {
    if (this->IsV4Compatible()) {
        return IPAddress(*reinterpret_cast<const in_addr *>(
            this->address.s6_addr + 12));
    } else {
        return this->UnmapV4Address();
    }
}
<commit_msg>Linux hotfix<commit_after>/*
 * IPAddress6.cpp
 *
 * Copyright (C) 2006 - 2008 by Universitaet Stuttgart (VIS).
 * Alle Rechte vorbehalten.
 * Copyright (C) 2008 by Christoph Mller. Alle Rechte vorbehalten.
 */

#include "vislib/IPAddress6.h"

#include <cstdlib>

#include "vislib/assert.h"
#include "vislib/DNS.h"
#include "vislib/IllegalStateException.h"
#include "vislib/OutOfRangeException.h"
#include "vislib/SocketException.h"
#include "vislib/Trace.h"

/*
 * vislib::net::IPAddress6::Create
 */
vislib::net::IPAddress6 vislib::net::IPAddress6::Create(
        const char *hostNameOrAddress) {
    IPAddress6 retval;
    DNS::GetHostAddress(retval, hostNameOrAddress);
    return retval;
}

/*
 * vislib::net::IPAddress6::Create
 */
vislib::net::IPAddress6 vislib::net::IPAddress6::Create(
        const wchar_t *hostNameOrAddress) {
    IPAddress6 retval;
    DNS::GetHostAddress(retval, hostNameOrAddress);
    return retval;
}

/*
 * vislib::net::IPAddress6::ALL_NODES_ON_LINK
 */
const vislib::net::IPAddress6 vislib::net::IPAddress6::ALL_NODES_ON_LINK
#ifdef _WIN32
    (::in6addr_allnodesonlink);
#else /* _WIN32 */
    = vislib::net::IPAddress6::Create("ff02::1");
#endif /* _WIN32 */

/*
 * vislib::net::IPAddress6::ALL_ROUTERS_ON_LINK
 */
const vislib::net::IPAddress6 vislib::net::IPAddress6::ALL_ROUTERS_ON_LINK
#ifdef _WIN32
    (::in6addr_allroutersonlink);
#else /* _WIN32 */
    = vislib::net::IPAddress6::Create("ff02::2");
#endif /* _WIN32 */

/*
 * vislib::net::IPAddress6::ALL_NODES_ON_NODE
 */
const vislib::net::IPAddress6 vislib::net::IPAddress6::ALL_NODES_ON_NODE
#ifdef _WIN32
    (::in6addr_allnodesonnode);
#else /* _WIN32 */
    = vislib::net::IPAddress6::Create("ff01::1");
#endif /* _WIN32 */

/*
 * vislib::net::IPAddress6::ANY
 */
const vislib::net::IPAddress6 vislib::net::IPAddress6::ANY(::in6addr_any);

/*
 * vislib::net::IPAddress6::LOCALHOST
 */
const vislib::net::IPAddress6& vislib::net::IPAddress6::LOCALHOST
    = vislib::net::IPAddress6::LOOPBACK;

/*
 * vislib::net::IPAddress6::LOOPBACK
 */
const vislib::net::IPAddress6 vislib::net::IPAddress6::LOOPBACK(
    ::in6addr_loopback);

/*
 * vislib::net::IPAddress6::UNSPECIFIED
 */
const vislib::net::IPAddress6& vislib::net::IPAddress6::UNSPECIFIED
    = vislib::net::IPAddress6::ANY;

/*
 * vislib::net::IPAddress6::IPAddress6
 */
vislib::net::IPAddress6::IPAddress6(void) {
    *this = ::in6addr_loopback;
}

/*
 * vislib::net::IPAddress6::IPAddress6
 */
vislib::net::IPAddress6::IPAddress6(const struct in6_addr& address) {
    *this = address;
}

/*
 * vislib::net::IPAddress6::IPAddress6
 */
vislib::net::IPAddress6::IPAddress6(
        const BYTE b1, const BYTE b2, const BYTE b3, const BYTE b4,
        const BYTE b5, const BYTE b6, const BYTE b7, const BYTE b8,
        const BYTE b9, const BYTE b10, const BYTE b11, const BYTE b12,
        const BYTE b13, const BYTE b14, const BYTE b15, const BYTE b16) {
#define VLIPADDR5_INITBYTE(n) this->address.s6_addr[n - 1] = b##n
    VLIPADDR5_INITBYTE(1);
    VLIPADDR5_INITBYTE(2);
    VLIPADDR5_INITBYTE(3);
    VLIPADDR5_INITBYTE(4);
    VLIPADDR5_INITBYTE(5);
    VLIPADDR5_INITBYTE(6);
    VLIPADDR5_INITBYTE(7);
    VLIPADDR5_INITBYTE(8);
    VLIPADDR5_INITBYTE(9);
    VLIPADDR5_INITBYTE(10);
    VLIPADDR5_INITBYTE(11);
    VLIPADDR5_INITBYTE(12);
    VLIPADDR5_INITBYTE(13);
    VLIPADDR5_INITBYTE(14);
    VLIPADDR5_INITBYTE(15);
    VLIPADDR5_INITBYTE(16);
#undef VLIPADDR5_INITBYTE
}

/*
 * vislib::net::IPAddress6::IPAddress6
 */
vislib::net::IPAddress6::IPAddress6(const IPAddress& address) {
    this->MapV4Address(address);
}

/*
 * vislib::net::IPAddress6::IPAddress6
 */
vislib::net::IPAddress6::IPAddress6(const struct in_addr& address) {
    this->MapV4Address(address);
}

/*
 * vislib::net::IPAddress6::IPAddress6
 */
vislib::net::IPAddress6::IPAddress6(const IPAddress6& rhs) {
    *this = rhs;
}

/*
 * vislib::net::IPAddress6::~IPAddress6
 */
vislib::net::IPAddress6::~IPAddress6(void) {
}

/*
 * vislib::net::IPAddress6::GetPrefix
 */
vislib::net::IPAddress6
vislib::net::IPAddress6::GetPrefix(const ULONG prefixLength) const {
    IPAddress6 retval;
    int cntBytes = sizeof(retval.address.s6_addr);
    int cntPrefix = prefixLength > static_cast<ULONG>(8 * cntBytes)
        ? cntBytes : static_cast<int>(prefixLength);
    div_t cntCopy = ::div(cntPrefix, 8);

    /* Zero out everything. */
    ::ZeroMemory(retval.address.s6_addr, cntBytes);

    /* Copy complete bytes. */
    ::memcpy(retval.address.s6_addr, this->address.s6_addr, cntCopy.quot);

    /* Copy fraction of incomplete byte if necessary. */
    if (cntCopy.rem > 0) {
        retval.address.s6_addr[cntCopy.quot]
            = this->address.s6_addr[cntCopy.quot] << (8 - cntCopy.rem);
    }

    return retval;
}

/*
 * vislib::net::IPAddress6::MapV4Address
 */
void vislib::net::IPAddress6::MapV4Address(const struct in_addr& address) {
    /* Zero out first 80 bits. */
    for (int i = 0; i < 10; i++) {
        this->address.s6_addr[i] = 0;
    }

    /* Bits 80 to 95 must be all 1. */
    for (int i = 10; i < 12; i++) {
        this->address.s6_addr[i] = 0xff;
    }

    /* Embed IPv4 in the last 32 bits. */
    ASSERT(sizeof(in_addr) == 4);
    ::memcpy(this->address.s6_addr + 12, &address, sizeof(in_addr));

    ASSERT(this->IsV4Mapped());
}

/*
 * vislib::net::IPAddress6::ToStringA
 */
vislib::StringA vislib::net::IPAddress6::ToStringA(void) const {
    struct sockaddr_in6 addr;   // Dummy socket address used for lookup.
    char buffer[NI_MAXHOST];    // Receives the stringised address.
    int err = 0;                // OS operation return value.

    ::ZeroMemory(&addr, sizeof(addr));
    addr.sin6_family = AF_INET6;
    ::memcpy(&addr.sin6_addr, &this->address, sizeof(struct in6_addr));

    if ((err = ::getnameinfo(reinterpret_cast<struct sockaddr *>(&addr),
            sizeof(struct sockaddr_in6), buffer, sizeof(buffer), NULL, 0,
            NI_NUMERICHOST)) != 0) {
        VLTRACE(Trace::LEVEL_VL_ERROR, "::getnameinfo failed in "
            "IPAddress6::ToStringA(): %s\n",
#ifdef _WIN32
            ::gai_strerrorA(err)
#else /* _WIN32 */
            ::gai_strerror(err)
#endif /* _WIN32 */
        );
        buffer[0] = 0;
    }

    return StringA(buffer);
}

/*
 * vislib::net::IPAddress6::UnmapV4Address
 */
vislib::net::IPAddress vislib::net::IPAddress6::UnmapV4Address(void) const {
    if (this->IsV4Mapped()) {
        return IPAddress(*reinterpret_cast<const in_addr *>(
            this->address.s6_addr + 12));
    } else {
        throw IllegalStateException("The IPv6 address is not a mapped IPv4 "
            "address.", __FILE__, __LINE__);
    }
}

/*
 * vislib::net::IPAddress6::operator []
 */
BYTE vislib::net::IPAddress6::operator [](const int i) const {
    if ((i > 0) && (i < static_cast<int>(sizeof(this->address)))) {
        return reinterpret_cast<const BYTE *>(&this->address)[i];
    } else {
        throw OutOfRangeException(i, 0, sizeof(this->address), __FILE__,
            __LINE__);
    }
}

/*
 * vislib::net::IPAddress6::operator =
 */
vislib::net::IPAddress6& vislib::net::IPAddress6::operator =(
        const struct in6_addr& rhs) {
    if (&this->address != &rhs) {
        ::memcpy(&this->address, &rhs, sizeof(struct in6_addr));
    }

    return *this;
}

/*
 * vislib::net::IPAddress6::operator =
 */
vislib::net::IPAddress6& vislib::net::IPAddress6::operator =(
        const IPAddress& rhs) {
    this->MapV4Address(rhs);
    return *this;
}

/*
 * vislib::net::IPAddress6::operator ==
 */
bool vislib::net::IPAddress6::operator ==(const struct in6_addr& rhs) const {
#ifndef _WIN32
#define IN6_ADDR_EQUAL IN6_ARE_ADDR_EQUAL
#endif /* !_WIN32 */
    return (IN6_ADDR_EQUAL(&this->address, &rhs) != 0);
}

/*
 * vislib::net::IPAddress6::IPAddress
 */
vislib::net::IPAddress6::operator vislib::net::IPAddress(void) const {
    if (this->IsV4Compatible()) {
        return IPAddress(*reinterpret_cast<const in_addr *>(
            this->address.s6_addr + 12));
    } else {
        return this->UnmapV4Address();
    }
}
<|endoftext|>


<commit_before>/*! @file cell.cpp
    @brief Implementation of Cell class
*/
#include "cell.hpp"

#include <wtl/iostr.hpp>
#include <wtl/random.hpp>

#include <type_traits>

namespace tumopp {

static_assert(std::is_nothrow_copy_constructible<Cell>{}, "");
static_assert(std::is_nothrow_move_constructible<Cell>{}, "");
Cell::param_type Cell::PARAM_;

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////
namespace {

class GammaFactory {
  public:
    GammaFactory(double k) noexcept: shape_(k) {}
    std::gamma_distribution<double> operator()(double mu) {
        const double theta = std::max(mu / shape_, 0.0);
        return std::gamma_distribution<double>(shape_, theta);
    }
    void param(double k) {shape_ = k;}
  private:
    double shape_;
};

template <class URBG>
inline bool bernoulli(double p, URBG& engine) {
    // consume less URBG when p is set to 0 or 1.
    return p >= 1.0 || (p > 0.0 && wtl::generate_canonical(engine) < p);
}

class bernoulli_distribution {
  public:
    bernoulli_distribution(double p) noexcept: p_(p) {}
    template <class URBG>
    bool operator()(URBG& engine) const {
        return p_ >= 1.0 || (p_ > 0.0 && wtl::generate_canonical(engine) < p_);
    }
    void param(double p) {p_ = p;}
  private:
    double p_;
};

GammaFactory GAMMA_FACTORY(Cell::param().GAMMA_SHAPE);
bernoulli_distribution BERN_SYMMETRIC(Cell::param().PROB_SYMMETRIC_DIVISION);
bernoulli_distribution BERN_MUT_BIRTH(Cell::param().RATE_BIRTH);
bernoulli_distribution BERN_MUT_DEATH(Cell::param().RATE_DEATH);
bernoulli_distribution BERN_MUT_ALPHA(Cell::param().RATE_ALPHA);
bernoulli_distribution BERN_MUT_MIGRA(Cell::param().RATE_MIGRA);
std::normal_distribution<double> GAUSS_BIRTH(Cell::param().MEAN_BIRTH, Cell::param().SD_BIRTH);
std::normal_distribution<double> GAUSS_DEATH(Cell::param().MEAN_DEATH, Cell::param().SD_DEATH);
std::normal_distribution<double> GAUSS_ALPHA(Cell::param().MEAN_ALPHA, Cell::param().SD_ALPHA);
std::normal_distribution<double> GAUSS_MIGRA(Cell::param().MEAN_MIGRA, Cell::param().SD_MIGRA);

}// namespace
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////

void Cell::param(const param_type& p) {
    PARAM_ = p;
    GAMMA_FACTORY.param(PARAM_.GAMMA_SHAPE);
    BERN_SYMMETRIC.param(PARAM_.PROB_SYMMETRIC_DIVISION);
    BERN_MUT_BIRTH.param(PARAM_.RATE_BIRTH);
    BERN_MUT_DEATH.param(PARAM_.RATE_DEATH);
    BERN_MUT_ALPHA.param(PARAM_.RATE_ALPHA);
    BERN_MUT_MIGRA.param(PARAM_.RATE_MIGRA);
    GAUSS_BIRTH.param(decltype(GAUSS_BIRTH)::param_type(PARAM_.MEAN_BIRTH, PARAM_.SD_BIRTH));
    GAUSS_DEATH.param(decltype(GAUSS_DEATH)::param_type(PARAM_.MEAN_DEATH, PARAM_.SD_DEATH));
    GAUSS_ALPHA.param(decltype(GAUSS_ALPHA)::param_type(PARAM_.MEAN_ALPHA, PARAM_.SD_ALPHA));
    GAUSS_MIGRA.param(decltype(GAUSS_MIGRA)::param_type(PARAM_.MEAN_MIGRA, PARAM_.SD_MIGRA));
}

void Cell::differentiate(urbg_t& engine) {
    if (is_differentiated()) return;
    if (BERN_SYMMETRIC(engine)) return;
    proliferation_capacity_ = static_cast<int8_t>(PARAM_.MAX_PROLIFERATION_CAPACITY);
}

std::string Cell::mutate(urbg_t& engine) {
    auto oss = wtl::make_oss();
    if (BERN_MUT_BIRTH(engine)) {
        event_rates_ = std::make_shared<EventRates>(*event_rates_);
        double s = GAUSS_BIRTH(engine);
        oss << id_ << "\tbeta\t" << s << "\n";
        event_rates_->birth_rate *= (s += 1.0);
    }
    if (BERN_MUT_DEATH(engine)) {
        event_rates_ = std::make_shared<EventRates>(*event_rates_);
        double s = GAUSS_DEATH(engine);
        oss << id_ << "\tdelta\t" << s << "\n";
        event_rates_->death_rate *= (s += 1.0);
    }
    if (BERN_MUT_ALPHA(engine)) {
        event_rates_ = std::make_shared<EventRates>(*event_rates_);
        double s = GAUSS_ALPHA(engine);
        oss << id_ << "\talpha\t" << s << "\n";
        event_rates_->death_prob *= (s += 1.0);
    }
    if (BERN_MUT_MIGRA(engine)) {
        event_rates_ = std::make_shared<EventRates>(*event_rates_);
        double s = GAUSS_MIGRA(engine);
        oss << id_ << "\trho\t" << s << "\n";
        event_rates_->migra_rate *= (s += 1.0);
    }
    return oss.str();
}

std::string Cell::force_mutate(urbg_t& engine) {
    event_rates_ = std::make_shared<EventRates>(*event_rates_);
    const double s_birth = GAUSS_BIRTH(engine);
    const double s_death = GAUSS_DEATH(engine);
    const double s_alpha = GAUSS_ALPHA(engine);
    const double s_migra = GAUSS_MIGRA(engine);
    event_rates_->birth_rate *= (1.0 + s_birth);
    event_rates_->death_rate *= (1.0 + s_death);
    event_rates_->death_prob *= (1.0 + s_alpha);
    event_rates_->migra_rate *= (1.0 + s_migra);
    auto oss = wtl::make_oss();
    oss << id_ << "\tbeta\t" << s_birth << "\n"
        << id_ << "\tdelta\t" << s_death << "\n"
        << id_ << "\talpha\t" << s_alpha << "\n"
        << id_ << "\trho\t" << s_migra << "\n";
    return oss.str();
}

double Cell::delta_time(urbg_t& engine, const double now, const double positional_value, const bool surrounded) {
    double t_birth = std::numeric_limits<double>::infinity();
    double t_death = std::numeric_limits<double>::infinity();
    double t_migra = std::numeric_limits<double>::infinity();
    if (proliferation_capacity_ != 0) {
        double mu = 1.0;
        mu /= birth_rate();
        mu /= positional_value;
        if (!surrounded) mu -= (now - time_of_birth_);
        t_birth = GAMMA_FACTORY(mu)(engine);
    }
    if (death_rate() > 0.0) {
        std::exponential_distribution<double> exponential(death_rate());
        t_death = exponential(engine);
    }
    if (migra_rate() > 0.0) {
        std::exponential_distribution<double> exponential(migra_rate());
        t_migra = exponential(engine);
    }

    if (t_birth < t_death && t_birth < t_migra) {
        next_event_ = bernoulli(death_prob(), engine)
                      ? Event::death : Event::birth;
        return t_birth;
    } else if (t_death < t_migra) {
        next_event_ = Event::death;
        return t_death;
    } else {
        next_event_ = Event::migration;
        return t_migra;
    }
}

void Cell::set_cycle_dependent_death(urbg_t& engine, const double p) {
    //TODO: reduce redundant copy for susceptible cells
    event_rates_ = std::make_shared<EventRates>(*event_rates_);
    event_rates_->death_prob = p;
    next_event_ = bernoulli(p, engine) ? Event::death : Event::birth;
}

std::string Cell::header() {
    std::ostringstream oss;
    oss << "x\ty\tz\t"
        << "id\tancestor\t"
        << "birth\tdeath\t"
        << "omega";
    return oss.str();
}

std::ostream& Cell::write(std::ostream& ost) const {
    return ost
        << coord_[0] << "\t" << coord_[1] << "\t" << coord_[2] << "\t"
        << id_ << "\t"
        << (ancestor_ ? ancestor_->id_ : 0u) << "\t"
        << time_of_birth_ << "\t" << time_of_death_ << "\t"
        << static_cast<int>(proliferation_capacity_);
}

std::ostream& Cell::traceback(std::ostream& ost, std::unordered_set<unsigned>* done) const {
    write(ost) << "\n";
    if (ancestor_ && done->insert(ancestor_->id_).second) {
        ancestor_->traceback(ost, done);
    }
    return ost;
}

//! Stream operator for debug print
std::ostream& operator<< (std::ostream& ost, const Cell& x) {
    return x.write(ost);
}

} // namespace tumopp
<commit_msg>:art: Output only mutations with s>0 from force_mutate()<commit_after>/*! @file cell.cpp
    @brief Implementation of Cell class
*/
#include "cell.hpp"

#include <wtl/iostr.hpp>
#include <wtl/random.hpp>

#include <type_traits>

namespace tumopp {

static_assert(std::is_nothrow_copy_constructible<Cell>{}, "");
static_assert(std::is_nothrow_move_constructible<Cell>{}, "");
Cell::param_type Cell::PARAM_;

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////
namespace {

class GammaFactory {
  public:
    GammaFactory(double k) noexcept: shape_(k) {}
    std::gamma_distribution<double> operator()(double mu) {
        const double theta = std::max(mu / shape_, 0.0);
        return std::gamma_distribution<double>(shape_, theta);
    }
    void param(double k) {shape_ = k;}
  private:
    double shape_;
};

template <class URBG>
inline bool bernoulli(double p, URBG& engine) {
    // consume less URBG when p is set to 0 or 1.
    return p >= 1.0 || (p > 0.0 && wtl::generate_canonical(engine) < p);
}

class bernoulli_distribution {
  public:
    bernoulli_distribution(double p) noexcept: p_(p) {}
    template <class URBG>
    bool operator()(URBG& engine) const {
        return p_ >= 1.0 || (p_ > 0.0 && wtl::generate_canonical(engine) < p_);
    }
    void param(double p) {p_ = p;}
  private:
    double p_;
};

GammaFactory GAMMA_FACTORY(Cell::param().GAMMA_SHAPE);
bernoulli_distribution BERN_SYMMETRIC(Cell::param().PROB_SYMMETRIC_DIVISION);
bernoulli_distribution BERN_MUT_BIRTH(Cell::param().RATE_BIRTH);
bernoulli_distribution BERN_MUT_DEATH(Cell::param().RATE_DEATH);
bernoulli_distribution BERN_MUT_ALPHA(Cell::param().RATE_ALPHA);
bernoulli_distribution BERN_MUT_MIGRA(Cell::param().RATE_MIGRA);
std::normal_distribution<double> GAUSS_BIRTH(Cell::param().MEAN_BIRTH, Cell::param().SD_BIRTH);
std::normal_distribution<double> GAUSS_DEATH(Cell::param().MEAN_DEATH, Cell::param().SD_DEATH);
std::normal_distribution<double> GAUSS_ALPHA(Cell::param().MEAN_ALPHA, Cell::param().SD_ALPHA);
std::normal_distribution<double> GAUSS_MIGRA(Cell::param().MEAN_MIGRA, Cell::param().SD_MIGRA);

}// namespace
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////

void Cell::param(const param_type& p) {
    PARAM_ = p;
    GAMMA_FACTORY.param(PARAM_.GAMMA_SHAPE);
    BERN_SYMMETRIC.param(PARAM_.PROB_SYMMETRIC_DIVISION);
    BERN_MUT_BIRTH.param(PARAM_.RATE_BIRTH);
    BERN_MUT_DEATH.param(PARAM_.RATE_DEATH);
    BERN_MUT_ALPHA.param(PARAM_.RATE_ALPHA);
    BERN_MUT_MIGRA.param(PARAM_.RATE_MIGRA);
    GAUSS_BIRTH.param(decltype(GAUSS_BIRTH)::param_type(PARAM_.MEAN_BIRTH, PARAM_.SD_BIRTH));
    GAUSS_DEATH.param(decltype(GAUSS_DEATH)::param_type(PARAM_.MEAN_DEATH, PARAM_.SD_DEATH));
    GAUSS_ALPHA.param(decltype(GAUSS_ALPHA)::param_type(PARAM_.MEAN_ALPHA, PARAM_.SD_ALPHA));
    GAUSS_MIGRA.param(decltype(GAUSS_MIGRA)::param_type(PARAM_.MEAN_MIGRA, PARAM_.SD_MIGRA));
}

void Cell::differentiate(urbg_t& engine) {
    if (is_differentiated()) return;
    if (BERN_SYMMETRIC(engine)) return;
    proliferation_capacity_ = static_cast<int8_t>(PARAM_.MAX_PROLIFERATION_CAPACITY);
}

std::string Cell::mutate(urbg_t& engine) {
    auto oss = wtl::make_oss();
    if (BERN_MUT_BIRTH(engine)) {
        event_rates_ = std::make_shared<EventRates>(*event_rates_);
        double s = GAUSS_BIRTH(engine);
        oss << id_ << "\tbeta\t" << s << "\n";
        event_rates_->birth_rate *= (s += 1.0);
    }
    if (BERN_MUT_DEATH(engine)) {
        event_rates_ = std::make_shared<EventRates>(*event_rates_);
        double s = GAUSS_DEATH(engine);
        oss << id_ << "\tdelta\t" << s << "\n";
        event_rates_->death_rate *= (s += 1.0);
    }
    if (BERN_MUT_ALPHA(engine)) {
        event_rates_ = std::make_shared<EventRates>(*event_rates_);
        double s = GAUSS_ALPHA(engine);
        oss << id_ << "\talpha\t" << s << "\n";
        event_rates_->death_prob *= (s += 1.0);
    }
    if (BERN_MUT_MIGRA(engine)) {
        event_rates_ = std::make_shared<EventRates>(*event_rates_);
        double s = GAUSS_MIGRA(engine);
        oss << id_ << "\trho\t" << s << "\n";
        event_rates_->migra_rate *= (s += 1.0);
    }
    return oss.str();
}

std::string Cell::force_mutate(urbg_t& engine) {
    event_rates_ = std::make_shared<EventRates>(*event_rates_);
    const double s_birth = GAUSS_BIRTH(engine);
    const double s_death = GAUSS_DEATH(engine);
    const double s_alpha = GAUSS_ALPHA(engine);
    const double s_migra = GAUSS_MIGRA(engine);
    event_rates_->birth_rate *= (1.0 + s_birth);
    event_rates_->death_rate *= (1.0 + s_death);
    event_rates_->death_prob *= (1.0 + s_alpha);
    event_rates_->migra_rate *= (1.0 + s_migra);
    auto oss = wtl::make_oss();
    if (s_birth != 0.0) {oss << id_ << "\tbeta\t"  << s_birth << "\n";}
    if (s_death != 0.0) {oss << id_ << "\tdelta\t" << s_death << "\n";}
    if (s_alpha != 0.0) {oss << id_ << "\talpha\t" << s_alpha << "\n";}
    if (s_migra != 0.0) {oss << id_ << "\trho\t"   << s_migra << "\n";}
    return oss.str();
}

double Cell::delta_time(urbg_t& engine, const double now, const double positional_value, const bool surrounded) {
    double t_birth = std::numeric_limits<double>::infinity();
    double t_death = std::numeric_limits<double>::infinity();
    double t_migra = std::numeric_limits<double>::infinity();
    if (proliferation_capacity_ != 0) {
        double mu = 1.0;
        mu /= birth_rate();
        mu /= positional_value;
        if (!surrounded) mu -= (now - time_of_birth_);
        t_birth = GAMMA_FACTORY(mu)(engine);
    }
    if (death_rate() > 0.0) {
        std::exponential_distribution<double> exponential(death_rate());
        t_death = exponential(engine);
    }
    if (migra_rate() > 0.0) {
        std::exponential_distribution<double> exponential(migra_rate());
        t_migra = exponential(engine);
    }

    if (t_birth < t_death && t_birth < t_migra) {
        next_event_ = bernoulli(death_prob(), engine)
                      ? Event::death : Event::birth;
        return t_birth;
    } else if (t_death < t_migra) {
        next_event_ = Event::death;
        return t_death;
    } else {
        next_event_ = Event::migration;
        return t_migra;
    }
}

void Cell::set_cycle_dependent_death(urbg_t& engine, const double p) {
    //TODO: reduce redundant copy for susceptible cells
    event_rates_ = std::make_shared<EventRates>(*event_rates_);
    event_rates_->death_prob = p;
    next_event_ = bernoulli(p, engine) ? Event::death : Event::birth;
}

std::string Cell::header() {
    std::ostringstream oss;
    oss << "x\ty\tz\t"
        << "id\tancestor\t"
        << "birth\tdeath\t"
        << "omega";
    return oss.str();
}

std::ostream& Cell::write(std::ostream& ost) const {
    return ost
        << coord_[0] << "\t" << coord_[1] << "\t" << coord_[2] << "\t"
        << id_ << "\t"
        << (ancestor_ ? ancestor_->id_ : 0u) << "\t"
        << time_of_birth_ << "\t" << time_of_death_ << "\t"
        << static_cast<int>(proliferation_capacity_);
}

std::ostream& Cell::traceback(std::ostream& ost, std::unordered_set<unsigned>* done) const {
    write(ost) << "\n";
    if (ancestor_ && done->insert(ancestor_->id_).second) {
        ancestor_->traceback(ost, done);
    }
    return ost;
}

//! Stream operator for debug print
std::ostream& operator<< (std::ostream& ost, const Cell& x) {
    return x.write(ost);
}

} // namespace tumopp
<|endoftext|>


<commit_before>/* vim: set sw=4 sts=4 et foldmethod=syntax : */

#include <max_common_subgraph/algorithms.hh>
#include <max_clique/algorithms.hh>

#include <graph/degree_sort.hh>
#include <graph/min_width_sort.hh>

#include <boost/program_options.hpp>

#include <iostream>
#include <iomanip>
#include <exception>
#include <algorithm>
#include <random>
#include <thread>
#include <cstdlib>

using namespace parasols;
namespace po = boost::program_options;

using std::chrono::steady_clock;
using std::chrono::duration_cast;
using std::chrono::milliseconds;

auto algorithms = {
    MaxCliqueAlgorithm{ cco_max_clique<CCOPermutations::None, CCOInference::None> }
};

void table(int size1, int size2, int samples)
{
    using namespace std::placeholders;

    for (int p1 = 0 ; p1 <= 100 ; p1 += 1) {
        for (int p2 = 0 ; p2 <= 100 ; p2 += 1) {
            std::cout << p1 / 100.0 << " " << p2 / 100.0;

            for (auto & algorithm : algorithms) {
                double size_total = 0.0, nodes_total = 0.0, best_nodes_total = 0.0, first = 0.0, second = 0.0;

                for (int sample = 0 ; sample < samples ; ++sample) {
                    std::mt19937 rnd1, rnd2;
                    rnd1.seed(1234 + sample + (p1 * 2 * samples));
                    rnd2.seed(24681012 + sample + samples + (p2 * 2 * samples));
                    Graph graph1(size1, false), graph2(size2, false);

                    std::uniform_real_distribution<double> dist(0.0, 1.0);
                    for (int e = 0 ; e < size1 ; ++e)
                        for (int f = e + 1 ; f < size1 ; ++f)
                            if (dist(rnd1) <= (double(p1) / 100.0))
                                graph1.add_edge(e, f);

                    for (int e = 0 ; e < size2 ; ++e)
                        for (int f = e + 1 ; f < size2 ; ++f)
                            if (dist(rnd2) <= (double(p2) / 100.0))
                                graph2.add_edge(e, f);

                    MaxCommonSubgraphParams params;
                    params.max_clique_algorithm = algorithm;
                    params.order_function = std::bind(none_sort, _1, _2, false);
                    std::atomic<bool> abort;
                    abort.store(false);
                    params.abort = &abort;
                    params.start_time = steady_clock::now();

                    auto result1 = clique_max_common_subgraph(std::make_pair(graph1, graph2), params);
                    size_total += result1.size;
                    nodes_total += result1.nodes;

                    params.start_time = steady_clock::now();
                    auto result2 = clique_max_common_subgraph(std::make_pair(graph2, graph1), params);

                    if (result1.size != result2.size)
                        throw 0; /* oops... */

                    if (result1.nodes < result2.nodes) {
                        best_nodes_total += result1.nodes;
                        first += 1.0;
                    }
                    else if (result1.nodes == result2.nodes) {
                        best_nodes_total += result1.nodes;
                        first += 0.5;
                        second += 0.5;
                    }
                    else {
                        best_nodes_total += result2.nodes;
                        second += 1.0;
                    }
                }

                std::cout << " " << (size_total / samples) << " " <<
                    (nodes_total / samples) << " " << (best_nodes_total /
                            samples) << " " << first << " " << second;
            }

            std::cout << std::endl;
        }

        std::cout << std::endl;
    }
}

auto main(int argc, char * argv[]) -> int
{
    try {
        po::options_description display_options{ "Program options" };
        display_options.add_options()
            ("help",                 "Display help information")
            ;

        po::options_description all_options{ "All options" };
        all_options.add(display_options);

        all_options.add_options()
            ("size1",       po::value<int>(),                       "Size of first graph")
            ("size2",       po::value<int>(),                       "Size of second graph")
            ("samples",     po::value<int>(),                       "Sample size")
            ;

        po::positional_options_description positional_options;
        positional_options
            .add("size1",      1)
            .add("size2",      1)
            .add("samples",    1)
            ;

        po::variables_map options_vars;
        po::store(po::command_line_parser(argc, argv)
                .options(all_options)
                .positional(positional_options)
                .run(), options_vars);
        po::notify(options_vars);

        /* --help? Show a message, and exit. */
        if (options_vars.count("help")) {
            std::cout << "Usage: " << argv[0] << " [options] size1 size2 samples" << std::endl;
            std::cout << std::endl;
            std::cout << display_options << std::endl;
            return EXIT_SUCCESS;
        }

        /* No values specified? Show a message and exit. */
        if (! options_vars.count("size1") || ! options_vars.count("size2") || ! options_vars.count("samples")) {
            std::cout << "Usage: " << argv[0] << " [options] size1 size2 samples" << std::endl;
            return EXIT_FAILURE;
        }

        int size1 = options_vars["size1"].as<int>();
        int size2 = options_vars["size2"].as<int>();
        int samples = options_vars["samples"].as<int>();

        table(size1, size2, samples);

        return EXIT_SUCCESS;
    }
    catch (const po::error & e) {
        std::cerr << "Error: " << e.what() << std::endl;
        std::cerr << "Try " << argv[0] << " --help" << std::endl;
        return EXIT_FAILURE;
    }
    catch (const std::exception & e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return EXIT_FAILURE;
    }
}

<commit_msg>Order as a parameter<commit_after>/* vim: set sw=4 sts=4 et foldmethod=syntax : */

#include <max_common_subgraph/algorithms.hh>
#include <max_clique/algorithms.hh>

#include <graph/orders.hh>

#include <boost/program_options.hpp>

#include <iostream>
#include <iomanip>
#include <exception>
#include <algorithm>
#include <random>
#include <thread>
#include <cstdlib>

using namespace parasols;
namespace po = boost::program_options;

using std::chrono::steady_clock;
using std::chrono::duration_cast;
using std::chrono::milliseconds;

auto algorithms = {
    MaxCliqueAlgorithm{ cco_max_clique<CCOPermutations::None, CCOInference::None> }
};

void table(int size1, int size2, int samples, const MaxCliqueOrderFunction & order_function)
{
    using namespace std::placeholders;

    for (int p1 = 0 ; p1 <= 100 ; p1 += 1) {
        for (int p2 = 0 ; p2 <= 100 ; p2 += 1) {
            std::cout << p1 / 100.0 << " " << p2 / 100.0;

            for (auto & algorithm : algorithms) {
                double size_total = 0.0, nodes_total = 0.0, best_nodes_total = 0.0, first = 0.0, second = 0.0;

                for (int sample = 0 ; sample < samples ; ++sample) {
                    std::mt19937 rnd1, rnd2;
                    rnd1.seed(1234 + sample + (p1 * 2 * samples));
                    rnd2.seed(24681012 + sample + samples + (p2 * 2 * samples));
                    Graph graph1(size1, false), graph2(size2, false);

                    std::uniform_real_distribution<double> dist(0.0, 1.0);
                    for (int e = 0 ; e < size1 ; ++e)
                        for (int f = e + 1 ; f < size1 ; ++f)
                            if (dist(rnd1) <= (double(p1) / 100.0))
                                graph1.add_edge(e, f);

                    for (int e = 0 ; e < size2 ; ++e)
                        for (int f = e + 1 ; f < size2 ; ++f)
                            if (dist(rnd2) <= (double(p2) / 100.0))
                                graph2.add_edge(e, f);

                    MaxCommonSubgraphParams params;
                    params.max_clique_algorithm = algorithm;
                    params.order_function = order_function;
                    std::atomic<bool> abort;
                    abort.store(false);
                    params.abort = &abort;
                    params.start_time = steady_clock::now();

                    auto result1 = clique_max_common_subgraph(std::make_pair(graph1, graph2), params);
                    size_total += result1.size;
                    nodes_total += result1.nodes;

                    params.start_time = steady_clock::now();
                    auto result2 = clique_max_common_subgraph(std::make_pair(graph2, graph1), params);

                    if (result1.size != result2.size)
                        throw 0; /* oops... */

                    if (result1.nodes < result2.nodes) {
                        best_nodes_total += result1.nodes;
                        first += 1.0;
                    }
                    else if (result1.nodes == result2.nodes) {
                        best_nodes_total += result1.nodes;
                        first += 0.5;
                        second += 0.5;
                    }
                    else {
                        best_nodes_total += result2.nodes;
                        second += 1.0;
                    }
                }

                std::cout << " " << (size_total / samples) << " " <<
                    (nodes_total / samples) << " " << (best_nodes_total /
                            samples) << " " << first << " " << second;
            }

            std::cout << std::endl;
        }

        std::cout << std::endl;
    }
}

auto main(int argc, char * argv[]) -> int
{
    try {
        po::options_description display_options{ "Program options" };
        display_options.add_options()
            ("help",                 "Display help information")
            ;

        po::options_description all_options{ "All options" };
        all_options.add(display_options);

        all_options.add_options()
            ("size1",       po::value<int>(),                       "Size of first graph")
            ("size2",       po::value<int>(),                       "Size of second graph")
            ("samples",     po::value<int>(),                       "Sample size")
            ("order",      "Specify the initial vertex order")
            ;

        po::positional_options_description positional_options;
        positional_options
            .add("size1",      1)
            .add("size2",      1)
            .add("samples",    1)
            .add("order",      1)
            ;

        po::variables_map options_vars;
        po::store(po::command_line_parser(argc, argv)
                .options(all_options)
                .positional(positional_options)
                .run(), options_vars);
        po::notify(options_vars);

        /* --help? Show a message, and exit. */
        if (options_vars.count("help")) {
            std::cout << "Usage: " << argv[0] << " [options] size1 size2 samples order" << std::endl;
            std::cout << std::endl;
            std::cout << display_options << std::endl;
            return EXIT_SUCCESS;
        }

        /* No values specified? Show a message and exit. */
        if (! options_vars.count("size1") || ! options_vars.count("size2") || ! options_vars.count("samples")
                || ! options_vars.count("order")) {
            std::cout << "Usage: " << argv[0] << " [options] size1 size2 samples order" << std::endl;
            return EXIT_FAILURE;
        }

        int size1 = options_vars["size1"].as<int>();
        int size2 = options_vars["size2"].as<int>();
        int samples = options_vars["samples"].as<int>();

        /* Turn an order string name into a runnable function. */
        MaxCliqueOrderFunction order_function;
        for (auto order = orders.begin() ; order != orders.end() ; ++order)
            if (std::get<0>(*order) == options_vars["order"].as<std::string>()) {
                order_function = std::get<1>(*order);
                break;
            }

        /* Unknown algorithm? Show a message and exit. */
        if (! order_function) {
            std::cerr << "Unknown order " << options_vars["order"].as<std::string>() << ", choose from:";
            for (auto a : orders)
                std::cerr << " " << std::get<0>(a);
            std::cerr << std::endl;
            return EXIT_FAILURE;
        }

        table(size1, size2, samples, order_function);

        return EXIT_SUCCESS;
    }
    catch (const po::error & e) {
        std::cerr << "Error: " << e.what() << std::endl;
        std::cerr << "Try " << argv[0] << " --help" << std::endl;
        return EXIT_FAILURE;
    }
    catch (const std::exception & e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return EXIT_FAILURE;
    }
}

<|endoftext|>