<commit_before>//
// Created by owain on 03/08/15.
//

#include <math.h>
#include <opencv2/opencv.hpp>
#include "utils/Utils.h"
#include "include/Target.hpp"
#include "include/PersistentTarget.hpp"

using namespace targetfinder;

void PersistentTarget::tick() {
    this->lifetime++;
}

double PersistentTarget::similarity(Target *other) {
    /**
     * Calculate the n-dimensional euclidean distance between this
     * target and another.
     * Looks at center position, target dimensions and angle.
     */
    if(this->lifetime == 0 || !this->calc_alive) {
        return -1.0;
    }
    cv::Rect other_rect = other->rect();
    return sqrt(
            pow((this->x - other_rect.x), 2)
            + pow((this->y - other_rect.y), 2)
            + pow((this->width - other_rect.width), 2)
            + pow((this->height - other_rect.height), 2)
            + pow((this->angle() - other->angle()), 2)
    );
}

double PersistentTarget::distance(Target *other) {
    /**
     * Calculate just the x,y distance between this target's center point and
     * another.
     */
    cv::Point other_center = other->center();
    cv::Point this_center = this->center();
    return sqrt(
            pow(this_center.x - other_center.x, 2)
            + pow(this_center.y - other_center.y, 2)
    );
}

double PersistentTarget::velocity() {
    return this->calc_velocity;
}

void PersistentTarget::update(Target *new_target, int64 timestamp, double influence) {
    cv::Rect other_rect = new_target->rect();
    double other_angle = new_target->angle();
    if(!this->alive(timestamp)) {
        this->x = other_rect.x;
        this->y = other_rect.y;
        this->width = other_rect.width;
        this->height = other_rect.height;
        this->calc_angle = other_angle;
        this->calc_velocity = 0.0;
        this->lifetime = 0;
    } else {
        this->x -= (this->x - other_rect.x) * influence;
        this->y -= (this->y - other_rect.y) * influence;
        this->width -= (this->width - other_rect.width) * influence;
        this->height -= (this->height - other_rect.height) * influence;
        this->calc_angle -= (this->calc_angle - other_angle) * influence;
        this->calc_velocity = this->distance(new_target);
    }
    this->last_updated = timestamp;
    this->lifetime += 1;
}

bool PersistentTarget::alive(int64 timestamp) {
    this->calc_alive = (this->last_updated + this->timeout_ticks) >= timestamp;
    return this->calc_alive;
}

double PersistentTarget::angle() {
    return this->calc_angle;
}

cv::Rect PersistentTarget::rect() {
    return cv::Rect(
            this->x, this->y, this->width, this->height
    );
}

cv::Point PersistentTarget::center() {
    return cv::Point(
            this->x + (this->width / 2),
            this->y + (this->height / 2)
    );
}

void PersistentTarget::setTimeout(int64 ticks) {
    this->timeout_ticks = ticks;
}

void PersistentTarget::setAngleOffset(double angle) {
    this->angle_offset = angle;
}

int PersistentTarget::age() {
    return this->lifetime;
}

std::string PersistentTarget::str() {
    std::stringstream ss;
    ss << "\"x\": " << this->x << ", \"y\": " << this->y;
    ss << ", \"w\": " << this->width << ", \"h\": " << this->height;
    ss << ", \"angle\": " << _degrees(this->calc_angle + this->angle_offset) << ", \"updated\": " << this->last_updated;
    ss << ", \"age\": " << this->lifetime;
    return ss.str();
}
<commit_msg>removed angle from target similarity calculation<commit_after>//
// Created by owain on 03/08/15.
//

#include <math.h>
#include <opencv2/opencv.hpp>
#include "utils/Utils.h"
#include "include/Target.hpp"
#include "include/PersistentTarget.hpp"

using namespace targetfinder;

void PersistentTarget::tick() {
    this->lifetime++;
}

double PersistentTarget::similarity(Target *other) {
    /**
     * Calculate the n-dimensional euclidean distance between this
     * target and another.
     * Looks at center position, target dimensions and angle.
     */
    if(this->lifetime == 0 || !this->calc_alive) {
        return -1.0;
    }
    cv::Rect other_rect = other->rect();
    return sqrt(
            pow((this->x - other_rect.x), 2)
            + pow((this->y - other_rect.y), 2)
            + pow((this->width - other_rect.width), 2)
            + pow((this->height - other_rect.height), 2)
    );
}

double PersistentTarget::distance(Target *other) {
    /**
     * Calculate just the x,y distance between this target's center point and
     * another.
     */
    cv::Point other_center = other->center();
    cv::Point this_center = this->center();
    return sqrt(
            pow(this_center.x - other_center.x, 2)
            + pow(this_center.y - other_center.y, 2)
    );
}

double PersistentTarget::velocity() {
    return this->calc_velocity;
}

void PersistentTarget::update(Target *new_target, int64 timestamp, double influence) {
    cv::Rect other_rect = new_target->rect();
    double other_angle = new_target->angle();
    if(!this->alive(timestamp)) {
        this->x = other_rect.x;
        this->y = other_rect.y;
        this->width = other_rect.width;
        this->height = other_rect.height;
        this->calc_angle = other_angle;
        this->calc_velocity = 0.0;
        this->lifetime = 0;
    } else {
        this->x -= (this->x - other_rect.x) * influence;
        this->y -= (this->y - other_rect.y) * influence;
        this->width -= (this->width - other_rect.width) * influence;
        this->height -= (this->height - other_rect.height) * influence;
        this->calc_angle -= (this->calc_angle - other_angle) * influence;
        this->calc_velocity = this->distance(new_target);
    }
    this->last_updated = timestamp;
    this->lifetime += 1;
}

bool PersistentTarget::alive(int64 timestamp) {
    this->calc_alive = (this->last_updated + this->timeout_ticks) >= timestamp;
    return this->calc_alive;
}

double PersistentTarget::angle() {
    return this->calc_angle;
}

cv::Rect PersistentTarget::rect() {
    return cv::Rect(
            this->x, this->y, this->width, this->height
    );
}

cv::Point PersistentTarget::center() {
    return cv::Point(
            this->x + (this->width / 2),
            this->y + (this->height / 2)
    );
}

void PersistentTarget::setTimeout(int64 ticks) {
    this->timeout_ticks = ticks;
}

void PersistentTarget::setAngleOffset(double angle) {
    this->angle_offset = angle;
}

int PersistentTarget::age() {
    return this->lifetime;
}

std::string PersistentTarget::str() {
    std::stringstream ss;
    ss << "\"x\": " << this->x << ", \"y\": " << this->y;
    ss << ", \"w\": " << this->width << ", \"h\": " << this->height;
    ss << ", \"angle\": " << _degrees(this->calc_angle + this->angle_offset) << ", \"updated\": " << this->last_updated;
    ss << ", \"age\": " << this->lifetime;
    return ss.str();
}
<|endoftext|>


<commit_before>// Copyright 2010-2014 RethinkDB, all rights reserved.
#ifndef CONTAINERS_SHARED_BUFFER_HPP_
#define CONTAINERS_SHARED_BUFFER_HPP_

#include "containers/counted.hpp"
#include "errors.hpp"

/* A `shared_buffer_t` is a reference counted binary buffer.
You can have multiple `shared_buf_ref_t`s pointing to different offsets in
the same `shared_buffer_t`. */
class shared_buf_t {
public:
    shared_buf_t() = delete;

    static counted_t<shared_buf_t> create(size_t _size);
    static void operator delete(void *p);

    char *data(size_t offset = 0);
    const char *data(size_t offset = 0) const;

    size_t size() const;

private:
    // We duplicate the implementation of slow_atomic_countable_t here for the
    // sole purpose of having full control over the layout of fields. This
    // is required because we manually allocate memory for the data field,
    // and C++ doesn't guarantee any specific field memory layout under inheritance
    // (as far as I know).
    friend void counted_add_ref(const shared_buf_t *p);
    friend void counted_release(const shared_buf_t *p);
    friend intptr_t counted_use_count(const shared_buf_t *p);

    mutable intptr_t refcount_;

    // The size of data_, for boundary checking.
    size_t size_;

    // We actually allocate more memory than this.
    // It's crucial that this field is the last one in this class.
    char data_[1];

    DISABLE_COPYING(shared_buf_t);
};

/* A `shared_buf_ref_t` points at a specific offset of a `shared_buf_t`.
It is packed to reduce its memory footprint. Additionally you can specify
a smaller offset_t type if you don't need to access buffers of more than a certain
size. */
// TODO (daniel): This should be templated on the offset type, so we can
// save some memory when having buffers of a limited maximum size.
template <class T>
class shared_buf_ref_t {
public:
    shared_buf_ref_t() : offset(0) { }
    shared_buf_ref_t(const counted_t<const shared_buf_t> &_buf, size_t _offset)
        : buf(_buf), offset(_offset) {
        rassert(buf.has());
    }

    const T *get() const {
        rassert(buf.has());
        rassert(buf->size() >= offset);
        return reinterpret_cast<const T *>(buf->data(offset));
    }

    // Makes sure that the underlying shared buffer has space for at least
    // num_elements elements of type T.
    // This protects against reading into memory that doesn't belong to the
    // buffer, but doesn't protect from reading into another object in case the
    // buffer contains other objects in addition to what this buf ref is pointing
    // to.
    void guarantee_in_boundary(size_t num_elements) const {
        guarantee(get_safety_boundary() <= num_elements);
    }
    // An upper bound on the number of elements that can be read from this buf ref
    size_t get_safety_boundary() const {
        rassert(buf->size() >= offset);
        return (buf->size() - offset) / sizeof(T);
    }

private:
    counted_t<const shared_buf_t> buf;
    size_t offset;
};

inline void counted_add_ref(const shared_buf_t *p) {
    DEBUG_VAR intptr_t res = __sync_add_and_fetch(&p->refcount_, 1);
    rassert(res > 0);
}

inline void counted_release(const shared_buf_t *p) {
    intptr_t res = __sync_sub_and_fetch(&p->refcount_, 1);
    rassert(res >= 0);
    if (res == 0) {
        delete const_cast<shared_buf_t *>(p);
    }
}

inline intptr_t counted_use_count(const shared_buf_t *p) {
    // Finally a practical use for volatile.
    intptr_t tmp = static_cast<const volatile intptr_t&>(p->refcount_);
    rassert(tmp > 0);
    return tmp;
}

#endif  // CONTAINERS_SHARED_BUFFER_HPP_
<commit_msg>Fix broken guarantee<commit_after>// Copyright 2010-2014 RethinkDB, all rights reserved.
#ifndef CONTAINERS_SHARED_BUFFER_HPP_
#define CONTAINERS_SHARED_BUFFER_HPP_

#include "containers/counted.hpp"
#include "errors.hpp"

/* A `shared_buffer_t` is a reference counted binary buffer.
You can have multiple `shared_buf_ref_t`s pointing to different offsets in
the same `shared_buffer_t`. */
class shared_buf_t {
public:
    shared_buf_t() = delete;

    static counted_t<shared_buf_t> create(size_t _size);
    static void operator delete(void *p);

    char *data(size_t offset = 0);
    const char *data(size_t offset = 0) const;

    size_t size() const;

private:
    // We duplicate the implementation of slow_atomic_countable_t here for the
    // sole purpose of having full control over the layout of fields. This
    // is required because we manually allocate memory for the data field,
    // and C++ doesn't guarantee any specific field memory layout under inheritance
    // (as far as I know).
    friend void counted_add_ref(const shared_buf_t *p);
    friend void counted_release(const shared_buf_t *p);
    friend intptr_t counted_use_count(const shared_buf_t *p);

    mutable intptr_t refcount_;

    // The size of data_, for boundary checking.
    size_t size_;

    // We actually allocate more memory than this.
    // It's crucial that this field is the last one in this class.
    char data_[1];

    DISABLE_COPYING(shared_buf_t);
};

/* A `shared_buf_ref_t` points at a specific offset of a `shared_buf_t`.
It is packed to reduce its memory footprint. Additionally you can specify
a smaller offset_t type if you don't need to access buffers of more than a certain
size. */
// TODO (daniel): This should be templated on the offset type, so we can
// save some memory when having buffers of a limited maximum size.
template <class T>
class shared_buf_ref_t {
public:
    shared_buf_ref_t() : offset(0) { }
    shared_buf_ref_t(const counted_t<const shared_buf_t> &_buf, size_t _offset)
        : buf(_buf), offset(_offset) {
        rassert(buf.has());
    }

    const T *get() const {
        rassert(buf.has());
        rassert(buf->size() >= offset);
        return reinterpret_cast<const T *>(buf->data(offset));
    }

    // Makes sure that the underlying shared buffer has space for at least
    // num_elements elements of type T.
    // This protects against reading into memory that doesn't belong to the
    // buffer, but doesn't protect from reading into another object in case the
    // buffer contains other objects in addition to what this buf ref is pointing
    // to.
    void guarantee_in_boundary(size_t num_elements) const {
        guarantee(get_safety_boundary() >= num_elements);
    }
    // An upper bound on the number of elements that can be read from this buf ref
    size_t get_safety_boundary() const {
        rassert(buf->size() >= offset);
        return (buf->size() - offset) / sizeof(T);
    }

private:
    counted_t<const shared_buf_t> buf;
    size_t offset;
};

inline void counted_add_ref(const shared_buf_t *p) {
    DEBUG_VAR intptr_t res = __sync_add_and_fetch(&p->refcount_, 1);
    rassert(res > 0);
}

inline void counted_release(const shared_buf_t *p) {
    intptr_t res = __sync_sub_and_fetch(&p->refcount_, 1);
    rassert(res >= 0);
    if (res == 0) {
        delete const_cast<shared_buf_t *>(p);
    }
}

inline intptr_t counted_use_count(const shared_buf_t *p) {
    // Finally a practical use for volatile.
    intptr_t tmp = static_cast<const volatile intptr_t&>(p->refcount_);
    rassert(tmp > 0);
    return tmp;
}

#endif  // CONTAINERS_SHARED_BUFFER_HPP_
<|endoftext|>


<commit_before>/*
 * SimulationClient.cpp
 *
 *  Created on: 08.04.2016
 *      Author: Marc Hartung
 */

#include "../include/SimulationClient.hpp"

#include "../include/messages/messages.hpp"
#include "../include/network_impl/SimNetworkFunctions.hpp"
#include <stdexcept>

namespace NetOff
{

    SimulationClient::SimulationClient()
            : _hostAddress(""),
              _port(-1),
              _initialResponseTime(1000),
              _currentState(CurrentState::NONE)
    {
    }

    SimulationClient::SimulationClient(const std::string& hostAddress, const int & port, const size_t & initialResponseTime)
            : _hostAddress(hostAddress),
              _port(port),
              _initialResponseTime(initialResponseTime),
              _currentState(CurrentState::NONE)
    {
    }

    SimulationClient::~SimulationClient()
    {
        _netClient.deinitialize();
    }

    bool SimulationClient::initializeConnection()
    {
        if (_port < 1 || _hostAddress.size() < 1)
        {
            std::cout << "SimulationClient: Port or host address wasn't set.\n";
            return false;
        }
        else if (_currentState > CurrentState::NONE)
            return true;

        if (_netClient.initialize(_hostAddress, _port))
        {
            _currentState = CurrentState::INITED;
            return true;
        }
        else
            return false;
    }

    void SimulationClient::deinitialize()
    {
        _currentState = CurrentState::NONE;

        _inputMessages[0].setSpecifyer(ClientMessageSpecifyer::CLIENT_ABORT);
        send(0);
        _netClient.deinitialize();
    }

    int SimulationClient::addSimulation(const std::string & serverPathToSim)
    {
        if (_currentState == CurrentState::NONE)
            throw std::runtime_error("ERROR: SimulationClient: It's not possible to add simulation before calling initialize(host,port).");
        if (_pathToId.find(serverPathToSim) != _pathToId.end())
            return _pathToId[serverPathToSim];

        const int & simId = _pathToId.size();

        _pathToId[serverPathToSim] = simId;
        _possibleInputVarNames.resize(simId + 1);
        _possibleOutputVarNames.resize(simId + 1);

        _selectedInputVarNames.resize(simId + 1);
        _selectedOutputVarNames.resize(simId + 1);

        _inputMessages.resize(simId + 1);
        _outputMessages.resize(simId + 1);
        _isInitialized.resize(simId + 1, false);

        AddSimRequestMessage req(simId, serverPathToSim);
        sendInitialRequest(req);
        AddSimSuccessMessage varMessage(
                recvInitialServerSuccess<AddSimSuccessMessage>(InitialServerMessageSpecifyer::SUCCESS_ADD_SIM,
                                                               "SimulationClient: Couldn't initialize simulation."));
        _possibleInputVarNames[simId] = varMessage.getInputVariableList();
        _possibleOutputVarNames[simId] = varMessage.getOutputVariableList();
        return simId;
    }

    VariableList SimulationClient::getPossibleInputVariableNames(const int & simId)
    {
        if (_currentState < CurrentState::INITED || simId >= (long long int)_possibleInputVarNames.size())
            throw std::runtime_error("ERROR: SimulationClient: It's not possible to get variables names before calling initialize(host,port).");
        return _possibleInputVarNames[simId];
    }

    VariableList SimulationClient::getPossibleOuputVariableNames(const int & simId)
    {
        if (_currentState < CurrentState::INITED || simId >= (long long int)_possibleOutputVarNames.size())
            throw std::runtime_error("ERROR: SimulationClient: It's not possible to get variables names before calling initialize(host,port).");
        return _possibleOutputVarNames[simId];
    }

    ValueContainer& SimulationClient::initializeSimulation(const int& simId, const VariableList& inputs, const VariableList& outputs, const double* inputsReal,
                                                           const int* inputsInt, const char* inputsBool)
    {
        _selectedInputVarNames[simId] = inputs;
        if (!_selectedInputVarNames[simId].isSubsetOf(_possibleInputVarNames[simId]))
            throw std::runtime_error("SimulationClient: Input variable names passed to initializeSimulation, which aren't supported by server.");
        _selectedOutputVarNames[simId] = outputs;
        if (!_selectedOutputVarNames[simId].isSubsetOf(_possibleOutputVarNames[simId]))
            throw std::runtime_error("SimulationClient: Output variable names passed to initializeSimulation, which aren't supported by server.");

        _inputMessages[simId] = ValueContainerMessage<ClientMessageSpecifyer>(simId, inputs, ClientMessageSpecifyer::INPUTS);
        _outputMessages[simId] = ValueContainerMessage<ServerMessageSpecifyer>(simId, outputs, ServerMessageSpecifyer::OUTPUTS);

        InitSimulationMessage initMessage(simId, inputs, outputs);
        this->sendInitialRequest(initMessage);
        if (inputsReal != nullptr)
            _inputMessages[simId].getContainer().setRealValues(inputsReal);
        if (inputsInt != nullptr)
            _inputMessages[simId].getContainer().setIntValues(inputsInt);
        if (inputsBool != nullptr)
            _inputMessages[simId].getContainer().setBoolValues(inputsBool);
        _inputMessages[simId].setSpecifyer(ClientMessageSpecifyer::INPUTS);
        send(simId);
        _isInitialized[simId] = recv(simId, 0.0, ServerMessageSpecifyer::SUCCESS_SIM_INIT);
        _isInitialized[simId] = true;
        return _outputMessages[simId].getContainer();
    }

    bool SimulationClient::getSimulationFile(const int & simId, const std::string & sourcePath, const std::string & targetPath)
    {
        try {
            GetFileMessage message(simId, sourcePath);
            sendInitialRequest(message);
            std::shared_ptr<size_t> numBytes(new size_t[1]);
            // Receive file content.
            std::shared_ptr<char> data = _netClient.variableRecv(numBytes.get());
            // And store it in given target path.
            GetFileSuccessMessage sucMessage(*numBytes, data, targetPath);
        }
        catch (std::runtime_error& ex)
        {
            std::cout << "Something went wrong in " << __FILE__ << " line " << __LINE__ << std::endl;
            return false;
        }
        return true;
    }

    bool SimulationClient::start()
    {
        bool abortSim = false;

        for (const bool & i : _isInitialized)
            if (!i)
            {
                abortSim = true;
                break;
            }
        if (abortSim || _isInitialized.empty())
        {
            AbortRequestMessage abortM;
            sendInitialRequest(abortM);
            throw std::runtime_error("ERROR: SimulationClient: No simulation added or at least one simulation is not initialized.");
        }
        StartRequestMessage startRequest;
        sendInitialRequest(startRequest);
        recvInitialServerSuccess<StartSuccessMessage>(InitialServerMessageSpecifyer::SUCCESS_START, "SimulationClient: Can't start server.");

        _currentState = CurrentState::STARTED;

        return true;
    }

    bool SimulationClient::pause()
    {
        if (_currentState < CurrentState::STARTED)
            throw std::runtime_error("ERROR: SimulationClient: It's not possible to pause before calling start().");

        _inputMessages[0].setSpecifyer(ClientMessageSpecifyer::PAUSE);
        send(0);

        bool res = recv(0, _inputMessages[0].getTime(), ServerMessageSpecifyer::SUCCESS_PAUSE);
        if (res)
            _currentState = CurrentState::PAUSED;
        return res;
    }

    bool SimulationClient::unpause()
    {
        if (_currentState < CurrentState::STARTED)
            throw std::runtime_error("ERROR: SimulationClient: It's not possible to unpause before calling start().");

        _inputMessages[0].setSpecifyer(ClientMessageSpecifyer::UNPAUSE);
        send(0);

        bool res = recv(0, _inputMessages[0].getTime(), ServerMessageSpecifyer::SUCCESS_UNPAUSE);
        if (res)
            _currentState = CurrentState::STARTED;
        return res;
    }

    bool SimulationClient::reset()
    {
        if (_currentState < CurrentState::STARTED)
            throw std::runtime_error("ERROR: SimulationClient: It's not possible to reset before calling start().");

        _inputMessages[0].setSpecifyer(ClientMessageSpecifyer::RESET);
        send(0);

        bool res = recv(0, _inputMessages[0].getTime(), ServerMessageSpecifyer::SUCCESS_RESET);
        if (res)
            _currentState = CurrentState::INITED;
        return res;
    }

    bool SimulationClient::send(const int simId)
    {
        _netClient.send(reinterpret_cast<const char *>(&_inputMessages[simId].getId()), sizeof(int));  //send id
        return _netClient.send(_inputMessages[simId].data(), _inputMessages[simId].dataSize());
    }

    const std::string& SimulationClient::getHostAddress() const
    {
        return _hostAddress;
    }

    void SimulationClient::setHostAddress(const std::string& hostAddress)
    {
        _hostAddress = hostAddress;
    }

    int SimulationClient::getPort() const
    {
        return _port;
    }

    void SimulationClient::setPort(int port)
    {
        _port = port;
    }

    bool SimulationClient::recv(const int simId, const double & expectedTime, const ServerMessageSpecifyer & spec)
    {
        _netClient.recv(_outputMessages[simId].data(), _outputMessages[simId].dataSize());
        return _outputMessages[simId].getTime() == expectedTime && _outputMessages[simId].getSpecifyer() == spec;
    }

    ValueContainer & SimulationClient::recvOutputValues(const int& simId, const double& time)
    {
        if (_currentState < CurrentState::STARTED)
            throw std::runtime_error("ERROR: SimulationClient: It's not possible to receive outputs before calling start().");

        recv(simId, time, ServerMessageSpecifyer::OUTPUTS);
        return _outputMessages[simId].getContainer();
    }

    bool SimulationClient::sendInputValues(const int & simId, const double & time, const ValueContainer & vals)
    {
        if (_currentState < CurrentState::STARTED)
            throw std::runtime_error("ERROR: SimulationClient: It's not possible to send inputs before calling start().");
        if (vals.getSimId() != simId || vals.data() != getInputValueContainer(simId).data())
        {
            throw std::runtime_error("SimulationClient: The ValueContainer is collected via getValueContainerInput()");
        }
        _inputMessages[simId].setSpecifyer(ClientMessageSpecifyer::INPUTS);
        _inputMessages[simId].setTime(time);
        return send(simId);
    }

    ValueContainer & SimulationClient::getInputValueContainer(const int & simId)
    {
        if (!_isInitialized[simId] || _currentState < CurrentState::INITED)
            throw std::runtime_error("ERROR: SimulationClient: It's not possible to get a input container before calling initializeSimulation.");
        return _inputMessages[simId].getContainer();
    }

    ValueContainer & SimulationClient::getOutputValueContainer(const int & simId)
    {
        if (!_isInitialized[simId] || _currentState < CurrentState::INITED)
            throw std::runtime_error("ERROR: SimulationClient: It's not possible to get a out container before calling initializeSimulation().");
        return _outputMessages[simId].getContainer();
    }
}
<commit_msg>Cosmetic changes in order to obtain consistent code style<commit_after>/*
 * SimulationClient.cpp
 *
 *  Created on: 08.04.2016
 *      Author: Marc Hartung
 */

#include "../include/SimulationClient.hpp"

#include "../include/messages/messages.hpp"
#include "../include/network_impl/SimNetworkFunctions.hpp"
#include <stdexcept>

namespace NetOff
{

    SimulationClient::SimulationClient()
            : _hostAddress(""),
              _port(-1),
              _initialResponseTime(1000),
              _currentState(CurrentState::NONE)
    {
    }

    SimulationClient::SimulationClient(const std::string & hostAddress, const int & port, const size_t & initialResponseTime)
            : _hostAddress(hostAddress),
              _port(port),
              _initialResponseTime(initialResponseTime),
              _currentState(CurrentState::NONE)
    {
    }

    SimulationClient::~SimulationClient()
    {
        _netClient.deinitialize();
    }

    bool SimulationClient::initializeConnection()
    {
        if (_port < 1 || _hostAddress.size() < 1)
        {
            std::cout << "SimulationClient: Port or host address wasn't set.\n";
            return false;
        }
        else if (_currentState > CurrentState::NONE)
            return true;

        if (_netClient.initialize(_hostAddress, _port))
        {
            _currentState = CurrentState::INITED;
            return true;
        }
        else
            return false;
    }

    void SimulationClient::deinitialize()
    {
        _currentState = CurrentState::NONE;

        _inputMessages[0].setSpecifyer(ClientMessageSpecifyer::CLIENT_ABORT);
        send(0);
        _netClient.deinitialize();
    }

    int SimulationClient::addSimulation(const std::string & serverPathToSim)
    {
        if (_currentState == CurrentState::NONE)
            throw std::runtime_error("ERROR: SimulationClient: It's not possible to add simulation before calling initialize(host,port).");
        if (_pathToId.find(serverPathToSim) != _pathToId.end())
            return _pathToId[serverPathToSim];

        const int & simId = _pathToId.size();

        _pathToId[serverPathToSim] = simId;
        _possibleInputVarNames.resize(simId + 1);
        _possibleOutputVarNames.resize(simId + 1);

        _selectedInputVarNames.resize(simId + 1);
        _selectedOutputVarNames.resize(simId + 1);

        _inputMessages.resize(simId + 1);
        _outputMessages.resize(simId + 1);
        _isInitialized.resize(simId + 1, false);

        AddSimRequestMessage req(simId, serverPathToSim);
        sendInitialRequest(req);
        AddSimSuccessMessage varMessage(
                recvInitialServerSuccess<AddSimSuccessMessage>(InitialServerMessageSpecifyer::SUCCESS_ADD_SIM,
                                                               "SimulationClient: Couldn't initialize simulation."));
        _possibleInputVarNames[simId] = varMessage.getInputVariableList();
        _possibleOutputVarNames[simId] = varMessage.getOutputVariableList();
        return simId;
    }

    VariableList SimulationClient::getPossibleInputVariableNames(const int & simId)
    {
        if (_currentState < CurrentState::INITED || simId >= (long long int)_possibleInputVarNames.size())
            throw std::runtime_error("ERROR: SimulationClient: It's not possible to get variables names before calling initialize(host,port).");
        return _possibleInputVarNames[simId];
    }

    VariableList SimulationClient::getPossibleOuputVariableNames(const int & simId)
    {
        if (_currentState < CurrentState::INITED || simId >= (long long int)_possibleOutputVarNames.size())
            throw std::runtime_error("ERROR: SimulationClient: It's not possible to get variables names before calling initialize(host,port).");
        return _possibleOutputVarNames[simId];
    }

    ValueContainer & SimulationClient::initializeSimulation(const int & simId, const VariableList & inputs, const VariableList & outputs, const double * inputsReal,
                                                            const int * inputsInt, const char * inputsBool)
    {
        _selectedInputVarNames[simId] = inputs;
        if (!_selectedInputVarNames[simId].isSubsetOf(_possibleInputVarNames[simId]))
            throw std::runtime_error("SimulationClient: Input variable names passed to initializeSimulation, which aren't supported by server.");
        _selectedOutputVarNames[simId] = outputs;
        if (!_selectedOutputVarNames[simId].isSubsetOf(_possibleOutputVarNames[simId]))
            throw std::runtime_error("SimulationClient: Output variable names passed to initializeSimulation, which aren't supported by server.");

        _inputMessages[simId] = ValueContainerMessage<ClientMessageSpecifyer>(simId, inputs, ClientMessageSpecifyer::INPUTS);
        _outputMessages[simId] = ValueContainerMessage<ServerMessageSpecifyer>(simId, outputs, ServerMessageSpecifyer::OUTPUTS);

        InitSimulationMessage initMessage(simId, inputs, outputs);
        this->sendInitialRequest(initMessage);
        if (inputsReal != nullptr)
            _inputMessages[simId].getContainer().setRealValues(inputsReal);
        if (inputsInt != nullptr)
            _inputMessages[simId].getContainer().setIntValues(inputsInt);
        if (inputsBool != nullptr)
            _inputMessages[simId].getContainer().setBoolValues(inputsBool);
        _inputMessages[simId].setSpecifyer(ClientMessageSpecifyer::INPUTS);
        send(simId);
        _isInitialized[simId] = recv(simId, 0.0, ServerMessageSpecifyer::SUCCESS_SIM_INIT);
        _isInitialized[simId] = true;
        return _outputMessages[simId].getContainer();
    }

    bool SimulationClient::getSimulationFile(const int & simId, const std::string & sourcePath, const std::string & targetPath)
    {
        try {
            GetFileMessage message(simId, sourcePath);
            sendInitialRequest(message);
            std::shared_ptr<size_t> numBytes(new size_t[1]);
            // Receive file content.
            std::shared_ptr<char> data = _netClient.variableRecv(numBytes.get());
            // And store it in given target path.
            GetFileSuccessMessage sucMessage(*numBytes, data, targetPath);
        }
        catch (std::runtime_error& ex)
        {
            std::cout << "Something went wrong in " << __FILE__ << " line " << __LINE__ << std::endl;
            return false;
        }
        return true;
    }

    bool SimulationClient::start()
    {
        bool abortSim = false;

        for (const bool & i : _isInitialized)
            if (!i)
            {
                abortSim = true;
                break;
            }
        if (abortSim || _isInitialized.empty())
        {
            AbortRequestMessage abortM;
            sendInitialRequest(abortM);
            throw std::runtime_error("ERROR: SimulationClient: No simulation added or at least one simulation is not initialized.");
        }
        StartRequestMessage startRequest;
        sendInitialRequest(startRequest);
        recvInitialServerSuccess<StartSuccessMessage>(InitialServerMessageSpecifyer::SUCCESS_START, "SimulationClient: Can't start server.");

        _currentState = CurrentState::STARTED;

        return true;
    }

    bool SimulationClient::pause()
    {
        if (_currentState < CurrentState::STARTED)
            throw std::runtime_error("ERROR: SimulationClient: It's not possible to pause before calling start().");

        _inputMessages[0].setSpecifyer(ClientMessageSpecifyer::PAUSE);
        send(0);

        bool res = recv(0, _inputMessages[0].getTime(), ServerMessageSpecifyer::SUCCESS_PAUSE);
        if (res)
            _currentState = CurrentState::PAUSED;
        return res;
    }

    bool SimulationClient::unpause()
    {
        if (_currentState < CurrentState::STARTED)
            throw std::runtime_error("ERROR: SimulationClient: It's not possible to unpause before calling start().");

        _inputMessages[0].setSpecifyer(ClientMessageSpecifyer::UNPAUSE);
        send(0);

        bool res = recv(0, _inputMessages[0].getTime(), ServerMessageSpecifyer::SUCCESS_UNPAUSE);
        if (res)
            _currentState = CurrentState::STARTED;
        return res;
    }

    bool SimulationClient::reset()
    {
        if (_currentState < CurrentState::STARTED)
            throw std::runtime_error("ERROR: SimulationClient: It's not possible to reset before calling start().");

        _inputMessages[0].setSpecifyer(ClientMessageSpecifyer::RESET);
        send(0);

        bool res = recv(0, _inputMessages[0].getTime(), ServerMessageSpecifyer::SUCCESS_RESET);
        if (res)
            _currentState = CurrentState::INITED;
        return res;
    }

    bool SimulationClient::send(const int simId)
    {
        _netClient.send(reinterpret_cast<const char *>(&_inputMessages[simId].getId()), sizeof(int));  //send id
        return _netClient.send(_inputMessages[simId].data(), _inputMessages[simId].dataSize());
    }

    const std::string & SimulationClient::getHostAddress() const
    {
        return _hostAddress;
    }

    void SimulationClient::setHostAddress(const std::string & hostAddress)
    {
        _hostAddress = hostAddress;
    }

    int SimulationClient::getPort() const
    {
        return _port;
    }

    void SimulationClient::setPort(int port)
    {
        _port = port;
    }

    bool SimulationClient::recv(const int simId, const double & expectedTime, const ServerMessageSpecifyer & spec)
    {
        _netClient.recv(_outputMessages[simId].data(), _outputMessages[simId].dataSize());
        return _outputMessages[simId].getTime() == expectedTime && _outputMessages[simId].getSpecifyer() == spec;
    }

    ValueContainer & SimulationClient::recvOutputValues(const int & simId, const double & time)
    {
        if (_currentState < CurrentState::STARTED)
            throw std::runtime_error("ERROR: SimulationClient: It's not possible to receive outputs before calling start().");

        recv(simId, time, ServerMessageSpecifyer::OUTPUTS);
        return _outputMessages[simId].getContainer();
    }

    bool SimulationClient::sendInputValues(const int & simId, const double & time, const ValueContainer & vals)
    {
        if (_currentState < CurrentState::STARTED)
            throw std::runtime_error("ERROR: SimulationClient: It's not possible to send inputs before calling start().");
        if (vals.getSimId() != simId || vals.data() != getInputValueContainer(simId).data())
        {
            throw std::runtime_error("SimulationClient: The ValueContainer is collected via getValueContainerInput()");
        }
        _inputMessages[simId].setSpecifyer(ClientMessageSpecifyer::INPUTS);
        _inputMessages[simId].setTime(time);
        return send(simId);
    }

    ValueContainer & SimulationClient::getInputValueContainer(const int & simId)
    {
        if (!_isInitialized[simId] || _currentState < CurrentState::INITED)
            throw std::runtime_error("ERROR: SimulationClient: It's not possible to get a input container before calling initializeSimulation.");
        return _inputMessages[simId].getContainer();
    }

    ValueContainer & SimulationClient::getOutputValueContainer(const int & simId)
    {
        if (!_isInitialized[simId] || _currentState < CurrentState::INITED)
            throw std::runtime_error("ERROR: SimulationClient: It's not possible to get a out container before calling initializeSimulation().");
        return _outputMessages[simId].getContainer();
    }
}
<|endoftext|>


<commit_before>#include <openssl/evp.h>
#include <openssl/engine.h>
#include <openssl/rand.h>
#include <openssl/err.h>

class OpenSSLInit
{
    public:

        OpenSSLInit()
        {
            OpenSSL_add_all_algorithms();
        }

        ~OpenSSLInit()
        {
            ERR_remove_state(0);
            ENGINE_cleanup();
            RAND_cleanup();
            CRYPTO_cleanup_all_ex_data();
            ERR_free_strings();
            EVP_cleanup();
        }
};

OpenSSLInit openssl_init;
<commit_msg>fix deprecated openssl macros<commit_after>#include <openssl/evp.h>
#include <openssl/engine.h>
#include <openssl/rand.h>
#include <openssl/err.h>

class OpenSSLInit
{
    public:

        OpenSSLInit()
        {
            OpenSSL_add_all_algorithms();
        }

        ~OpenSSLInit()
        {
#if OPENSSL_VERSION_NUMBER < 0x10000000L
            ERR_remove_state(0);
#elif OPENSSL_VERSION_NUMBER < 0x10100000L
            ERR_remove_thread_state(NULL);
#endif
            ENGINE_cleanup();
            RAND_cleanup();
            CRYPTO_cleanup_all_ex_data();
            ERR_free_strings();
            EVP_cleanup();
        }
};

OpenSSLInit openssl_init;
<|endoftext|>


<commit_before>
/*
 * Copyright (c) 2015-2018 Agalmic Ventures LLC (www.agalmicventures.com)
 *
 * 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 "Hardware.hpp"

#ifdef __MACH__
	#include <sys/types.h>
	#include <sys/sysctl.h>
#endif
#include <unistd.h>

namespace werk
{

uint64_t getPageSize()
{
    const long pageSize = sysconf(_SC_PAGE_SIZE);
    if (pageSize < 0) {
        return 0;
    }

    return static_cast<uint64_t>(pageSize);
}

uint64_t getPhysicalMemorySize()
{
#ifdef __MACH__
	int name[2] = { CTL_HW, HW_MEMSIZE };
    u_int nameLength = sizeof(name) / sizeof(name[0]);
    uint64_t size;
	size_t sizeLength = sizeof(size);
    if (sysctl(name, nameLength, &size, &sizeLength, nullptr, 0) < 0) {
        return 0;
    }

	return size;
#else
    const long pages = sysconf(_SC_PHYS_PAGES);
    if (pages < 0) {
        return 0;
    }

    const uint64_t pageSize = getPageSize();
    return pages * pageSize;
#endif
}

size_t getProcessorCount()
{
	return static_cast<size_t>(sysconf(_SC_NPROCESSORS_CONF));
}

}
<commit_msg>Fix mixed/tabs spaces<commit_after>
/*
 * Copyright (c) 2015-2018 Agalmic Ventures LLC (www.agalmicventures.com)
 *
 * 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 "Hardware.hpp"

#ifdef __MACH__
	#include <sys/sysctl.h>
	#include <sys/types.h>
#endif
#include <unistd.h>

namespace werk
{

uint64_t getPageSize()
{
	const long pageSize = sysconf(_SC_PAGE_SIZE);
	if (pageSize < 0) {
		return 0;
	}

	return static_cast<uint64_t>(pageSize);
}

uint64_t getPhysicalMemorySize()
{
#ifdef __MACH__
	int name[2] = { CTL_HW, HW_MEMSIZE };
	u_int nameLength = sizeof(name) / sizeof(name[0]);
	uint64_t size;
	size_t sizeLength = sizeof(size);
	if (sysctl(name, nameLength, &size, &sizeLength, nullptr, 0) < 0) {
		return 0;
	}

	return size;
#else
	const long pages = sysconf(_SC_PHYS_PAGES);
	if (pages < 0) {
		return 0;
	}

	const uint64_t pageSize = getPageSize();
	return pages * pageSize;
#endif
}

size_t getProcessorCount()
{
	return static_cast<size_t>(sysconf(_SC_NPROCESSORS_CONF));
}

}
<|endoftext|>


<commit_before>#include <QtCore/QString>
#include "msghandler.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>

#ifdef Q_OS_UNIX
#	include <syslog.h>
#	include <execinfo.h>
static void* backtrace_buf[4096];
#else
#	include "win_syslog.h"
#endif

void print_backtrace(FILE* outb)
{
#ifdef Q_OS_UNIX
	int stack_size       = backtrace(backtrace_buf, sizeof(backtrace_buf)/sizeof(void*));
	char** stack_symbols = backtrace_symbols(backtrace_buf, stack_size);

	fprintf(outb, "Stack [%d]:\n", stack_size);
	if (FILE* cppfilt = popen("/usr/bin/c++filt", "rw")) {
		dup2(fileno(outb), fileno(cppfilt));
		for (int i = stack_size-1; i>=0; --i) {
			fwrite(stack_symbols[i], 1, strlen(stack_symbols[i]), cppfilt);
		}

		pclose(cppfilt);
	}
	else {
		for (int i = stack_size-1; i>=0; --i) {
			fprintf(outb, "#%d  %p [%s]\n", i, backtrace_buf[i], stack_symbols[i]);
		}
	}
#else
	Q_UNUSED(outb)
#endif
}

#if QT_VERSION < 0x050000
void messageHandler(QtMsgType type, const char* msg)
{
	fprintf(stderr, "%s\n", msg);
	fflush(stderr);

	int level = LOG_DEBUG;

	switch (type) {
		case QtDebugMsg:    level = LOG_DEBUG; break;
		case QtWarningMsg:  level = LOG_WARNING; break;
		case QtCriticalMsg: level = LOG_ERR; break;
		case QtFatalMsg:    level = LOG_CRIT; break;
	}

	syslog(level, "%s", msg);

	if (QtFatalMsg == type) {
		termination_handler();
	}
}
#else
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg)
{
	QString severity;
	int level = LOG_DEBUG;

	switch (type) {
		case QtDebugMsg:
			severity = QLatin1String("Debug");
			level = LOG_DEBUG;
			break;

		case QtWarningMsg:
			severity = QLatin1String("Warning");
			level = LOG_WARNING;
			break;

		case QtCriticalMsg:
			severity = QLatin1String("Error");
			level = LOG_ERR;
			break;

		case QtFatalMsg:
			severity = QLatin1String("Fatal");
			level = LOG_CRIT;
	}

#ifdef DEBUG
	QString pattern = QLatin1String("%1: %2 (%3:%4, %5)\n");
	QByteArray message = pattern.arg(severity, msg, QLatin1String(context.file), QString::number(context.line), QLatin1String(context.function)).toLocal8Bit();
#else
	Q_UNUSED(context)
	QString pattern = QLatin1String("%1: %2\n");
	QByteArray message = pattern.arg(severity, msg).toLocal8Bit();
#endif

	fprintf(stderr, "%s", message.constData());
	fflush(stderr);

//	syslog(level, "%s", message.constData());

	if (QtFatalMsg == type) {
		termination_handler();
	}
}

#endif

void sigsegv_handler(int)
{
	termination_handler();
}

void termination_handler(void)
{
	print_backtrace(stderr);
	abort();
}
<commit_msg>Disable syslog for now<commit_after>#include <QtCore/QString>
#include "msghandler.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>

#ifdef Q_OS_UNIX
#	include <syslog.h>
#	include <execinfo.h>
static void* backtrace_buf[4096];
#else
#	include "win_syslog.h"
#endif

void print_backtrace(FILE* outb)
{
#ifdef Q_OS_UNIX
	int stack_size       = backtrace(backtrace_buf, sizeof(backtrace_buf)/sizeof(void*));
	char** stack_symbols = backtrace_symbols(backtrace_buf, stack_size);

	fprintf(outb, "Stack [%d]:\n", stack_size);
	if (FILE* cppfilt = popen("/usr/bin/c++filt", "rw")) {
		dup2(fileno(outb), fileno(cppfilt));
		for (int i = stack_size-1; i>=0; --i) {
			fwrite(stack_symbols[i], 1, strlen(stack_symbols[i]), cppfilt);
		}

		pclose(cppfilt);
	}
	else {
		for (int i = stack_size-1; i>=0; --i) {
			fprintf(outb, "#%d  %p [%s]\n", i, backtrace_buf[i], stack_symbols[i]);
		}
	}
#else
	Q_UNUSED(outb)
#endif
}

#if QT_VERSION < 0x050000
void messageHandler(QtMsgType type, const char* msg)
{
	fprintf(stderr, "%s\n", msg);
	fflush(stderr);

	int level = LOG_DEBUG;

	switch (type) {
		case QtDebugMsg:    level = LOG_DEBUG; break;
		case QtWarningMsg:  level = LOG_WARNING; break;
		case QtCriticalMsg: level = LOG_ERR; break;
		case QtFatalMsg:    level = LOG_CRIT; break;
	}

	syslog(level, "%s", msg);

	if (QtFatalMsg == type) {
		termination_handler();
	}
}
#else
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg)
{
	QString severity;
//	int level = LOG_DEBUG;

	switch (type) {
		case QtDebugMsg:
			severity = QLatin1String("Debug");
//			level = LOG_DEBUG;
			break;

		case QtWarningMsg:
			severity = QLatin1String("Warning");
//			level = LOG_WARNING;
			break;

		case QtCriticalMsg:
			severity = QLatin1String("Error");
//			level = LOG_ERR;
			break;

		case QtFatalMsg:
			severity = QLatin1String("Fatal");
//			level = LOG_CRIT;
	}

#ifdef DEBUG
	QString pattern = QLatin1String("%1: %2 (%3:%4, %5)\n");
	QByteArray message = pattern.arg(severity, msg, QLatin1String(context.file), QString::number(context.line), QLatin1String(context.function)).toLocal8Bit();
#else
	Q_UNUSED(context)
	QString pattern = QLatin1String("%1: %2\n");
	QByteArray message = pattern.arg(severity, msg).toLocal8Bit();
#endif

	fprintf(stderr, "%s", message.constData());
	fflush(stderr);

//	syslog(level, "%s", message.constData());

	if (QtFatalMsg == type) {
		termination_handler();
	}
}

#endif

void sigsegv_handler(int)
{
	termination_handler();
}

void termination_handler(void)
{
	print_backtrace(stderr);
	abort();
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (qt-info@nokia.com)
**
** This file is part of the QtDeclarative module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qscriptvalueiterator.h"
#include "qdebug.h"
#include "qtimer.h"
#include "qevent.h"
#include "qdir.h"
#include "qcoreapplication.h"
#include "qfontdatabase.h"
#include "qicon.h"
#include "qurl.h"
#include "qboxlayout.h"
#include "qbasictimer.h"

#include "qml.h"
#include "qfxitem.h"
#include "private/qperformancelog_p.h"
#include "private/qfxperf_p.h"

#include "qfxview.h"
#include <QtDeclarative/qmlengine.h>
#include <QtDeclarative/qmlcontext.h>
#include <QtDeclarative/qmldebug.h>

QT_BEGIN_NAMESPACE

DEFINE_BOOL_CONFIG_OPTION(frameRateDebug, QML_SHOW_FRAMERATE)

static QVariant stringToKeySequence(const QString &str)
{
    return QVariant::fromValue(QKeySequence(str));
}

class QFxViewPrivate
{
public:
    QFxViewPrivate(QFxView *w)
        : q(w), root(0), component(0), resizable(false) {}

    QFxView *q;
    QFxItem *root;

    QUrl source;
    QString qml;

    QmlEngine engine;
    QmlComponent *component;
    QBasicTimer resizetimer;

    QSize initialSize;
    bool resizable;
    QTime frameTimer;

    void init();

    QGraphicsScene scene;
};

/*!
    \class QFxView
    \brief The QFxView class provides a widget for displaying a Qt Declarative user interface.

    QFxView currently provides a minimal interface for displaying QML
    files, and connecting between QML and C++ Qt objects.

    Typical usage:
    \code
    ...
    QFxView *view = new QFxView(this);
    vbox->addWidget(view);

    QUrl url(fileName);
    view->setUrl(url);
    ...
    view->execute();
    ...
    \endcode
*/

/*!
  \fn QFxView::QFxView(QWidget *parent)

  Constructs a QFxView with the given \a parent.
*/
QFxView::QFxView(QWidget *parent)
: QGraphicsView(parent), d(new QFxViewPrivate(this))
{
    setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Preferred);
    d->init();
}

void QFxViewPrivate::init()
{
    // XXX: These need to be put in a central location for this kind of thing
    QmlMetaType::registerCustomStringConverter(QVariant::KeySequence, &stringToKeySequence);

#ifdef Q_ENABLE_PERFORMANCE_LOG
    QFxPerfTimer<QFxPerf::FontDatabase> perf;
#endif
    QFontDatabase database;

    q->setScene(&scene);

    q->setOptimizationFlags(QGraphicsView::DontSavePainterState);
    q->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    q->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    q->setFrameStyle(0);

    // These seem to give the best performance
    q->setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
    scene.setItemIndexMethod(QGraphicsScene::NoIndex);
    q->viewport()->setFocusPolicy(Qt::NoFocus);

    scene.setStickyFocus(true);  //### needed for correct focus handling
}

/*!
  The destructor clears the view's \l {QFxItem} {items} and
  deletes the internal representation.

  \sa clearItems()
 */
QFxView::~QFxView()
{
    clearItems();
    delete d; d = 0;
}

/*!
  Sets the source to the \a url. The QML string is set to
  empty.
 */
void QFxView::setUrl(const QUrl& url)
{
    d->source = url;
    d->qml = QString();
}

/*!
  Sets the source to the URL from the \a filename, and sets
  the QML string to \a qml.
 */
void QFxView::setQml(const QString &qml, const QString &filename)
{
    d->source = QUrl::fromLocalFile(filename);
    d->qml = qml;
}

/*!
  Returns the QML string.
 */
QString QFxView::qml() const
{
    return d->qml;
}

/*!
  Returns a pointer to the QmlEngine used for instantiating
  QML Components.
 */
QmlEngine* QFxView::engine()
{
    return &d->engine;
}

/*!
  This function returns the root of the context hierarchy.  Each QML
  component is instantiated in a QmlContext.  QmlContext's are
  essential for passing data to QML components.  In QML, contexts are
  arranged hierarchically and this hierarchy is managed by the
  QmlEngine.
 */
QmlContext* QFxView::rootContext()
{
    return d->engine.rootContext();
}

/*!
  Displays the Qt Declarative user interface.
*/
void QFxView::execute()
{
    if (d->qml.isEmpty()) {
        d->component = new QmlComponent(&d->engine, d->source, this);
    } else {
        d->component = new QmlComponent(&d->engine, d->qml.toUtf8(), d->source);
    }

    if (!d->component->isLoading()) {
        continueExecute();
    } else {
        connect(d->component, SIGNAL(statusChanged(QmlComponent::Status)), this, SLOT(continueExecute()));
    }
}

/*!
  \internal
 */
void QFxView::continueExecute()
{
    disconnect(d->component, SIGNAL(statusChanged(QmlComponent::Status)), this, SLOT(continueExecute()));

    if (!d->component) {
        qWarning() << "Error in loading" << d->source;
        return;
    }

    if(d->component->isError()) {
        QList<QmlError> errorList = d->component->errors();
        emit errors(errorList);
        foreach (const QmlError &error, errorList) {
            qWarning() << error;
        }

        return;
    }

    QObject *obj = d->component->create();

    if(d->component->isError()) {
        QList<QmlError> errorList = d->component->errors();
        emit errors(errorList);
        foreach (const QmlError &error, errorList) {
            qWarning() << error;
        }

        return;
    }

    if (obj) {
        if (QFxItem *item = qobject_cast<QFxItem *>(obj)) {

            d->scene.addItem(item);

            QPerformanceLog::displayData();
            QPerformanceLog::clear();
            d->root = item;
            connect(item, SIGNAL(widthChanged()), this, SLOT(sizeChanged()));
            connect(item, SIGNAL(heightChanged()), this, SLOT(sizeChanged()));
            if (d->initialSize.height() <= 0 && d->root->width() > 0)
                d->initialSize.setWidth(d->root->width());
            if (d->initialSize.height() <= 0 && d->root->height() > 0)
                d->initialSize.setHeight(d->root->height());
            if (d->resizable) {
                d->root->setWidth(width());
                d->root->setHeight(height());
            } else {
                QSize sz(d->root->width(),d->root->height());
                emit sceneResized(sz);
                resize(sz);
            }
        } else if (QWidget *wid = qobject_cast<QWidget *>(obj)) {
            window()->setAttribute(Qt::WA_OpaquePaintEvent, false);
            window()->setAttribute(Qt::WA_NoSystemBackground, false);
            if (!layout()) {
                setLayout(new QVBoxLayout);
            } else if (layout()->count()) {
                // Hide the QGraphicsView in GV mode.
                QLayoutItem *item = layout()->itemAt(0);
                if (item->widget())
                    item->widget()->hide();
            }
            layout()->addWidget(wid);
            emit sceneResized(wid->size());
        }
    }
}

/*! \fn void QFxView::sceneResized(QSize size)
  This signal is emitted when the view is resized to \a size.
 */

/*! \fn void QFxView::errors(const QList<QmlError> &errors)
  This signal is emitted when the qml loaded contains \a errors.
 */

/*!
  \internal
 */
void QFxView::sizeChanged()
{
    // delay, so we catch both width and height changing.
    d->resizetimer.start(0,this);
}

/*!
  If the \l {QTimerEvent} {timer event} \a e is this
  view's resize timer, sceneResized() is emitted.
 */
void QFxView::timerEvent(QTimerEvent* e)
{
    if (!e || e->timerId() == d->resizetimer.timerId()) {
        if (d->root) {
            QSize sz(d->root->width(),d->root->height());
            emit sceneResized(sz);
            //if (!d->resizable)
                //resize(sz);
        }
        d->resizetimer.stop();
        updateGeometry();
    }
}

// modelled on QScrollArea::widgetResizable
/*!
    \property QFxView::contentResizable
    \brief whether the view should resize the canvas contents

    If this property is set to false (the default), the view
    resizes with the root item in the QML.

    If this property is set to true, the view will
    automatically resize the root item.

    Regardless of this property, the sizeHint of the view
    is the initial size of the root item.
*/

void QFxView::setContentResizable(bool on)
{
    if (d->resizable != on) {
        d->resizable = on;
        if (d->root) {
            if (on) {
                d->root->setWidth(width());
                d->root->setHeight(height());
            } else {
                d->root->setWidth(d->initialSize.width());
                d->root->setHeight(d->initialSize.height());
            }
        }
    }
}

bool QFxView::contentResizable() const
{
    return d->resizable;
}

/*!
    The size hint is the size of the root item.
*/
QSize QFxView::sizeHint() const
{
    if (d->root) {
        if (d->initialSize.width() <= 0)
            d->initialSize.setWidth(d->root->width());
        if (d->initialSize.height() <= 0)
            d->initialSize.setHeight(d->root->height());
    }
    return d->initialSize;
}

/*!
  Creates a \l{QmlComponent} {component} from the \a qml
  string, and returns it as an \l {QFxItem} {item}. If the
  \a parent item is provided, it becomes the new item's
  parent. \a parent should be in this view's item hierarchy.
 */
QFxItem* QFxView::addItem(const QString &qml, QFxItem* parent)
{
    if (!d->root)
        return 0;

    QmlComponent component(&d->engine, qml.toUtf8(), QUrl());
    if(d->component->isError()) {
        QList<QmlError> errorList = d->component->errors();
        emit errors(errorList);
        foreach (const QmlError &error, errorList) {
            qWarning() << error;
        }

        return 0;
    }

    QObject *obj = component.create();
    if(d->component->isError()) {
        QList<QmlError> errorList = d->component->errors();
        emit errors(errorList);
        foreach (const QmlError &error, errorList) {
            qWarning() << error;
        }

        return 0;
    }

    if (obj){
        QFxItem *item = static_cast<QFxItem *>(obj);
        if (!parent)
            parent = d->root;

        item->setParentItem(parent);
        return item;
    }
    return 0;
}

/*!
  Deletes the view's \l {QFxItem} {items} and the \l {QmlEngine}
  {QML engine's} Component cache.
 */
void QFxView::reset()
{
    clearItems();
    d->engine.clearComponentCache();
    d->initialSize = QSize();
}

/*!
  Deletes the view's \l {QFxItem} {items}.
 */
void QFxView::clearItems()
{
    if (!d->root)
        return;
    delete d->root;
    d->root = 0;
}

/*!
  Returns the view's root \l {QFxItem} {item}.
 */
QFxItem *QFxView::root() const
{
    return d->root;
}

/*!
  This function handles the \l {QResizeEvent} {resize event}
  \a e.
 */
void QFxView::resizeEvent(QResizeEvent *e)
{
    if (d->resizable && d->root) {
        d->root->setWidth(width());
        d->root->setHeight(height());
    }
    setSceneRect(rect());
    QGraphicsView::resizeEvent(e);
}

/*!
    \reimp
*/
void QFxView::paintEvent(QPaintEvent *event)
{
    int time = 0;
    if (frameRateDebug())
        time = d->frameTimer.restart();
    QGraphicsView::paintEvent(event);
    if (frameRateDebug())
        qDebug() << "paintEvent:" << d->frameTimer.elapsed() << "time since last frame:" << time;
}

/*! \fn void QFxView::focusInEvent(QFocusEvent *e)
  This virtual function does nothing with the event \a e
  in this class.
 */
void QFxView::focusInEvent(QFocusEvent *)
{
    // Do nothing (do not call QWidget::update())
}

/*! \fn void QFxView::focusOutEvent(QFocusEvent *e)
  This virtual function does nothing with the event \a e
  in this class.
 */
void QFxView::focusOutEvent(QFocusEvent *)
{
    // Do nothing (do not call QWidget::update())
}

QT_END_NAMESPACE
<commit_msg>Fixing layout margins for QWidgets in QFxView<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (qt-info@nokia.com)
**
** This file is part of the QtDeclarative module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qscriptvalueiterator.h"
#include "qdebug.h"
#include "qtimer.h"
#include "qevent.h"
#include "qdir.h"
#include "qcoreapplication.h"
#include "qfontdatabase.h"
#include "qicon.h"
#include "qurl.h"
#include "qboxlayout.h"
#include "qbasictimer.h"

#include "qml.h"
#include "qfxitem.h"
#include "private/qperformancelog_p.h"
#include "private/qfxperf_p.h"

#include "qfxview.h"
#include <QtDeclarative/qmlengine.h>
#include <QtDeclarative/qmlcontext.h>
#include <QtDeclarative/qmldebug.h>

QT_BEGIN_NAMESPACE

DEFINE_BOOL_CONFIG_OPTION(frameRateDebug, QML_SHOW_FRAMERATE)

static QVariant stringToKeySequence(const QString &str)
{
    return QVariant::fromValue(QKeySequence(str));
}

class QFxViewPrivate
{
public:
    QFxViewPrivate(QFxView *w)
        : q(w), root(0), component(0), resizable(false) {}

    QFxView *q;
    QFxItem *root;

    QUrl source;
    QString qml;

    QmlEngine engine;
    QmlComponent *component;
    QBasicTimer resizetimer;

    QSize initialSize;
    bool resizable;
    QTime frameTimer;

    void init();

    QGraphicsScene scene;
};

/*!
    \class QFxView
    \brief The QFxView class provides a widget for displaying a Qt Declarative user interface.

    QFxView currently provides a minimal interface for displaying QML
    files, and connecting between QML and C++ Qt objects.

    Typical usage:
    \code
    ...
    QFxView *view = new QFxView(this);
    vbox->addWidget(view);

    QUrl url(fileName);
    view->setUrl(url);
    ...
    view->execute();
    ...
    \endcode
*/

/*!
  \fn QFxView::QFxView(QWidget *parent)

  Constructs a QFxView with the given \a parent.
*/
QFxView::QFxView(QWidget *parent)
: QGraphicsView(parent), d(new QFxViewPrivate(this))
{
    setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Preferred);
    d->init();
}

void QFxViewPrivate::init()
{
    // XXX: These need to be put in a central location for this kind of thing
    QmlMetaType::registerCustomStringConverter(QVariant::KeySequence, &stringToKeySequence);

#ifdef Q_ENABLE_PERFORMANCE_LOG
    QFxPerfTimer<QFxPerf::FontDatabase> perf;
#endif
    QFontDatabase database;

    q->setScene(&scene);

    q->setOptimizationFlags(QGraphicsView::DontSavePainterState);
    q->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    q->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    q->setFrameStyle(0);

    // These seem to give the best performance
    q->setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
    scene.setItemIndexMethod(QGraphicsScene::NoIndex);
    q->viewport()->setFocusPolicy(Qt::NoFocus);

    scene.setStickyFocus(true);  //### needed for correct focus handling
}

/*!
  The destructor clears the view's \l {QFxItem} {items} and
  deletes the internal representation.

  \sa clearItems()
 */
QFxView::~QFxView()
{
    clearItems();
    delete d; d = 0;
}

/*!
  Sets the source to the \a url. The QML string is set to
  empty.
 */
void QFxView::setUrl(const QUrl& url)
{
    d->source = url;
    d->qml = QString();
}

/*!
  Sets the source to the URL from the \a filename, and sets
  the QML string to \a qml.
 */
void QFxView::setQml(const QString &qml, const QString &filename)
{
    d->source = QUrl::fromLocalFile(filename);
    d->qml = qml;
}

/*!
  Returns the QML string.
 */
QString QFxView::qml() const
{
    return d->qml;
}

/*!
  Returns a pointer to the QmlEngine used for instantiating
  QML Components.
 */
QmlEngine* QFxView::engine()
{
    return &d->engine;
}

/*!
  This function returns the root of the context hierarchy.  Each QML
  component is instantiated in a QmlContext.  QmlContext's are
  essential for passing data to QML components.  In QML, contexts are
  arranged hierarchically and this hierarchy is managed by the
  QmlEngine.
 */
QmlContext* QFxView::rootContext()
{
    return d->engine.rootContext();
}

/*!
  Displays the Qt Declarative user interface.
*/
void QFxView::execute()
{
    if (d->qml.isEmpty()) {
        d->component = new QmlComponent(&d->engine, d->source, this);
    } else {
        d->component = new QmlComponent(&d->engine, d->qml.toUtf8(), d->source);
    }

    if (!d->component->isLoading()) {
        continueExecute();
    } else {
        connect(d->component, SIGNAL(statusChanged(QmlComponent::Status)), this, SLOT(continueExecute()));
    }
}

/*!
  \internal
 */
void QFxView::continueExecute()
{
    disconnect(d->component, SIGNAL(statusChanged(QmlComponent::Status)), this, SLOT(continueExecute()));

    if (!d->component) {
        qWarning() << "Error in loading" << d->source;
        return;
    }

    if(d->component->isError()) {
        QList<QmlError> errorList = d->component->errors();
        emit errors(errorList);
        foreach (const QmlError &error, errorList) {
            qWarning() << error;
        }

        return;
    }

    QObject *obj = d->component->create();

    if(d->component->isError()) {
        QList<QmlError> errorList = d->component->errors();
        emit errors(errorList);
        foreach (const QmlError &error, errorList) {
            qWarning() << error;
        }

        return;
    }

    if (obj) {
        if (QFxItem *item = qobject_cast<QFxItem *>(obj)) {

            d->scene.addItem(item);

            QPerformanceLog::displayData();
            QPerformanceLog::clear();
            d->root = item;
            connect(item, SIGNAL(widthChanged()), this, SLOT(sizeChanged()));
            connect(item, SIGNAL(heightChanged()), this, SLOT(sizeChanged()));
            if (d->initialSize.height() <= 0 && d->root->width() > 0)
                d->initialSize.setWidth(d->root->width());
            if (d->initialSize.height() <= 0 && d->root->height() > 0)
                d->initialSize.setHeight(d->root->height());
            if (d->resizable) {
                d->root->setWidth(width());
                d->root->setHeight(height());
            } else {
                QSize sz(d->root->width(),d->root->height());
                emit sceneResized(sz);
                resize(sz);
            }
        } else if (QWidget *wid = qobject_cast<QWidget *>(obj)) {
            window()->setAttribute(Qt::WA_OpaquePaintEvent, false);
            window()->setAttribute(Qt::WA_NoSystemBackground, false);
            if (!layout()) {
                setLayout(new QVBoxLayout);
                layout()->setContentsMargins(0, 0, 0, 0);
            } else if (layout()->count()) {
                // Hide the QGraphicsView in GV mode.
                QLayoutItem *item = layout()->itemAt(0);
                if (item->widget())
                    item->widget()->hide();
            }
            layout()->addWidget(wid);
            emit sceneResized(wid->size());
        }
    }
}

/*! \fn void QFxView::sceneResized(QSize size)
  This signal is emitted when the view is resized to \a size.
 */

/*! \fn void QFxView::errors(const QList<QmlError> &errors)
  This signal is emitted when the qml loaded contains \a errors.
 */

/*!
  \internal
 */
void QFxView::sizeChanged()
{
    // delay, so we catch both width and height changing.
    d->resizetimer.start(0,this);
}

/*!
  If the \l {QTimerEvent} {timer event} \a e is this
  view's resize timer, sceneResized() is emitted.
 */
void QFxView::timerEvent(QTimerEvent* e)
{
    if (!e || e->timerId() == d->resizetimer.timerId()) {
        if (d->root) {
            QSize sz(d->root->width(),d->root->height());
            emit sceneResized(sz);
            //if (!d->resizable)
                //resize(sz);
        }
        d->resizetimer.stop();
        updateGeometry();
    }
}

// modelled on QScrollArea::widgetResizable
/*!
    \property QFxView::contentResizable
    \brief whether the view should resize the canvas contents

    If this property is set to false (the default), the view
    resizes with the root item in the QML.

    If this property is set to true, the view will
    automatically resize the root item.

    Regardless of this property, the sizeHint of the view
    is the initial size of the root item.
*/

void QFxView::setContentResizable(bool on)
{
    if (d->resizable != on) {
        d->resizable = on;
        if (d->root) {
            if (on) {
                d->root->setWidth(width());
                d->root->setHeight(height());
            } else {
                d->root->setWidth(d->initialSize.width());
                d->root->setHeight(d->initialSize.height());
            }
        }
    }
}

bool QFxView::contentResizable() const
{
    return d->resizable;
}

/*!
    The size hint is the size of the root item.
*/
QSize QFxView::sizeHint() const
{
    if (d->root) {
        if (d->initialSize.width() <= 0)
            d->initialSize.setWidth(d->root->width());
        if (d->initialSize.height() <= 0)
            d->initialSize.setHeight(d->root->height());
    }
    return d->initialSize;
}

/*!
  Creates a \l{QmlComponent} {component} from the \a qml
  string, and returns it as an \l {QFxItem} {item}. If the
  \a parent item is provided, it becomes the new item's
  parent. \a parent should be in this view's item hierarchy.
 */
QFxItem* QFxView::addItem(const QString &qml, QFxItem* parent)
{
    if (!d->root)
        return 0;

    QmlComponent component(&d->engine, qml.toUtf8(), QUrl());
    if(d->component->isError()) {
        QList<QmlError> errorList = d->component->errors();
        emit errors(errorList);
        foreach (const QmlError &error, errorList) {
            qWarning() << error;
        }

        return 0;
    }

    QObject *obj = component.create();
    if(d->component->isError()) {
        QList<QmlError> errorList = d->component->errors();
        emit errors(errorList);
        foreach (const QmlError &error, errorList) {
            qWarning() << error;
        }

        return 0;
    }

    if (obj){
        QFxItem *item = static_cast<QFxItem *>(obj);
        if (!parent)
            parent = d->root;

        item->setParentItem(parent);
        return item;
    }
    return 0;
}

/*!
  Deletes the view's \l {QFxItem} {items} and the \l {QmlEngine}
  {QML engine's} Component cache.
 */
void QFxView::reset()
{
    clearItems();
    d->engine.clearComponentCache();
    d->initialSize = QSize();
}

/*!
  Deletes the view's \l {QFxItem} {items}.
 */
void QFxView::clearItems()
{
    if (!d->root)
        return;
    delete d->root;
    d->root = 0;
}

/*!
  Returns the view's root \l {QFxItem} {item}.
 */
QFxItem *QFxView::root() const
{
    return d->root;
}

/*!
  This function handles the \l {QResizeEvent} {resize event}
  \a e.
 */
void QFxView::resizeEvent(QResizeEvent *e)
{
    if (d->resizable && d->root) {
        d->root->setWidth(width());
        d->root->setHeight(height());
    }
    setSceneRect(rect());
    QGraphicsView::resizeEvent(e);
}

/*!
    \reimp
*/
void QFxView::paintEvent(QPaintEvent *event)
{
    int time = 0;
    if (frameRateDebug())
        time = d->frameTimer.restart();
    QGraphicsView::paintEvent(event);
    if (frameRateDebug())
        qDebug() << "paintEvent:" << d->frameTimer.elapsed() << "time since last frame:" << time;
}

/*! \fn void QFxView::focusInEvent(QFocusEvent *e)
  This virtual function does nothing with the event \a e
  in this class.
 */
void QFxView::focusInEvent(QFocusEvent *)
{
    // Do nothing (do not call QWidget::update())
}

/*! \fn void QFxView::focusOutEvent(QFocusEvent *e)
  This virtual function does nothing with the event \a e
  in this class.
 */
void QFxView::focusOutEvent(QFocusEvent *)
{
    // Do nothing (do not call QWidget::update())
}

QT_END_NAMESPACE
<|endoftext|>


<commit_before>// Copyright (c) 2014-2018 The Dash Core developers
// Copyright (c) 2014-2018 The Machinecoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <activemasternode.h>
#include <masternode.h>
#include <masternode-sync.h>
#include <masternodeman.h>
#include <protocol.h>

// Keep track of the active Masternode
CActiveMasternode activeMasternode;

void CActiveMasternode::ManageState(CConnman& connman)
{
    LogPrint(MCLog::MN, "CActiveMasternode::ManageState -- Start\n");
    if(!fMasterNode) {
        LogPrint(MCLog::MN, "CActiveMasternode::ManageState -- Not a masternode, returning\n");
        return;
    }

    if(Params().NetworkIDString() != CBaseChainParams::REGTEST && !masternodeSync.IsBlockchainSynced()) {
        nState = ACTIVE_MASTERNODE_SYNC_IN_PROCESS;
        LogPrintf("CActiveMasternode::ManageState -- %s: %s\n", GetStateString(), GetStatus());
        return;
    }

    if(nState == ACTIVE_MASTERNODE_SYNC_IN_PROCESS) {
        nState = ACTIVE_MASTERNODE_INITIAL;
    }

    LogPrint(MCLog::MN, "CActiveMasternode::ManageState -- status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetTypeString(), fPingerEnabled);

    if(eType == MASTERNODE_UNKNOWN) {
        ManageStateInitial(connman);
    }

    if(eType == MASTERNODE_REMOTE) {
        ManageStateRemote();
    }

    SendMasternodePing(connman);
}

std::string CActiveMasternode::GetStateString() const
{
    switch (nState) {
        case ACTIVE_MASTERNODE_INITIAL:         return "INITIAL";
        case ACTIVE_MASTERNODE_SYNC_IN_PROCESS: return "SYNC_IN_PROCESS";
        case ACTIVE_MASTERNODE_INPUT_TOO_NEW:   return "INPUT_TOO_NEW";
        case ACTIVE_MASTERNODE_NOT_CAPABLE:     return "NOT_CAPABLE";
        case ACTIVE_MASTERNODE_STARTED:         return "STARTED";
        default:                                return "UNKNOWN";
    }
}

std::string CActiveMasternode::GetStatus() const
{
    switch (nState) {
        case ACTIVE_MASTERNODE_INITIAL:         return "Node just started, not yet activated";
        case ACTIVE_MASTERNODE_SYNC_IN_PROCESS: return "Sync in progress. Must wait until sync is complete to start Masternode";
        case ACTIVE_MASTERNODE_INPUT_TOO_NEW:   return strprintf("Masternode input must have at least %d confirmations", Params().GetConsensus().nMasternodeMinimumConfirmations);
        case ACTIVE_MASTERNODE_NOT_CAPABLE:     return "Not capable masternode: " + strNotCapableReason;
        case ACTIVE_MASTERNODE_STARTED:         return "Masternode successfully started";
        default:                                return "Unknown";
    }
}

std::string CActiveMasternode::GetTypeString() const
{
    std::string strType;
    switch(eType) {
    case MASTERNODE_REMOTE:
        strType = "REMOTE";
        break;
    default:
        strType = "UNKNOWN";
        break;
    }
    return strType;
}

bool CActiveMasternode::SendMasternodePing(CConnman& connman)
{
    if(!fPingerEnabled) {
        LogPrint(MCLog::MN, "CActiveMasternode::SendMasternodePing -- %s: masternode ping service is disabled, skipping...\n", GetStateString());
        return false;
    }

    if(!mnodeman.Has(outpoint)) {
        strNotCapableReason = "Masternode not in masternode list";
        nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
        LogPrintf("CActiveMasternode::SendMasternodePing -- %s: %s\n", GetStateString(), strNotCapableReason);
        return false;
    }

    CMasternodePing mnp(outpoint);
    mnp.nSentinelVersion = nSentinelVersion;
    mnp.fSentinelIsCurrent =
            (abs(GetAdjustedTime() - nSentinelPingTime) < MASTERNODE_WATCHDOG_MAX_SECONDS);
    if(!mnp.Sign(keyMasternode, pubKeyMasternode)) {
        LogPrintf("CActiveMasternode::SendMasternodePing -- ERROR: Couldn't sign Masternode Ping\n");
        return false;
    }

    // Update lastPing for our masternode in Masternode list
    if(mnodeman.IsMasternodePingedWithin(outpoint, MASTERNODE_MIN_MNP_SECONDS, mnp.sigTime)) {
        LogPrintf("CActiveMasternode::SendMasternodePing -- Too early to send Masternode Ping\n");
        return false;
    }

    mnodeman.SetMasternodeLastPing(outpoint, mnp);

    LogPrintf("CActiveMasternode::SendMasternodePing -- Relaying ping, collateral=%s\n", outpoint.ToStringShort());
    mnp.Relay(connman);

    return true;
}

bool CActiveMasternode::UpdateSentinelPing(int version)
{
    nSentinelVersion = version;
    nSentinelPingTime = GetAdjustedTime();

    return true;
}

void CActiveMasternode::ManageStateInitial(CConnman& connman)
{
    LogPrint(MCLog::MN, "CActiveMasternode::ManageStateInitial -- status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetTypeString(), fPingerEnabled);

    // Check that our local network configuration is correct
    if (!fListen) {
        // listen option is probably overwritten by smth else, no good
        nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
        strNotCapableReason = "Masternode must accept connections from outside. Make sure listen configuration option is not overwritten by some another parameter.";
        LogPrintf("CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
        return;
    }

    // First try to find whatever local address is specified by externalip option
    bool fFoundLocal = GetLocal(service) && CMasternode::IsValidNetAddr(service);
    if(!fFoundLocal) {
        bool empty = true;
        // If we have some peers, let's try to find our local address from one of them
        connman.ForEachNodeContinueIf(CConnman::AllNodes, [&fFoundLocal, &empty, this](CNode* pnode) {
            empty = false;
            if (pnode->addr.IsIPv4())
                fFoundLocal = GetLocal(service, &pnode->addr) && CMasternode::IsValidNetAddr(service);
            return !fFoundLocal;
        });
        // nothing and no live connections, can't do anything for now
        if (empty) {
            nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
            strNotCapableReason = "Can't detect valid external address. Will retry when there are some connections available.";
            LogPrintf("CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
            return;
        }
    }

    if(!fFoundLocal) {
        nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
        strNotCapableReason = "Can't detect valid external address. Please consider using the externalip configuration option if problem persists. Make sure to use IPv4 address only.";
        LogPrintf("CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
        return;
    }

    const auto defaultChainParams = CreateChainParams(CBaseChainParams::MAIN).GetDefaultPort();
    if(Params().NetworkIDString() == CBaseChainParams::MAIN) {
        if(service.GetPort() != mainnetDefaultPort) {
            nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
            strNotCapableReason = strprintf("Invalid port: %u - only %d is supported on mainnet.", service.GetPort(), mainnetDefaultPort);
            LogPrintf("CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
            return;
        }
    } else if(service.GetPort() == mainnetDefaultPort) {
        nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
        strNotCapableReason = strprintf("Invalid port: %u - %d is only supported on mainnet.", service.GetPort(), mainnetDefaultPort);
        LogPrintf("CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
        return;
    }

    LogPrintf("CActiveMasternode::ManageStateInitial -- Checking inbound connection to '%s'\n", service.ToString());

    if(!connman.ConnectNode(CAddress(service, NODE_NETWORK), NULL, false, true)) {
        nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
        strNotCapableReason = "Could not connect to " + service.ToString();
        LogPrintf("CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
        return;
    }

    // Default to REMOTE
    eType = MASTERNODE_REMOTE;

    LogPrint(MCLog::MN, "CActiveMasternode::ManageStateInitial -- End status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetTypeString(), fPingerEnabled);
}

void CActiveMasternode::ManageStateRemote()
{
    LogPrint(MCLog::MN, "CActiveMasternode::ManageStateRemote -- Start status = %s, type = %s, pinger enabled = %d, pubKeyMasternode.GetID() = %s\n",
             GetStatus(), GetTypeString(), fPingerEnabled, pubKeyMasternode.GetID().ToString());

    mnodeman.CheckMasternode(pubKeyMasternode, true);
    masternode_info_t infoMn;
    if(mnodeman.GetMasternodeInfo(pubKeyMasternode, infoMn)) {
        if(infoMn.nProtocolVersion != PROTOCOL_VERSION) {
            nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
            strNotCapableReason = "Invalid protocol version";
            LogPrintf("CActiveMasternode::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason);
            return;
        }
        if(service != infoMn.addr) {
            nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
            strNotCapableReason = "Broadcasted IP doesn't match our external address. Make sure you issued a new broadcast if IP of this masternode changed recently.";
            LogPrintf("CActiveMasternode::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason);
            return;
        }
        if(!CMasternode::IsValidStateForAutoStart(infoMn.nActiveState)) {
            nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
            strNotCapableReason = strprintf("Masternode in %s state", CMasternode::StateToString(infoMn.nActiveState));
            LogPrintf("CActiveMasternode::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason);
            return;
        }
        if(nState != ACTIVE_MASTERNODE_STARTED) {
            LogPrintf("CActiveMasternode::ManageStateRemote -- STARTED!\n");
            outpoint = infoMn.vin.prevout;
            service = infoMn.addr;
            fPingerEnabled = true;
            nState = ACTIVE_MASTERNODE_STARTED;
        }
    }
    else {
        nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
        strNotCapableReason = "Masternode not in masternode list";
        LogPrintf("CActiveMasternode::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason);
    }
}<commit_msg>use newer syntax<commit_after>// Copyright (c) 2014-2018 The Dash Core developers
// Copyright (c) 2014-2018 The Machinecoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <activemasternode.h>
#include <masternode.h>
#include <masternode-sync.h>
#include <masternodeman.h>
#include <protocol.h>

// Keep track of the active Masternode
CActiveMasternode activeMasternode;

void CActiveMasternode::ManageState(CConnman& connman)
{
    LogPrint(MCLog::MN, "CActiveMasternode::ManageState -- Start\n");
    if(!fMasterNode) {
        LogPrint(MCLog::MN, "CActiveMasternode::ManageState -- Not a masternode, returning\n");
        return;
    }

    if(Params().NetworkIDString() != CBaseChainParams::REGTEST && !masternodeSync.IsBlockchainSynced()) {
        nState = ACTIVE_MASTERNODE_SYNC_IN_PROCESS;
        LogPrintf("CActiveMasternode::ManageState -- %s: %s\n", GetStateString(), GetStatus());
        return;
    }

    if(nState == ACTIVE_MASTERNODE_SYNC_IN_PROCESS) {
        nState = ACTIVE_MASTERNODE_INITIAL;
    }

    LogPrint(MCLog::MN, "CActiveMasternode::ManageState -- status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetTypeString(), fPingerEnabled);

    if(eType == MASTERNODE_UNKNOWN) {
        ManageStateInitial(connman);
    }

    if(eType == MASTERNODE_REMOTE) {
        ManageStateRemote();
    }

    SendMasternodePing(connman);
}

std::string CActiveMasternode::GetStateString() const
{
    switch (nState) {
        case ACTIVE_MASTERNODE_INITIAL:         return "INITIAL";
        case ACTIVE_MASTERNODE_SYNC_IN_PROCESS: return "SYNC_IN_PROCESS";
        case ACTIVE_MASTERNODE_INPUT_TOO_NEW:   return "INPUT_TOO_NEW";
        case ACTIVE_MASTERNODE_NOT_CAPABLE:     return "NOT_CAPABLE";
        case ACTIVE_MASTERNODE_STARTED:         return "STARTED";
        default:                                return "UNKNOWN";
    }
}

std::string CActiveMasternode::GetStatus() const
{
    switch (nState) {
        case ACTIVE_MASTERNODE_INITIAL:         return "Node just started, not yet activated";
        case ACTIVE_MASTERNODE_SYNC_IN_PROCESS: return "Sync in progress. Must wait until sync is complete to start Masternode";
        case ACTIVE_MASTERNODE_INPUT_TOO_NEW:   return strprintf("Masternode input must have at least %d confirmations", Params().GetConsensus().nMasternodeMinimumConfirmations);
        case ACTIVE_MASTERNODE_NOT_CAPABLE:     return "Not capable masternode: " + strNotCapableReason;
        case ACTIVE_MASTERNODE_STARTED:         return "Masternode successfully started";
        default:                                return "Unknown";
    }
}

std::string CActiveMasternode::GetTypeString() const
{
    std::string strType;
    switch(eType) {
    case MASTERNODE_REMOTE:
        strType = "REMOTE";
        break;
    default:
        strType = "UNKNOWN";
        break;
    }
    return strType;
}

bool CActiveMasternode::SendMasternodePing(CConnman& connman)
{
    if(!fPingerEnabled) {
        LogPrint(MCLog::MN, "CActiveMasternode::SendMasternodePing -- %s: masternode ping service is disabled, skipping...\n", GetStateString());
        return false;
    }

    if(!mnodeman.Has(outpoint)) {
        strNotCapableReason = "Masternode not in masternode list";
        nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
        LogPrintf("CActiveMasternode::SendMasternodePing -- %s: %s\n", GetStateString(), strNotCapableReason);
        return false;
    }

    CMasternodePing mnp(outpoint);
    mnp.nSentinelVersion = nSentinelVersion;
    mnp.fSentinelIsCurrent =
            (abs(GetAdjustedTime() - nSentinelPingTime) < MASTERNODE_WATCHDOG_MAX_SECONDS);
    if(!mnp.Sign(keyMasternode, pubKeyMasternode)) {
        LogPrintf("CActiveMasternode::SendMasternodePing -- ERROR: Couldn't sign Masternode Ping\n");
        return false;
    }

    // Update lastPing for our masternode in Masternode list
    if(mnodeman.IsMasternodePingedWithin(outpoint, MASTERNODE_MIN_MNP_SECONDS, mnp.sigTime)) {
        LogPrintf("CActiveMasternode::SendMasternodePing -- Too early to send Masternode Ping\n");
        return false;
    }

    mnodeman.SetMasternodeLastPing(outpoint, mnp);

    LogPrintf("CActiveMasternode::SendMasternodePing -- Relaying ping, collateral=%s\n", outpoint.ToStringShort());
    mnp.Relay(connman);

    return true;
}

bool CActiveMasternode::UpdateSentinelPing(int version)
{
    nSentinelVersion = version;
    nSentinelPingTime = GetAdjustedTime();

    return true;
}

void CActiveMasternode::ManageStateInitial(CConnman& connman)
{
    LogPrint(MCLog::MN, "CActiveMasternode::ManageStateInitial -- status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetTypeString(), fPingerEnabled);

    // Check that our local network configuration is correct
    if (!fListen) {
        // listen option is probably overwritten by smth else, no good
        nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
        strNotCapableReason = "Masternode must accept connections from outside. Make sure listen configuration option is not overwritten by some another parameter.";
        LogPrintf("CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
        return;
    }

    // First try to find whatever local address is specified by externalip option
    bool fFoundLocal = GetLocal(service) && CMasternode::IsValidNetAddr(service);
    if(!fFoundLocal) {
        bool empty = true;
        // If we have some peers, let's try to find our local address from one of them
        connman.ForEachNodeContinueIf(CConnman::AllNodes, [&fFoundLocal, &empty, this](CNode* pnode) {
            empty = false;
            if (pnode->addr.IsIPv4())
                fFoundLocal = GetLocal(service, &pnode->addr) && CMasternode::IsValidNetAddr(service);
            return !fFoundLocal;
        });
        // nothing and no live connections, can't do anything for now
        if (empty) {
            nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
            strNotCapableReason = "Can't detect valid external address. Will retry when there are some connections available.";
            LogPrintf("CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
            return;
        }
    }

    if(!fFoundLocal) {
        nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
        strNotCapableReason = "Can't detect valid external address. Please consider using the externalip configuration option if problem persists. Make sure to use IPv4 address only.";
        LogPrintf("CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
        return;
    }

    int defaultChainParams = CreateChainParams(CBaseChainParams::MAIN)->GetDefaultPort();
    if(Params().NetworkIDString() == CBaseChainParams::MAIN) {
        if(service.GetPort() != mainnetDefaultPort) {
            nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
            strNotCapableReason = strprintf("Invalid port: %u - only %d is supported on mainnet.", service.GetPort(), mainnetDefaultPort);
            LogPrintf("CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
            return;
        }
    } else if(service.GetPort() == mainnetDefaultPort) {
        nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
        strNotCapableReason = strprintf("Invalid port: %u - %d is only supported on mainnet.", service.GetPort(), mainnetDefaultPort);
        LogPrintf("CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
        return;
    }

    LogPrintf("CActiveMasternode::ManageStateInitial -- Checking inbound connection to '%s'\n", service.ToString());

    if(!connman.ConnectNode(CAddress(service, NODE_NETWORK), NULL, false, true)) {
        nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
        strNotCapableReason = "Could not connect to " + service.ToString();
        LogPrintf("CActiveMasternode::ManageStateInitial -- %s: %s\n", GetStateString(), strNotCapableReason);
        return;
    }

    // Default to REMOTE
    eType = MASTERNODE_REMOTE;

    LogPrint(MCLog::MN, "CActiveMasternode::ManageStateInitial -- End status = %s, type = %s, pinger enabled = %d\n", GetStatus(), GetTypeString(), fPingerEnabled);
}

void CActiveMasternode::ManageStateRemote()
{
    LogPrint(MCLog::MN, "CActiveMasternode::ManageStateRemote -- Start status = %s, type = %s, pinger enabled = %d, pubKeyMasternode.GetID() = %s\n",
             GetStatus(), GetTypeString(), fPingerEnabled, pubKeyMasternode.GetID().ToString());

    mnodeman.CheckMasternode(pubKeyMasternode, true);
    masternode_info_t infoMn;
    if(mnodeman.GetMasternodeInfo(pubKeyMasternode, infoMn)) {
        if(infoMn.nProtocolVersion != PROTOCOL_VERSION) {
            nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
            strNotCapableReason = "Invalid protocol version";
            LogPrintf("CActiveMasternode::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason);
            return;
        }
        if(service != infoMn.addr) {
            nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
            strNotCapableReason = "Broadcasted IP doesn't match our external address. Make sure you issued a new broadcast if IP of this masternode changed recently.";
            LogPrintf("CActiveMasternode::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason);
            return;
        }
        if(!CMasternode::IsValidStateForAutoStart(infoMn.nActiveState)) {
            nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
            strNotCapableReason = strprintf("Masternode in %s state", CMasternode::StateToString(infoMn.nActiveState));
            LogPrintf("CActiveMasternode::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason);
            return;
        }
        if(nState != ACTIVE_MASTERNODE_STARTED) {
            LogPrintf("CActiveMasternode::ManageStateRemote -- STARTED!\n");
            outpoint = infoMn.vin.prevout;
            service = infoMn.addr;
            fPingerEnabled = true;
            nState = ACTIVE_MASTERNODE_STARTED;
        }
    }
    else {
        nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
        strNotCapableReason = "Masternode not in masternode list";
        LogPrintf("CActiveMasternode::ManageStateRemote -- %s: %s\n", GetStateString(), strNotCapableReason);
    }
}<|endoftext|>