<commit_before>// Copyright 2013 Tanel Lebedev

#include "./main.h"

#include <sstream>
#include <iostream> // NOLINT

#include "Poco/Message.h"
#include "Poco/Util/Application.h"

#define ERRLEN 1024

namespace command_line_client {

    void Main::usage() {
        std::cout << "Recognized commands are: "
            "sync, start, stop, status, pushable, list, continue"
            << std::endl;
    }

    void Main::defineOptions(Poco::Util::OptionSet& options) {
        Poco::Util::Application::defineOptions(options);
        options.addOption(Poco::Util::Option(
            "verbose", "v", "verbose logging, to the console"));
    }

    int Main::main(const std::vector<std::string>& args) {
        if (args.empty()) {
            usage();
            return Poco::Util::Application::EXIT_USAGE;
        }

        char* apiToken = getenv("TOGGL_API_TOKEN");
        if (!apiToken) {
            std::cerr << "Please set TOGGL_API_TOKEN in environment" <<
                std::endl;
            return Poco::Util::Application::EXIT_USAGE;
        }

        kopsik_set_db_path(ctx, "kopsik.db");
        kopsik_set_log_path(ctx, "kopsik.log");

        // Start session in lib
        char err[ERRLEN];
        std::fill(err, err + ERRLEN, 0);
        if (KOPSIK_API_SUCCESS != kopsik_set_api_token(
                ctx, err, ERRLEN, apiToken)) {
            std::cerr << err << std::endl;
            return Poco::Util::Application::EXIT_SOFTWARE;
        }

        // Load user that is referenced by the session
        KopsikUser *user = kopsik_user_init();
        if (KOPSIK_API_SUCCESS != kopsik_current_user(
                ctx, err, ERRLEN, user)) {
            std::cerr << err << std::endl;
            return Poco::Util::Application::EXIT_SOFTWARE;
        }
        kopsik_user_clear(user);

        if ("sync" == args[0]) {
            if (KOPSIK_API_SUCCESS != kopsik_sync(ctx, err, ERRLEN, 1)) {
                std::cerr << err << std::endl;
                return Poco::Util::Application::EXIT_SOFTWARE;
            }
            std::cout << "Synced." << std::endl;
            return Poco::Util::Application::EXIT_OK;
        }

        if ("status" == args[0]) {
            KopsikTimeEntryViewItem *te = kopsik_time_entry_view_item_init();
            int found(0);
            if (KOPSIK_API_SUCCESS != kopsik_running_time_entry_view_item(
                    ctx, err, ERRLEN, te, &found)) {
                std::cerr << err << std::endl;
                kopsik_time_entry_view_item_clear(te);
                return Poco::Util::Application::EXIT_SOFTWARE;
            }
            if (found) {
                std::cout << "Tracking: " << te->Description << std::endl;
            } else {
                std::cout << "Not tracking." << std::endl;
            }
            kopsik_time_entry_view_item_clear(te);
            return Poco::Util::Application::EXIT_OK;
        }

        if ("pushable" == args[0]) {
            KopsikPushableModelStats stats;
            if (KOPSIK_API_SUCCESS != kopsik_pushable_models(
                    ctx, err, ERRLEN, &stats)) {
                std::cerr << err << std::endl;
                return Poco::Util::Application::EXIT_SOFTWARE;
            }
            std::cout << stats.TimeEntries << " pushable time entries." << std::endl;
            return Poco::Util::Application::EXIT_OK;
        }

        if ("start" == args[0]) {
            KopsikTimeEntryViewItem *te = kopsik_time_entry_view_item_init();
            if (KOPSIK_API_SUCCESS != kopsik_start(
                    ctx, err, ERRLEN, "New time entry", te)) {
                std::cerr << err << std::endl;
                kopsik_time_entry_view_item_clear(te);
                return Poco::Util::Application::EXIT_SOFTWARE;
            }
            if (KOPSIK_API_SUCCESS != kopsik_push(ctx, err, ERRLEN)) {
                std::cerr << err << std::endl;
            }
            if (te->Description) {
                std::cout << "Started: " << te->Description << std::endl;
            } else {
                std::cout << "Started." << std::endl;
            }
            kopsik_time_entry_view_item_clear(te);
            return Poco::Util::Application::EXIT_OK;
        }

        if ("stop" == args[0]) {
            KopsikTimeEntryViewItem *te = kopsik_time_entry_view_item_init();
            if (KOPSIK_API_SUCCESS != kopsik_stop(
                    ctx, err, ERRLEN, te)) {
                std::cerr << err << std::endl;
                kopsik_time_entry_view_item_clear(te);
                return Poco::Util::Application::EXIT_SOFTWARE;
            }
            if (KOPSIK_API_SUCCESS != kopsik_push(ctx, err, ERRLEN)) {
                std::cerr << err << std::endl;
            }
            if (te->Description) {
                std::cout << "Stopped: " << te->Description << std::endl;
            } else {
                std::cout << "Stopped." << std::endl;
            }
            kopsik_time_entry_view_item_clear(te);
            return Poco::Util::Application::EXIT_OK;
        }

        if ("list" == args[0]) {
            KopsikTimeEntryViewItemList *list =
                kopsik_time_entry_view_item_list_init();
            if (KOPSIK_API_SUCCESS != kopsik_time_entry_view_items(
                    ctx, err, ERRLEN, list)) {
                std::cerr << err << std::endl;
                kopsik_time_entry_view_item_list_clear(list);
                return Poco::Util::Application::EXIT_SOFTWARE;
            }
            for (unsigned int i = 0; i < list->Length; i++) {
                KopsikTimeEntryViewItem *item = list->ViewItems[i];
                std::cout << "description: " << item->Description
                    << " project: " << item->Project
                    << " duration: " << item->Duration
                    << std::endl;
            }
            std::cout << "Got " << list->Length << " time entry view items."
                << std::endl;
            kopsik_time_entry_view_item_list_clear(list);
            return Poco::Util::Application::EXIT_OK;
        }

        if ("listen" == args[0]) {
            std::cout << "Listening to websocket.. " << std::endl;
            if (KOPSIK_API_SUCCESS != kopsik_listen(ctx, err, ERRLEN)) {
                std::cerr << "Error while listening to websocket: "
                    << err << std::endl;
                return Poco::Util::Application::EXIT_SOFTWARE;
            }
            return Poco::Util::Application::EXIT_OK;
        }

        if ("continue" == args[0]) {
            KopsikTimeEntryViewItemList *list =
                kopsik_time_entry_view_item_list_init();

            if (KOPSIK_API_SUCCESS != kopsik_time_entry_view_items(
                    ctx, err, ERRLEN, list)) {
                std::cerr << err << std::endl;
                kopsik_time_entry_view_item_list_clear(list);
                return Poco::Util::Application::EXIT_SOFTWARE;
            }

            if (!list->Length) {
                std::cout << "No time entry found to continue." << std::endl;
                kopsik_time_entry_view_item_list_clear(list);
                return Poco::Util::Application::EXIT_OK;
            }

            KopsikTimeEntryViewItem *te = kopsik_time_entry_view_item_init();
            if (KOPSIK_API_SUCCESS != kopsik_continue(
                    ctx, err, ERRLEN, list->ViewItems[0]->GUID, te)) {
                std::cerr << err << std::endl;
                kopsik_time_entry_view_item_list_clear(list);
                kopsik_time_entry_view_item_clear(te);
                return Poco::Util::Application::EXIT_SOFTWARE;
            }

            if (KOPSIK_API_SUCCESS != kopsik_push(ctx, err, ERRLEN)) {
                std::cerr << err << std::endl;
            }

            if (te->Description) {
                std::cout << "Started: " << te->Description << std::endl;
            } else {
                std::cout << "Started." << std::endl;
            }

            kopsik_time_entry_view_item_list_clear(list);
            kopsik_time_entry_view_item_clear(te);
            return Poco::Util::Application::EXIT_OK;
        }

        usage();
        return Poco::Util::Application::EXIT_USAGE;
    }
}  // namespace command_line_client
<commit_msg>List TE-s with projects too, in cmd line client<commit_after>// Copyright 2013 Tanel Lebedev

#include "./main.h"

#include <sstream>
#include <iostream> // NOLINT

#include "Poco/Message.h"
#include "Poco/Util/Application.h"

#define ERRLEN 1024

namespace command_line_client {

    void Main::usage() {
        std::cout << "Recognized commands are: "
            "sync, start, stop, status, pushable, list, continue"
            << std::endl;
    }

    void Main::defineOptions(Poco::Util::OptionSet& options) {
        Poco::Util::Application::defineOptions(options);
        options.addOption(Poco::Util::Option(
            "verbose", "v", "verbose logging, to the console"));
    }

    int Main::main(const std::vector<std::string>& args) {
        if (args.empty()) {
            usage();
            return Poco::Util::Application::EXIT_USAGE;
        }

        char* apiToken = getenv("TOGGL_API_TOKEN");
        if (!apiToken) {
            std::cerr << "Please set TOGGL_API_TOKEN in environment" <<
                std::endl;
            return Poco::Util::Application::EXIT_USAGE;
        }

        kopsik_set_db_path(ctx, "kopsik.db");
        kopsik_set_log_path(ctx, "kopsik.log");

        // Start session in lib
        char err[ERRLEN];
        std::fill(err, err + ERRLEN, 0);
        if (KOPSIK_API_SUCCESS != kopsik_set_api_token(
                ctx, err, ERRLEN, apiToken)) {
            std::cerr << err << std::endl;
            return Poco::Util::Application::EXIT_SOFTWARE;
        }

        // Load user that is referenced by the session
        KopsikUser *user = kopsik_user_init();
        if (KOPSIK_API_SUCCESS != kopsik_current_user(
                ctx, err, ERRLEN, user)) {
            std::cerr << err << std::endl;
            return Poco::Util::Application::EXIT_SOFTWARE;
        }
        kopsik_user_clear(user);

        if ("sync" == args[0]) {
            if (KOPSIK_API_SUCCESS != kopsik_sync(ctx, err, ERRLEN, 1)) {
                std::cerr << err << std::endl;
                return Poco::Util::Application::EXIT_SOFTWARE;
            }
            std::cout << "Synced." << std::endl;
            return Poco::Util::Application::EXIT_OK;
        }

        if ("status" == args[0]) {
            KopsikTimeEntryViewItem *te = kopsik_time_entry_view_item_init();
            int found(0);
            if (KOPSIK_API_SUCCESS != kopsik_running_time_entry_view_item(
                    ctx, err, ERRLEN, te, &found)) {
                std::cerr << err << std::endl;
                kopsik_time_entry_view_item_clear(te);
                return Poco::Util::Application::EXIT_SOFTWARE;
            }
            if (found) {
                std::cout << "Tracking: " << te->Description << std::endl;
            } else {
                std::cout << "Not tracking." << std::endl;
            }
            kopsik_time_entry_view_item_clear(te);
            return Poco::Util::Application::EXIT_OK;
        }

        if ("pushable" == args[0]) {
            KopsikPushableModelStats stats;
            if (KOPSIK_API_SUCCESS != kopsik_pushable_models(
                    ctx, err, ERRLEN, &stats)) {
                std::cerr << err << std::endl;
                return Poco::Util::Application::EXIT_SOFTWARE;
            }
            std::cout << stats.TimeEntries << " pushable time entries." << std::endl;
            return Poco::Util::Application::EXIT_OK;
        }

        if ("start" == args[0]) {
            KopsikTimeEntryViewItem *te = kopsik_time_entry_view_item_init();
            if (KOPSIK_API_SUCCESS != kopsik_start(
                    ctx, err, ERRLEN, "New time entry", te)) {
                std::cerr << err << std::endl;
                kopsik_time_entry_view_item_clear(te);
                return Poco::Util::Application::EXIT_SOFTWARE;
            }
            if (KOPSIK_API_SUCCESS != kopsik_push(ctx, err, ERRLEN)) {
                std::cerr << err << std::endl;
            }
            if (te->Description) {
                std::cout << "Started: " << te->Description << std::endl;
            } else {
                std::cout << "Started." << std::endl;
            }
            kopsik_time_entry_view_item_clear(te);
            return Poco::Util::Application::EXIT_OK;
        }

        if ("stop" == args[0]) {
            KopsikTimeEntryViewItem *te = kopsik_time_entry_view_item_init();
            if (KOPSIK_API_SUCCESS != kopsik_stop(
                    ctx, err, ERRLEN, te)) {
                std::cerr << err << std::endl;
                kopsik_time_entry_view_item_clear(te);
                return Poco::Util::Application::EXIT_SOFTWARE;
            }
            if (KOPSIK_API_SUCCESS != kopsik_push(ctx, err, ERRLEN)) {
                std::cerr << err << std::endl;
            }
            if (te->Description) {
                std::cout << "Stopped: " << te->Description << std::endl;
            } else {
                std::cout << "Stopped." << std::endl;
            }
            kopsik_time_entry_view_item_clear(te);
            return Poco::Util::Application::EXIT_OK;
        }

        if ("list" == args[0]) {
            KopsikTimeEntryViewItemList *list =
                kopsik_time_entry_view_item_list_init();
            if (KOPSIK_API_SUCCESS != kopsik_time_entry_view_items(
                    ctx, err, ERRLEN, list)) {
                std::cerr << err << std::endl;
                kopsik_time_entry_view_item_list_clear(list);
                return Poco::Util::Application::EXIT_SOFTWARE;
            }
            for (unsigned int i = 0; i < list->Length; i++) {
                KopsikTimeEntryViewItem *item = list->ViewItems[i];
                std::stringstream ss;
                ss << "description: " << item->Description;
                if (item->Project) {
                    ss << " project: " << item->Project;
                }
                if (item->Duration) {
                    ss << " duration: " << item->Duration;
                }
                std::cout << ss.str() << std::endl;
            }
            std::cout << "Got " << list->Length << " time entry view items."
                << std::endl;
            kopsik_time_entry_view_item_list_clear(list);
            return Poco::Util::Application::EXIT_OK;
        }

        if ("listen" == args[0]) {
            std::cout << "Listening to websocket.. " << std::endl;
            if (KOPSIK_API_SUCCESS != kopsik_listen(ctx, err, ERRLEN)) {
                std::cerr << "Error while listening to websocket: "
                    << err << std::endl;
                return Poco::Util::Application::EXIT_SOFTWARE;
            }
            return Poco::Util::Application::EXIT_OK;
        }

        if ("continue" == args[0]) {
            KopsikTimeEntryViewItemList *list =
                kopsik_time_entry_view_item_list_init();

            if (KOPSIK_API_SUCCESS != kopsik_time_entry_view_items(
                    ctx, err, ERRLEN, list)) {
                std::cerr << err << std::endl;
                kopsik_time_entry_view_item_list_clear(list);
                return Poco::Util::Application::EXIT_SOFTWARE;
            }

            if (!list->Length) {
                std::cout << "No time entry found to continue." << std::endl;
                kopsik_time_entry_view_item_list_clear(list);
                return Poco::Util::Application::EXIT_OK;
            }

            KopsikTimeEntryViewItem *te = kopsik_time_entry_view_item_init();
            if (KOPSIK_API_SUCCESS != kopsik_continue(
                    ctx, err, ERRLEN, list->ViewItems[0]->GUID, te)) {
                std::cerr << err << std::endl;
                kopsik_time_entry_view_item_list_clear(list);
                kopsik_time_entry_view_item_clear(te);
                return Poco::Util::Application::EXIT_SOFTWARE;
            }

            if (KOPSIK_API_SUCCESS != kopsik_push(ctx, err, ERRLEN)) {
                std::cerr << err << std::endl;
            }

            if (te->Description) {
                std::cout << "Started: " << te->Description << std::endl;
            } else {
                std::cout << "Started." << std::endl;
            }

            kopsik_time_entry_view_item_list_clear(list);
            kopsik_time_entry_view_item_clear(te);
            return Poco::Util::Application::EXIT_OK;
        }

        usage();
        return Poco::Util::Application::EXIT_USAGE;
    }
}  // namespace command_line_client
<|endoftext|>


<commit_before>// Copyright (c) 2014, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include <nix/valid/validator.hpp>
#include <nix/valid/checks.hpp>
#include <nix/valid/conditions.hpp>
#include <nix/valid/result.hpp>

#include <nix.hpp>

namespace nix {
namespace valid {

// ---------------------------------------------------------------------
// Templated, hidden validation utils that are only here in the cpp,
// not in the header (hides them from user)
// ---------------------------------------------------------------------

/**
  * @brief base entity validator
  *
  * Function taking a base entity and returning {@link Result} object
  *
  * @param entity base entity
  *
  * @returns The validation results as {@link Result} object
  */
template<typename T>
Result validate_entity(const base::Entity<T> &entity) {
    return validator({
        must(entity, &base::Entity<T>::id, notEmpty(), "id is not set!"),
        must(entity, &base::Entity<T>::createdAt, notFalse(), "date is not set!")
    });
}

/**
  * @brief base named entity validator
  *
  * Function taking a base named entity and returning {@link Result}
  * object
  *
  * @param named_entity base named entity
  *
  * @returns The validation results as {@link Result} object
  */
template<typename T>
Result validate_named_entity(const base::NamedEntity<T> &named_entity) {
    Result result_base = validate_entity<T>(named_entity);
    Result result = validator({
        must(named_entity, &base::NamedEntity<T>::name, notEmpty(), "no name set!"),
        must(named_entity, &base::NamedEntity<T>::type, notEmpty(), "no type set!")
    });

    return result.concat(result_base);
}

/**
  * @brief base entity with metadata validator
  *
  * Function taking a base entity with metadata and returning
  * {@link Result} object
  *
  * @param entity_with_metadata base entity with metadata
  *
  * @returns The validation results as {@link Result} object
  */
template<typename T>
Result validate_entity_with_metadata(const base::EntityWithMetadata<T> &entity_with_metadata) {
    return validate_named_entity<T>(entity_with_metadata);
}

/**
  * @brief base entity with sources validator
  *
  * Function taking a base entity with sources and returning
  * {@link Result} object
  *
  * @param entity_with_sources base entity with sources
  *
  * @returns The validation results as {@link Result} object
  */
template<typename T>
Result validate_entity_with_sources(const base::EntityWithSources<T> &entity_with_sources) {
    return validate_entity_with_metadata<T>(entity_with_sources);
}

// ---------------------------------------------------------------------
// Regular validaton utils split in header & cpp part
// ---------------------------------------------------------------------

Result validate(const Block &block) {
    return validate_entity_with_metadata(block);
}

Result validate(const DataArray &data_array) {
    Result result_base = validate_entity_with_sources(data_array);
    Result result = validator({
        must(data_array, &DataArray::dataType, notEqual<DataType>(DataType::Nothing), "data type is not set!"),
        must(data_array, &DataArray::dimensionCount, isEqual<size_t>(data_array.dataExtent().size()), "data dimensionality does not match number of defined dimensions!", {
            could(data_array, &DataArray::dimensions, notEmpty(), {
                must(data_array, &DataArray::dimensions, dimTicksMatchData(data_array), "in some of the Range dimensions the number of ticks differs from the number of data entries along the corresponding data dimension!"),
                must(data_array, &DataArray::dimensions, dimLabelsMatchData(data_array), "in some of the Set dimensions the number of labels differs from the number of data entries along the corresponding data dimension!") }) }),
        could(data_array, &DataArray::unit, notFalse(), {
            must(data_array, &DataArray::unit, isValidUnit(), "Unit is not SI or composite of SI units.") }),
        could(data_array, &DataArray::polynomCoefficients, notEmpty(), {
            should(data_array, &DataArray::expansionOrigin, notFalse(), "polynomial coefficients for calibration are set, but expansion origin is missing!") }),
        could(data_array, &DataArray::expansionOrigin, notFalse(), {
            should(data_array, &DataArray::polynomCoefficients, notEmpty(), "expansion origin for calibration is set, but polynomial coefficients are missing!") })
    });

    return result.concat(result_base);
}

Result validate(const Tag &tag) {
    Result result_base = validate_entity_with_sources(tag);
    Result result = validator({
        must(tag, &Tag::position, notEmpty(), "position is not set!"),
        could(tag, &Tag::references, notEmpty(), {
            must(tag, &Tag::position, positionsMatchRefs(tag.references()),
                "number of entries in position does not match number of dimensions in all referenced DataArrays!"),
            could(tag, &Tag::extent, notEmpty(), {
                must(tag, &Tag::position, extentsMatchPositions(tag.extent()), "Number of entries in position and extent do not match!"),
                must(tag, &Tag::extent, extentsMatchRefs(tag.references()),
                    "number of entries in extent does not match number of dimensions in all referenced DataArrays!") })
        }),
        // check units for validity
        could(tag, &Tag::units, notEmpty(), {
            must(tag, &Tag::units, isValidUnit(), "Unit is invalid: not an atomic SI. Note: So far composite units are not supported!"),
            must(tag, &Tag::references, tagRefsHaveUnits(tag.units()), "Some of the referenced DataArrays' dimensions don't have units where the tag has. Make sure that all references have the same number of dimensions as the tag has units and that each dimension has a unit set."),
                must(tag, &Tag::references, tagUnitsMatchRefsUnits(tag.units()), "Some of the referenced DataArrays' dimensions have units that are not convertible to the units set in tag. Note: So far composite SI units are not supported!")}),
    });

    return result.concat(result_base);
}

Result validate(const Property &property) {
    Result result_base = validate_entity(property);
    Result result = validator({
        must(property, &Property::name, notEmpty(), "name is not set!"),
        could(property, &Property::valueCount, notFalse(), {
            should(property, &Property::unit, notFalse(), "values are set, but unit is missing!") }),
        could(property, &Property::unit, notFalse(), {
            must(property, &Property::unit, isValidUnit(), "Unit is not SI or composite of SI units.") })
        // TODO: dataType to be tested too?
    });

    return result.concat(result_base);
}

Result validate(const MultiTag &multi_tag) {
    Result result_base = validate_entity_with_sources(multi_tag);
    Result result = validator({
        must(multi_tag, &MultiTag::positions, notFalse(), "positions are not set!"),
        // since extents & positions DataArray stores a vector of position / extent vectors it has to be 2-dim
        could(multi_tag, &MultiTag::positions, notFalse(), {
            must(multi_tag, &MultiTag::positions, dimEquals(2), "dimensionality of positions DataArray must be two!") }),
        could(multi_tag, &MultiTag::extents, notFalse(), {
            must(multi_tag, &MultiTag::extents, dimEquals(2), "dimensionality of extents DataArray must be two!") }),
        // check units for validity
        could(multi_tag, &MultiTag::units, notEmpty(), {
            must(multi_tag, &MultiTag::units, isValidUnit(), "Some of the units in tag are invalid: not an atomic SI. Note: So far composite SI units are not supported!"),
            must(multi_tag, &MultiTag::references, tagUnitsMatchRefsUnits(multi_tag.units()), "Some of the referenced DataArrays' dimensions have units that are not convertible to the units set in tag. Note: So far composite SI units are not supported!")}),
        // check positions & extents
        could(multi_tag, &MultiTag::extents, notFalse(), {
            must(multi_tag, &MultiTag::positions, extentsMatchPositions(multi_tag.extents()), "Number of entries in positions and extents do not match!") }),
        could(multi_tag, &MultiTag::references, notEmpty(), {
            could(multi_tag, &MultiTag::extents, notFalse(), {
                must(multi_tag, &MultiTag::extents, extentsMatchRefs(multi_tag.references()), "number of entries (in 2nd dim) in extents does not match number of dimensions in all referenced DataArrays!") }),
            must(multi_tag, &MultiTag::positions, positionsMatchRefs(multi_tag.references()), "number of entries (in 2nd dim) in positions does not match number of dimensions in all referenced DataArrays!") })
    });

    return result.concat(result_base);
}

Result validate(const Dimension &dim) {
    return validator({
        must(dim, &Dimension::index, notSmaller(1), "index is not set to valid value (> 0)!")
    });
}

Result validate(const RangeDimension &range_dim) {
    return validator({
        must(range_dim, &RangeDimension::index, notSmaller(1), "index is not set to valid value (size_t > 0)!"),
        must(range_dim, &RangeDimension::ticks, notEmpty(), "ticks are not set!"),
        must(range_dim, &RangeDimension::dimensionType, isEqual<DimensionType>(DimensionType::Range), "dimension type is not correct!"),
        could(range_dim, &RangeDimension::unit, notFalse(), {
            must(range_dim, &RangeDimension::unit, isAtomicUnit(), "Unit is set but not an atomic SI. Note: So far composite units are not supported!") }),
        must(range_dim, &RangeDimension::ticks, isSorted(), "Ticks are not sorted!")
    });
}

Result validate(const SampledDimension &sampled_dim) {
    return validator({
        must(sampled_dim, &SampledDimension::index, notSmaller(1), "index is not set to valid value (size_t > 0)!"),
        must(sampled_dim, &SampledDimension::samplingInterval, isGreater(0), "samplingInterval is not set to valid value (> 0)!"),
        must(sampled_dim, &SampledDimension::dimensionType, isEqual<DimensionType>(DimensionType::Sample), "dimension type is not correct!"),
        could(sampled_dim, &SampledDimension::offset, notFalse(), {
            should(sampled_dim, &SampledDimension::unit, isAtomicUnit(), "offset is set, but no valid unit set!") }),
        could(sampled_dim, &SampledDimension::unit, notFalse(), {
            must(sampled_dim, &SampledDimension::unit, isAtomicUnit(), "Unit is set but not an atomic SI. Note: So far composite units are not supported!") })
    });
}

Result validate(const SetDimension &set_dim) {
    return validator({
        must(set_dim, &SetDimension::index, notSmaller(1), "index is not set to valid value (size_t > 0)!"),
        must(set_dim, &SetDimension::dimensionType, isEqual<DimensionType>(DimensionType::Set), "dimension type is not correct!")
    });
}

Result validate(const Feature &feature) {
    Result result_base = validate_entity(feature);
    Result result = validator({
        must(feature, &Feature::data, notFalse(), "data is not set!"),
        must(feature, &Feature::linkType, notSmaller(0), "linkType is not set!")
    });

    return result.concat(result_base);
}

Result validate(const Section &section) {
    return validate_named_entity(section);
}

Result validate(const Source &source) {
    return validate_entity_with_metadata(source);
}

Result validate(const File &file) {
    return validator({
        could(file, &File::isOpen, notFalse(), {
            must(file, &File::createdAt, notFalse(), "date is not set!"),
            should(file, &File::version, notEmpty(), "version is not set!"),
            should(file, &File::format, notEmpty(), "format is not set!"),
            should(file, &File::location, notEmpty(), "location is not set!") })
    });
}

} // namespace valid
} // namespace nix
<commit_msg>[validator] remove check on positions/ext dims ==2<commit_after>// Copyright (c) 2014, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include <nix/valid/validator.hpp>
#include <nix/valid/checks.hpp>
#include <nix/valid/conditions.hpp>
#include <nix/valid/result.hpp>

#include <nix.hpp>

namespace nix {
namespace valid {

// ---------------------------------------------------------------------
// Templated, hidden validation utils that are only here in the cpp,
// not in the header (hides them from user)
// ---------------------------------------------------------------------

/**
  * @brief base entity validator
  *
  * Function taking a base entity and returning {@link Result} object
  *
  * @param entity base entity
  *
  * @returns The validation results as {@link Result} object
  */
template<typename T>
Result validate_entity(const base::Entity<T> &entity) {
    return validator({
        must(entity, &base::Entity<T>::id, notEmpty(), "id is not set!"),
        must(entity, &base::Entity<T>::createdAt, notFalse(), "date is not set!")
    });
}

/**
  * @brief base named entity validator
  *
  * Function taking a base named entity and returning {@link Result}
  * object
  *
  * @param named_entity base named entity
  *
  * @returns The validation results as {@link Result} object
  */
template<typename T>
Result validate_named_entity(const base::NamedEntity<T> &named_entity) {
    Result result_base = validate_entity<T>(named_entity);
    Result result = validator({
        must(named_entity, &base::NamedEntity<T>::name, notEmpty(), "no name set!"),
        must(named_entity, &base::NamedEntity<T>::type, notEmpty(), "no type set!")
    });

    return result.concat(result_base);
}

/**
  * @brief base entity with metadata validator
  *
  * Function taking a base entity with metadata and returning
  * {@link Result} object
  *
  * @param entity_with_metadata base entity with metadata
  *
  * @returns The validation results as {@link Result} object
  */
template<typename T>
Result validate_entity_with_metadata(const base::EntityWithMetadata<T> &entity_with_metadata) {
    return validate_named_entity<T>(entity_with_metadata);
}

/**
  * @brief base entity with sources validator
  *
  * Function taking a base entity with sources and returning
  * {@link Result} object
  *
  * @param entity_with_sources base entity with sources
  *
  * @returns The validation results as {@link Result} object
  */
template<typename T>
Result validate_entity_with_sources(const base::EntityWithSources<T> &entity_with_sources) {
    return validate_entity_with_metadata<T>(entity_with_sources);
}

// ---------------------------------------------------------------------
// Regular validaton utils split in header & cpp part
// ---------------------------------------------------------------------

Result validate(const Block &block) {
    return validate_entity_with_metadata(block);
}

Result validate(const DataArray &data_array) {
    Result result_base = validate_entity_with_sources(data_array);
    Result result = validator({
        must(data_array, &DataArray::dataType, notEqual<DataType>(DataType::Nothing), "data type is not set!"),
        must(data_array, &DataArray::dimensionCount, isEqual<size_t>(data_array.dataExtent().size()), "data dimensionality does not match number of defined dimensions!", {
            could(data_array, &DataArray::dimensions, notEmpty(), {
                must(data_array, &DataArray::dimensions, dimTicksMatchData(data_array), "in some of the Range dimensions the number of ticks differs from the number of data entries along the corresponding data dimension!"),
                must(data_array, &DataArray::dimensions, dimLabelsMatchData(data_array), "in some of the Set dimensions the number of labels differs from the number of data entries along the corresponding data dimension!") }) }),
        could(data_array, &DataArray::unit, notFalse(), {
            must(data_array, &DataArray::unit, isValidUnit(), "Unit is not SI or composite of SI units.") }),
        could(data_array, &DataArray::polynomCoefficients, notEmpty(), {
            should(data_array, &DataArray::expansionOrigin, notFalse(), "polynomial coefficients for calibration are set, but expansion origin is missing!") }),
        could(data_array, &DataArray::expansionOrigin, notFalse(), {
            should(data_array, &DataArray::polynomCoefficients, notEmpty(), "expansion origin for calibration is set, but polynomial coefficients are missing!") })
    });

    return result.concat(result_base);
}

Result validate(const Tag &tag) {
    Result result_base = validate_entity_with_sources(tag);
    Result result = validator({
        must(tag, &Tag::position, notEmpty(), "position is not set!"),
        could(tag, &Tag::references, notEmpty(), {
            must(tag, &Tag::position, positionsMatchRefs(tag.references()),
                "number of entries in position does not match number of dimensions in all referenced DataArrays!"),
            could(tag, &Tag::extent, notEmpty(), {
                must(tag, &Tag::position, extentsMatchPositions(tag.extent()), "Number of entries in position and extent do not match!"),
                must(tag, &Tag::extent, extentsMatchRefs(tag.references()),
                    "number of entries in extent does not match number of dimensions in all referenced DataArrays!") })
        }),
        // check units for validity
        could(tag, &Tag::units, notEmpty(), {
            must(tag, &Tag::units, isValidUnit(), "Unit is invalid: not an atomic SI. Note: So far composite units are not supported!"),
            must(tag, &Tag::references, tagRefsHaveUnits(tag.units()), "Some of the referenced DataArrays' dimensions don't have units where the tag has. Make sure that all references have the same number of dimensions as the tag has units and that each dimension has a unit set."),
                must(tag, &Tag::references, tagUnitsMatchRefsUnits(tag.units()), "Some of the referenced DataArrays' dimensions have units that are not convertible to the units set in tag. Note: So far composite SI units are not supported!")}),
    });

    return result.concat(result_base);
}

Result validate(const Property &property) {
    Result result_base = validate_entity(property);
    Result result = validator({
        must(property, &Property::name, notEmpty(), "name is not set!"),
        could(property, &Property::valueCount, notFalse(), {
            should(property, &Property::unit, notFalse(), "values are set, but unit is missing!") }),
        could(property, &Property::unit, notFalse(), {
            must(property, &Property::unit, isValidUnit(), "Unit is not SI or composite of SI units.") })
        // TODO: dataType to be tested too?
    });

    return result.concat(result_base);
}

Result validate(const MultiTag &multi_tag) {
    Result result_base = validate_entity_with_sources(multi_tag);
    Result result = validator({
        must(multi_tag, &MultiTag::positions, notFalse(), "positions are not set!"),
        // check units for validity
        could(multi_tag, &MultiTag::units, notEmpty(), {
            must(multi_tag, &MultiTag::units, isValidUnit(), "Some of the units in tag are invalid: not an atomic SI. Note: So far composite SI units are not supported!"),
            must(multi_tag, &MultiTag::references, tagUnitsMatchRefsUnits(multi_tag.units()), "Some of the referenced DataArrays' dimensions have units that are not convertible to the units set in tag. Note: So far composite SI units are not supported!")}),
        // check positions & extents
        could(multi_tag, &MultiTag::extents, notFalse(), {
            must(multi_tag, &MultiTag::positions, extentsMatchPositions(multi_tag.extents()), "Number of entries in positions and extents do not match!") }),
        could(multi_tag, &MultiTag::references, notEmpty(), {
            could(multi_tag, &MultiTag::extents, notFalse(), {
                must(multi_tag, &MultiTag::extents, extentsMatchRefs(multi_tag.references()), "number of entries (in 2nd dim) in extents does not match number of dimensions in all referenced DataArrays!") }),
            must(multi_tag, &MultiTag::positions, positionsMatchRefs(multi_tag.references()), "number of entries (in 2nd dim) in positions does not match number of dimensions in all referenced DataArrays!") })
    });

    return result.concat(result_base);
}

Result validate(const Dimension &dim) {
    return validator({
        must(dim, &Dimension::index, notSmaller(1), "index is not set to valid value (> 0)!")
    });
}

Result validate(const RangeDimension &range_dim) {
    return validator({
        must(range_dim, &RangeDimension::index, notSmaller(1), "index is not set to valid value (size_t > 0)!"),
        must(range_dim, &RangeDimension::ticks, notEmpty(), "ticks are not set!"),
        must(range_dim, &RangeDimension::dimensionType, isEqual<DimensionType>(DimensionType::Range), "dimension type is not correct!"),
        could(range_dim, &RangeDimension::unit, notFalse(), {
            must(range_dim, &RangeDimension::unit, isAtomicUnit(), "Unit is set but not an atomic SI. Note: So far composite units are not supported!") }),
        must(range_dim, &RangeDimension::ticks, isSorted(), "Ticks are not sorted!")
    });
}

Result validate(const SampledDimension &sampled_dim) {
    return validator({
        must(sampled_dim, &SampledDimension::index, notSmaller(1), "index is not set to valid value (size_t > 0)!"),
        must(sampled_dim, &SampledDimension::samplingInterval, isGreater(0), "samplingInterval is not set to valid value (> 0)!"),
        must(sampled_dim, &SampledDimension::dimensionType, isEqual<DimensionType>(DimensionType::Sample), "dimension type is not correct!"),
        could(sampled_dim, &SampledDimension::offset, notFalse(), {
            should(sampled_dim, &SampledDimension::unit, isAtomicUnit(), "offset is set, but no valid unit set!") }),
        could(sampled_dim, &SampledDimension::unit, notFalse(), {
            must(sampled_dim, &SampledDimension::unit, isAtomicUnit(), "Unit is set but not an atomic SI. Note: So far composite units are not supported!") })
    });
}

Result validate(const SetDimension &set_dim) {
    return validator({
        must(set_dim, &SetDimension::index, notSmaller(1), "index is not set to valid value (size_t > 0)!"),
        must(set_dim, &SetDimension::dimensionType, isEqual<DimensionType>(DimensionType::Set), "dimension type is not correct!")
    });
}

Result validate(const Feature &feature) {
    Result result_base = validate_entity(feature);
    Result result = validator({
        must(feature, &Feature::data, notFalse(), "data is not set!"),
        must(feature, &Feature::linkType, notSmaller(0), "linkType is not set!")
    });

    return result.concat(result_base);
}

Result validate(const Section &section) {
    return validate_named_entity(section);
}

Result validate(const Source &source) {
    return validate_entity_with_metadata(source);
}

Result validate(const File &file) {
    return validator({
        could(file, &File::isOpen, notFalse(), {
            must(file, &File::createdAt, notFalse(), "date is not set!"),
            should(file, &File::version, notEmpty(), "version is not set!"),
            should(file, &File::format, notEmpty(), "format is not set!"),
            should(file, &File::location, notEmpty(), "location is not set!") })
    });
}

} // namespace valid
} // namespace nix
<|endoftext|>


<commit_before>#include "view/SceneView.h"

#include "DotSceneLoader.h"

#include "util/BulletDebugDrawer.h"

#include <OgreRoot.h>
#include <OgreViewport.h>
#include <OgreConfigFile.h>
#include <OgreEntity.h>
#include <OgreWindowEventUtilities.h>

#include <sstream>
#include <string>

#include <btBulletDynamicsCommon.h>

SceneView::SceneView(Rally::Model::World& world) :
        world(world),
        camera(NULL),
        sceneManager(NULL),
        renderWindow(NULL){
        debugDrawEnabled = false;
}

SceneView::~SceneView() {
    //delete bulletDebugDrawer;
    tunnelPortalView.detach();

    playerCarView.detach();

    Ogre::Root* root = Ogre::Root::getSingletonPtr();
    delete root;
}

void SceneView::initialize(std::string resourceConfigPath, std::string pluginConfigPath) {
    Ogre::Root* root = new Ogre::Root(pluginConfigPath);

    this->loadResourceConfig(resourceConfigPath);
    // (The actual precaching is done below, once there is a render context)

    if(!root->restoreConfig() && !root->showConfigDialog()) {
        throw std::runtime_error("Could neither restore Ogre config, nor read it from the user.");
    }

    renderWindow = root->initialise(
        true, // auto-create the render window now
        "Rally Sport Racing Game");

    sceneManager = root->createSceneManager("OctreeSceneManager"); // Todo: Research a good scene manager

    // This should be done after creating a scene manager, so that there is a render context (GL/D3D)
    Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

    sceneManager->setSkyDome(true, "Rally/CloudySky", 5, 8);

    camera = this->addCamera("MainCamera");
    Ogre::Viewport* viewport = this->addViewport(camera);
    camera->setAspectRatio(Ogre::Real(viewport->getActualWidth()) / Ogre::Real(viewport->getActualHeight()));

    Ogre::SceneNode* sceneNode = sceneManager->getRootSceneNode()->createChildSceneNode();
    sceneNode->setPosition(Ogre::Vector3(0, 110.0f, 0));

    // Load the scene.
    DotSceneLoader loader;
    loader.parseDotScene("world.scene", "General", sceneManager, sceneNode);

    sceneManager->setShadowTechnique(Ogre::SHADOWTYPE_STENCIL_ADDITIVE);
    sceneManager->setShadowColour(Ogre::ColourValue(0.5, 0.5, 0.5) );
    sceneManager->setAmbientLight(Ogre::ColourValue(1, 1, 1));

    Ogre::Light* sunLight = sceneManager->createLight("sunLight");
    sunLight->setType(Ogre::Light::LT_DIRECTIONAL);
    sunLight->setCastShadows(true);
    sunLight->setDirection(Ogre::Vector3( 1, -2, 1 ));
    sunLight->setDiffuseColour(Ogre::ColourValue(1, 1, 1));
    sunLight->setSpecularColour(Ogre::ColourValue(1, 1, 1));
    sceneNode->attachObject(sunLight);

	playerCarView.attachTo(sceneManager);

	goalView.attachTo(sceneManager, "Goal", "car.mesh", world.getGoal());

    // Debug draw Bullet
    bulletDebugDrawer = new Rally::Util::BulletDebugDrawer(sceneManager);
    world.getPhysicsWorld().getDynamicsWorld()->setDebugDrawer(bulletDebugDrawer);

	// Sky dome
	//sceneManager->setSkyDome(true, "Rally/CloudySky", 5, 8, 1000, true);

	sceneManager->setSkyDome(true, "Rally/CloudySky", 5, 8);

	// Place the magic surface at the end of the tunnel.
	tunnelPortalView.attachTo(sceneManager, "TunnelPortal");
	tunnelPortalView.setScale(15.0f, 5.0f, true);
    tunnelPortalView.setPosition(Rally::Vector3(86.0f, 12.0f, -134.0f));
    tunnelPortalView.setOrientation(Rally::Quaternion(Ogre::Math::Sqrt(0.5f), 0, -Ogre::Math::Sqrt(0.5f), 0));

    // Snap a picture for the magic surface at Kopparbunken.
	tunnelPortalView.moveCamera(
        Rally::Vector3(255.0f, 12.0f, 240.0f), // position
        Rally::Vector3(255.0f, 12.0f, 239.0f)); // look at
    tunnelPortalView.takeSnapshot();
}

Ogre::Viewport* SceneView::addViewport(Ogre::Camera* followedCamera) {
    Ogre::Viewport* viewport = renderWindow->addViewport(camera);
    viewport->setBackgroundColour(Ogre::ColourValue(0, 0, 0));

    return viewport;
}

Ogre::Camera* SceneView::addCamera(Ogre::String cameraName) {
    // Setup camera to match viewport
    Ogre::Camera* camera = sceneManager->createCamera(cameraName);
	camera->setNearClipDistance(Ogre::Real(0.1));

    return camera;
}

void SceneView::loadResourceConfig(Ogre::String resourceConfigPath) {
    Ogre::ResourceGroupManager& resourceGroupManager = Ogre::ResourceGroupManager::getSingleton();

    Ogre::ConfigFile resourceConfig;
    resourceConfig.load(resourceConfigPath);

    for(Ogre::ConfigFile::SectionIterator sectionIterator = resourceConfig.getSectionIterator();
            sectionIterator.hasMoreElements();
            sectionIterator.moveNext()) {
        Ogre::ConfigFile::SettingsMultiMap* settings = sectionIterator.peekNextValue();

        // Now load all the resources for this resource group
        for(Ogre::ConfigFile::SettingsMultiMap::iterator resource = settings->begin();
                resource != settings->end();
                ++resource) {
            resourceGroupManager.addResourceLocation(
                resource->second, // filename of directory
                resource->first, // resource type
                sectionIterator.peekNextKey()); // resource group
        }
    }
}

bool SceneView::renderFrame(float deltaTime) {
    Ogre::WindowEventUtilities::messagePump();

    if(renderWindow->isClosed())  {
        return false;
    } else {
        updatePlayerCar(deltaTime);
        updateRemoteCars();
		//updateCheckPoints();

    if(debugDrawEnabled){
        world.getPhysicsWorld().getDynamicsWorld()->debugDrawWorld();
    }

        Ogre::Root& root = Ogre::Root::getSingleton();
        if(!root.renderOneFrame()) {
            return false;
        }
    }
    return true;
}

void SceneView::updatePlayerCar(float deltaTime) {
    // Todo: Move to separate view
    Rally::Model::Car& playerCar = world.getPlayerCar();
    Rally::Vector3 position = playerCar.getPosition();
    playerCarView.updateBody(playerCar.getPosition(), playerCar.getOrientation());
    playerCarView.updateWheels(
        playerCar.getRightFrontWheelOrientation(),
        playerCar.getLeftFrontWheelOrientation(),
        playerCar.getRightBackWheelOrientation(),
        playerCar.getLeftBackWheelOrientation());

	Rally::Vector3 currentCameraPosition = camera->getPosition();

	Rally::Vector3 displacementBase = playerCar.getOrientation() * Ogre::Vector3::UNIT_Z;
	displacementBase *= -1;

	float xzdisplacement = 6.5f;
	float ydisplacement = 3.0f;

	Rally::Vector3 displacement(xzdisplacement * displacementBase.x,
		ydisplacement,
		xzdisplacement * displacementBase.z);

    Rally::Vector3 endPosition = position + displacement;

	float velocityAdjust = playerCar.getVelocity().length()/6;
	float lerpAdjust = Ogre::Math::Clamp(velocityAdjust*deltaTime, 0.01f, 0.25f);

	// Lerp towards the new camera position to get a smoother pan
	float lerpX = Ogre::Math::lerp(currentCameraPosition.x, endPosition.x, lerpAdjust);
	float lerpY = Ogre::Math::lerp(currentCameraPosition.y, endPosition.y, lerpAdjust);
	float lerpZ = Ogre::Math::lerp(currentCameraPosition.z, endPosition.z, lerpAdjust);

	Rally::Vector3 newPos(lerpX, lerpY, lerpZ);
	Rally::Vector3 cameraPosition = newPos;

	/*
	Shoot a ray from the car (with an offset to prevent collision with itself) to the camera.
	If anyting is intersected the camera is adjusted to prevent that the camera is blocked.
	*/
	btVector3 start(position.x, position.y + 2.0f, position.z);
	btVector3 end(newPos.x, newPos.y, newPos.z);

	btCollisionWorld::ClosestRayResultCallback ClosestRayResultCallBack(start, end);

	// Perform raycast
	world.getPhysicsWorld().getDynamicsWorld()->getCollisionWorld()->rayTest(start, end, ClosestRayResultCallBack);

	if(ClosestRayResultCallBack.hasHit()) {
		btVector3 hitLoc = ClosestRayResultCallBack.m_hitPointWorld;

		//If the camera is blocked, the new camera is set to where the collison
		//happened with a tiny offset.
		cameraPosition = Rally::Vector3(hitLoc.getX(), hitLoc.getY(), hitLoc.getZ());

		float camOffset = 0.5f;

		//Adjust for X
		if(hitLoc.getX() > cameraPosition.x)
			cameraPosition += Rally::Vector3(-camOffset, 0.0f, 0.0f);
		else if(hitLoc.getX() < cameraPosition.x)
			cameraPosition += Rally::Vector3(camOffset, 0.0f, 0.0f);

		//Adjust for Y
		if(hitLoc.getY() > cameraPosition.y)
			cameraPosition += Rally::Vector3(0.0f, -camOffset, 0.0f);

		//Adjust for Z
		if(hitLoc.getZ() > cameraPosition.z)
			cameraPosition += Rally::Vector3(0.0f, 0.0f, -camOffset);
		else if(hitLoc.getZ() < cameraPosition.z)
			cameraPosition += Rally::Vector3(0.0f, 0.0f, camOffset);

	}

    camera->setPosition(cameraPosition);
	camera->lookAt(position);

    // This is a bit of a temporary hack... It is laggy though...
    /*Rally::Vector3 lookVector = (Rally::Vector3(255.0f, 12.0f, 240.0f) - Rally::Vector3(255.0f, 12.0f, 239.0f))*
        (cameraPosition - Rally::Vector3(86.0f, 12.0f, -134.0f)).length();
	tunnelPortalView.moveCamera(
        Rally::Vector3(255.0f, 12.0f, 240.0f) + lookVector, // position
        Rally::Vector3(255.0f, 12.0f, 239.0f) + lookVector); // look at
    tunnelPortalView.takeSnapshot();*/
}

void SceneView::updateRemoteCars() {
    for(std::map<int, Rally::View::RemoteCarView>::iterator carViewIterator = remoteCarViews.begin();
            carViewIterator != remoteCarViews.end();
            ++carViewIterator) {
        carViewIterator->second.updateWithRemoteCar();
    }
}

void SceneView::updateCheckPoints() {
	//goalView.update();
}

void SceneView::remoteCarUpdated(int carId, const Rally::Model::RemoteCar& remoteCar) {
    std::map<int, Rally::View::RemoteCarView>::iterator found = remoteCarViews.find(carId);

    // Lazily construct if not found
    if(found == remoteCarViews.end()) {
        found = remoteCarViews.insert(std::map<int, Rally::View::RemoteCarView>::value_type(carId,
            Rally::View::RemoteCarView(remoteCar))).first;
        std::ostringstream carNameStream;
        carNameStream << "RemoteCar_" << carId;
        std::string carName = carNameStream.str();

        found->second.attachTo(sceneManager, carName);
    }

    // We don't really update the car here, as it has to be done every frame for the interpolation.
}

void SceneView::remoteCarRemoved(int carId, const Rally::Model::RemoteCar& remoteCar) {
    remoteCarViews.erase(carId);
}

void SceneView::setDebugDrawEnabled(bool enabled){
    debugDrawEnabled = enabled;
}

void SceneView::toggleReflections() {
    playerCarView.setReflectionsOn(!playerCarView.isReflectionsOn());
}
<commit_msg>Fixed merge error and adjusted camera displacement<commit_after>#include "view/SceneView.h"

#include "DotSceneLoader.h"

#include "util/BulletDebugDrawer.h"

#include <OgreRoot.h>
#include <OgreViewport.h>
#include <OgreConfigFile.h>
#include <OgreEntity.h>
#include <OgreWindowEventUtilities.h>

#include <sstream>
#include <string>

#include <btBulletDynamicsCommon.h>

SceneView::SceneView(Rally::Model::World& world) :
        world(world),
        camera(NULL),
        sceneManager(NULL),
        renderWindow(NULL){
        debugDrawEnabled = false;
}

SceneView::~SceneView() {
    //delete bulletDebugDrawer;
    tunnelPortalView.detach();

    playerCarView.detach();

    Ogre::Root* root = Ogre::Root::getSingletonPtr();
    delete root;
}

void SceneView::initialize(std::string resourceConfigPath, std::string pluginConfigPath) {
    Ogre::Root* root = new Ogre::Root(pluginConfigPath);

    this->loadResourceConfig(resourceConfigPath);
    // (The actual precaching is done below, once there is a render context)

    if(!root->restoreConfig() && !root->showConfigDialog()) {
        throw std::runtime_error("Could neither restore Ogre config, nor read it from the user.");
    }

    renderWindow = root->initialise(
        true, // auto-create the render window now
        "Rally Sport Racing Game");

    sceneManager = root->createSceneManager("OctreeSceneManager"); // Todo: Research a good scene manager

    // This should be done after creating a scene manager, so that there is a render context (GL/D3D)
    Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

    sceneManager->setSkyDome(true, "Rally/CloudySky", 5, 8);

    camera = this->addCamera("MainCamera");
    Ogre::Viewport* viewport = this->addViewport(camera);
    camera->setAspectRatio(Ogre::Real(viewport->getActualWidth()) / Ogre::Real(viewport->getActualHeight()));

    Ogre::SceneNode* sceneNode = sceneManager->getRootSceneNode()->createChildSceneNode();
    sceneNode->setPosition(Ogre::Vector3(0, 110.0f, 0));

    // Load the scene.
    DotSceneLoader loader;
    loader.parseDotScene("world.scene", "General", sceneManager, sceneNode);

    sceneManager->setShadowTechnique(Ogre::SHADOWTYPE_STENCIL_ADDITIVE);
    sceneManager->setShadowColour(Ogre::ColourValue(0.5, 0.5, 0.5) );
    sceneManager->setAmbientLight(Ogre::ColourValue(1, 1, 1));

    Ogre::Light* sunLight = sceneManager->createLight("sunLight");
    sunLight->setType(Ogre::Light::LT_DIRECTIONAL);
    sunLight->setCastShadows(true);
    sunLight->setDirection(Ogre::Vector3( 1, -2, 1 ));
    sunLight->setDiffuseColour(Ogre::ColourValue(1, 1, 1));
    sunLight->setSpecularColour(Ogre::ColourValue(1, 1, 1));
    sceneNode->attachObject(sunLight);

	playerCarView.attachTo(sceneManager);

	goalView.attachTo(sceneManager, "Goal", "car.mesh", world.getGoal());

    // Debug draw Bullet
    bulletDebugDrawer = new Rally::Util::BulletDebugDrawer(sceneManager);
    world.getPhysicsWorld().getDynamicsWorld()->setDebugDrawer(bulletDebugDrawer);

	// Sky dome
	//sceneManager->setSkyDome(true, "Rally/CloudySky", 5, 8, 1000, true);

	sceneManager->setSkyDome(true, "Rally/CloudySky", 5, 8);

	// Place the magic surface at the end of the tunnel.
	tunnelPortalView.attachTo(sceneManager, "TunnelPortal");
	tunnelPortalView.setScale(15.0f, 5.0f, true);
    tunnelPortalView.setPosition(Rally::Vector3(86.0f, 12.0f, -134.0f));
    tunnelPortalView.setOrientation(Rally::Quaternion(Ogre::Math::Sqrt(0.5f), 0, -Ogre::Math::Sqrt(0.5f), 0));

    // Snap a picture for the magic surface at Kopparbunken.
	tunnelPortalView.moveCamera(
        Rally::Vector3(255.0f, 12.0f, 240.0f), // position
        Rally::Vector3(255.0f, 12.0f, 239.0f)); // look at
    tunnelPortalView.takeSnapshot();
}

Ogre::Viewport* SceneView::addViewport(Ogre::Camera* followedCamera) {
    Ogre::Viewport* viewport = renderWindow->addViewport(camera);
    viewport->setBackgroundColour(Ogre::ColourValue(0, 0, 0));

    return viewport;
}

Ogre::Camera* SceneView::addCamera(Ogre::String cameraName) {
    // Setup camera to match viewport
    Ogre::Camera* camera = sceneManager->createCamera(cameraName);
	camera->setNearClipDistance(Ogre::Real(0.1));

    return camera;
}

void SceneView::loadResourceConfig(Ogre::String resourceConfigPath) {
    Ogre::ResourceGroupManager& resourceGroupManager = Ogre::ResourceGroupManager::getSingleton();

    Ogre::ConfigFile resourceConfig;
    resourceConfig.load(resourceConfigPath);

    for(Ogre::ConfigFile::SectionIterator sectionIterator = resourceConfig.getSectionIterator();
            sectionIterator.hasMoreElements();
            sectionIterator.moveNext()) {
        Ogre::ConfigFile::SettingsMultiMap* settings = sectionIterator.peekNextValue();

        // Now load all the resources for this resource group
        for(Ogre::ConfigFile::SettingsMultiMap::iterator resource = settings->begin();
                resource != settings->end();
                ++resource) {
            resourceGroupManager.addResourceLocation(
                resource->second, // filename of directory
                resource->first, // resource type
                sectionIterator.peekNextKey()); // resource group
        }
    }
}

bool SceneView::renderFrame(float deltaTime) {
    Ogre::WindowEventUtilities::messagePump();

    if(renderWindow->isClosed())  {
        return false;
    } else {
        updatePlayerCar(deltaTime);
        updateRemoteCars();
		//updateCheckPoints();

    if(debugDrawEnabled){
        world.getPhysicsWorld().getDynamicsWorld()->debugDrawWorld();
    }

        Ogre::Root& root = Ogre::Root::getSingleton();
        if(!root.renderOneFrame()) {
            return false;
        }
    }
    return true;
}

void SceneView::updatePlayerCar(float deltaTime) {
    // Todo: Move to separate view
    Rally::Model::Car& playerCar = world.getPlayerCar();
    Rally::Vector3 position = playerCar.getPosition();
    playerCarView.updateBody(playerCar.getPosition(), playerCar.getOrientation());
    playerCarView.updateWheels(
        playerCar.getRightFrontWheelOrientation(),
        playerCar.getLeftFrontWheelOrientation(),
        playerCar.getRightBackWheelOrientation(),
        playerCar.getLeftBackWheelOrientation());

	Rally::Vector3 currentCameraPosition = camera->getPosition();

	Rally::Vector3 displacementBase = playerCar.getOrientation() * Ogre::Vector3::UNIT_Z;
	displacementBase *= -1;

	float xzdisplacement = 7.0f;
	float ydisplacement = 3.0f;

	Rally::Vector3 displacement(
		xzdisplacement * displacementBase.x,
		ydisplacement,
		xzdisplacement * displacementBase.z);

    Rally::Vector3 endPosition = position + displacement;

	float velocityAdjust = playerCar.getVelocity().length()/6;
	float lerpAdjust = Ogre::Math::Clamp(velocityAdjust*deltaTime, 0.01f, 0.25f);

	// Lerp towards the new camera position to get a smoother pan
	float lerpX = Ogre::Math::lerp(currentCameraPosition.x, endPosition.x, lerpAdjust);
	float lerpY = Ogre::Math::lerp(currentCameraPosition.y, endPosition.y, lerpAdjust);
	float lerpZ = Ogre::Math::lerp(currentCameraPosition.z, endPosition.z, lerpAdjust);

	Rally::Vector3 newPos(lerpX, lerpY, lerpZ);
	Rally::Vector3 cameraPosition = newPos;

	/*
	Shoot a ray from the car (with an offset to prevent collision with itself) to the camera.
	If anyting is intersected the camera is adjusted to prevent that the camera is blocked.
	*/
	btVector3 start(position.x, position.y + 2.0f, position.z);
	btVector3 end(newPos.x, newPos.y, newPos.z);

	btCollisionWorld::ClosestRayResultCallback ClosestRayResultCallBack(start, end);

	// Perform raycast
	world.getPhysicsWorld().getDynamicsWorld()->getCollisionWorld()->rayTest(start, end, ClosestRayResultCallBack);

	if(ClosestRayResultCallBack.hasHit()) {
		btVector3 hitLoc = ClosestRayResultCallBack.m_hitPointWorld;

		//If the camera is blocked, the new camera is set to where the collison
		//happened with a tiny offset.
		cameraPosition = Rally::Vector3(hitLoc.getX(), hitLoc.getY(), hitLoc.getZ());

		float camOffset = 0.5f;

		//Adjust for X
		if(hitLoc.getX() > cameraPosition.x)
			cameraPosition += Rally::Vector3(-camOffset, 0.0f, 0.0f);
		else if(hitLoc.getX() < cameraPosition.x)
			cameraPosition += Rally::Vector3(camOffset, 0.0f, 0.0f);

		//Adjust for Y
		if(hitLoc.getY() > cameraPosition.y)
			cameraPosition += Rally::Vector3(0.0f, -camOffset, 0.0f);

		//Adjust for Z
		if(hitLoc.getZ() > cameraPosition.z)
			cameraPosition += Rally::Vector3(0.0f, 0.0f, -camOffset);
		else if(hitLoc.getZ() < cameraPosition.z)
			cameraPosition += Rally::Vector3(0.0f, 0.0f, camOffset);

	}

    camera->setPosition(cameraPosition);
	camera->lookAt(position);

    // This is a bit of a temporary hack... It is laggy though...
    /*Rally::Vector3 lookVector = (Rally::Vector3(255.0f, 12.0f, 240.0f) - Rally::Vector3(255.0f, 12.0f, 239.0f))*
        (cameraPosition - Rally::Vector3(86.0f, 12.0f, -134.0f)).length();
	tunnelPortalView.moveCamera(
        Rally::Vector3(255.0f, 12.0f, 240.0f) + lookVector, // position
        Rally::Vector3(255.0f, 12.0f, 239.0f) + lookVector); // look at
    tunnelPortalView.takeSnapshot();*/
}

void SceneView::updateRemoteCars() {
    for(std::map<int, Rally::View::RemoteCarView>::iterator carViewIterator = remoteCarViews.begin();
            carViewIterator != remoteCarViews.end();
            ++carViewIterator) {
        carViewIterator->second.updateWithRemoteCar();
    }
}

void SceneView::updateCheckPoints() {
	//goalView.update();
}

void SceneView::remoteCarUpdated(int carId, const Rally::Model::RemoteCar& remoteCar) {
    std::map<int, Rally::View::RemoteCarView>::iterator found = remoteCarViews.find(carId);

    // Lazily construct if not found
    if(found == remoteCarViews.end()) {
        found = remoteCarViews.insert(std::map<int, Rally::View::RemoteCarView>::value_type(carId,
            Rally::View::RemoteCarView(remoteCar))).first;
        std::ostringstream carNameStream;
        carNameStream << "RemoteCar_" << carId;
        std::string carName = carNameStream.str();

        found->second.attachTo(sceneManager, carName);
    }

    // We don't really update the car here, as it has to be done every frame for the interpolation.
}

void SceneView::remoteCarRemoved(int carId, const Rally::Model::RemoteCar& remoteCar) {
    remoteCarViews.erase(carId);
}

void SceneView::setDebugDrawEnabled(bool enabled){
    debugDrawEnabled = enabled;
}

void SceneView::toggleReflections() {
    playerCarView.setReflectionsOn(!playerCarView.isReflectionsOn());
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <string>

#include <QDir>
#include <QFileDialog>
#include <QFileInfoList>
#include <QList>
#include <QMessageBox>
#include <QProcess>
#include <QTextStream>
#include <QVariant>

#include "api.h"
#include "apiprocess.h"
#include "cpp_utils.h"
#include "Exif.h"

using namespace std;

APIProcess *process;

API::API(const std::string &rootdir) : rootdir(rootdir) {
}

void API::setFrame(QWebFrame *frame) {
  this->frame = frame;
}

void API::setWindow(MainWindow *mainwindow) {
	this->mainwindow = mainwindow;
}

void API::evaluateJavaScript(const QString & scriptSource) {
  frame->evaluateJavaScript(scriptSource);
}

bool API::closeApp() {
	QVariant v = frame->evaluateJavaScript("isSafeToClose();");
	return v.toBool();
}

void API::doCloseApp() {
        qApp->quit();
}

void API::openBrowser(QString url) {
#if defined Q_WS_WIN
        url = "file:///"+url;
        // search whether user has chrome installed
        QSettings brwCH("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\chrome.exe",QSettings::NativeFormat);
        QString brwPath = brwCH.value( "Default", "0" ).toString();
        if(brwPath!="0") {
                QProcess::startDetached(brwPath, QStringList() << "--allow-file-access-from-files" << url);
                return;
        }

        // search whether user has safari installed
        QSettings brwSA("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Safari.exe",QSettings::NativeFormat);
        brwPath = brwSA.value( "Default", "0" ).toString();
        if(brwPath!="0") {
                QProcess::startDetached(brwPath, QStringList() << url);
                return;
        }

        // tell user that they don't have any compatible browser and exit
        QMessageBox::critical(mainwindow,tr("No Browser"),tr("There is no compatible browser installed on this computer.\nYou need either Chrome or Safari in order to view your time machine."));
        return;

// TODO: must be tested on MAC
#elif defined Q_WS_MAC
        url = "file://"+url;
        if(QFileInfo("/Applications/Google Chrome.app").exists())
                QProcess::startDetached("/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", QStringList() << "--allow-file-access-from-files" << url);
        else if(QFileInfo("/Applications/Safari.app").exists())
                QProcess::startDetached("/Applications/Safari.app/Contents/MacOS/Safari", QStringList() << url);
        else
                QDesktopServices::openUrl(url);

// TODO: must be tested on Linux
#else
        QProcess process;
        process.setReadChannel(QProcess::StandardOutput);
        process.setReadChannelMode(QProcess::MergedChannels);
        process.start("type -p chromium");

        process.waitForStarted(1000);
        process.waitForFinished(1000);

        QByteArray list = process.readAll();

        // if there is chromium installed
        if(list.length()>0)
        {
                QProcess::startDetached(list, QStringList() << url);
                return;
        }

        process.start("type -p google-chrome");

        process.waitForStarted(1000);
        process.waitForFinished(1000);

        list = process.readAll();

        // if there is google-chrome installed
        if(list.length()>0)
        {
                QProcess::startDetached(list, QStringList() << url);
                return;
        }

        // go with the default browser
        QDesktopServices::openUrl(url);
#endif
}

void API::setUndoMenu(bool state) {
	mainwindow->setUndoMenu(state);
}

void API::setRedoMenu(bool state) {
	mainwindow->setRedoMenu(state);
}

void API::setNewProjectMenu(bool state) {
	mainwindow->setNewProjectMenu(state);
}

void API::setOpenProjectMenu(bool state) {
	mainwindow->setOpenProjectMenu(state);
}

void API::setSaveMenu(bool state) {
	mainwindow->setSaveMenu(state);
}

void API::setSaveAsMenu(bool state) {
	mainwindow->setSaveAsMenu(state);
}

void API::setAddImagesMenu(bool state) {
	mainwindow->setAddImagesMenu(state);
}

void API::setAddFoldersMenu(bool state) {
	mainwindow->setAddFoldersMenu(state);
}

void API::setRecentlyAddedMenu(bool state) {
        mainwindow->setRecentlyAddedMenu(state);
}

int API::log() {
  fprintf(stderr, "log!\n");
  QVariantList args;
  args << "hello";
  args << 33;
  requestCallback(44, args);
  return 33;
}

void API::addJSObject() {
  frame->addToJavaScriptWindowObject(QString("_api"), this);
}

// readThumbnail:
// Example
//
//

QPixmap API::readThumbnail(QString path) {
  try {
    string path_utf8 = path.toUtf8().constData();

    FILE *in = fopen_utf8(path_utf8, "rb"); //was rw
    EXIF_ASSERT(in, ExifErr() << "Can't read " << path_utf8);
    ExifView exif(path_utf8);
    size_t offset = exif.get_thumbnail_location();
    int32 length;
    exif.query_by_tag(EXIF_ThumbnailLength, length);
    EXIF_ASSERT(length > 0, ExifErr() << "Illegal thumbnail length");
    vector<unsigned char> buf(length);
    EXIF_ASSERT(fseek(in, offset, SEEK_SET) == 0, ExifErr() << "Error reading thumbnail");
    //EXIF_ASSERT(1 == (int32)fread(&buf[0], length, 1, in), ExifErr() << "Error reading thumbnail");
    fread(&buf[0], length, 1, in);
    fclose(in);

    QPixmap ret;
    ret.loadFromData(&buf[0], length);

    return ret;
  } catch (ExifErr &e) {
    fprintf(stderr, "ExifErr: %s\n", e.what());
    return QPixmap();
  }
}

double API::exifTime(QString path) {
  try {
    string path_utf8 = path.toUtf8().constData();
    ExifView exif(path_utf8);
    ExifDateTime capture_time = exif.get_capture_time();
    struct tm tm;
    memset(&tm, 0, sizeof(tm));
    tm.tm_year = capture_time.m_year - 1900;
    tm.tm_mon = capture_time.m_month - 1;
    tm.tm_mday = capture_time.m_day;
    tm.tm_hour = capture_time.m_hour;
    tm.tm_min = capture_time.m_minute;
    tm.tm_sec = capture_time.m_second;
    double seconds = (double) mktime(&tm);

    int32 hundredths = 0;
    try {
      exif.query_by_tag(EXIF_SubSecTimeDigitized, hundredths);
    } catch (ExifErr &) {}

    return seconds + hundredths / 100.0;
  } catch (ExifErr &e) {
    fprintf(stderr, "ExifErr: %s\n", e.what());
    // Would be nicer to return null here, but don't know how to do that
    return -1.0;
  }
}

QStringList listDirectoryRecursively(QString path) {
  QStringList ret;
  QFileInfoList dir = QDir(path).entryInfoList();
  for (int i = 0; i < dir.length(); i++) {
    if (dir[i].fileName() == "." || dir[i].fileName() == "..") {
      // ignore
    } else if (dir[i].isDir()) {
      ret << listDirectoryRecursively(dir[i].absoluteFilePath());
    } else {
      ret << dir[i].absoluteFilePath();
    }
  }
  return ret;
}

void API::dropPaths(QStringList paths) {
  droppedPaths = paths;
}

void API::requestCallback(int id, QVariantList args) {
  emit callback(id, args);
}

QStringList API::droppedFilesRecursive() {

  QStringList ret;
  for (int i = 0; i < droppedPaths.length(); i++) {
    //fprintf(stderr, "dfr: >%s<\n", droppedPaths[i].toUtf8().constData());
    QFileInfo info(droppedPaths[i]);
    if (info.isDir()) {
      ret << listDirectoryRecursively(droppedPaths[i]);
    } else {
      ret << info.absoluteFilePath();
    }
  }
  ret.removeDuplicates();
  ret.sort();
  return ret;
}

// filter, e.g. "*.tmc"
QString API::saveAsDialog(QString caption, QString startingDirectory, QString filter) {
  return QFileDialog::getSaveFileName(NULL, caption, startingDirectory, filter);
}

bool API::writeFile(QString path, QString data)
{
  QFile file(path);
  if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
    return false;
  }
  QTextStream(&file) << data;
  mainwindow->setCurrentFile(path);
  return true;
}

QString API::readFileDialog(QString caption, QString startingDirectory, QString filter)
{
  QString path = QFileDialog::getOpenFileName(NULL, caption, startingDirectory, filter);
  return readFile(path);
}

QString API::readFile(QString path)
{
  if(path != "") {
    QFile file(path);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) return ""; // null would be better
    openedProject = path;
    mainwindow->setCurrentFile(path);
    return QTextStream(&file).readAll();
  }
  return NULL;
}

QString API::getOpenedProjectPath()
{
	return openedProject;
}

bool API::makeDirectory(QString path)
{
  return QDir().mkdir(path);
}

bool API::makeFullDirectoryPath(QString path)
{
  return QDir().mkpath(path);
}

bool API::fileExists(QString path)
{
  return QDir().exists(path);
}

bool API::invokeRubySubprocess(QStringList args, int callback_id)
{
  fprintf(stderr, "invokeRubySubprocess:");
  for (int i = 0; i < args.length(); i++) {
    fprintf(stderr, " %s", args[i].toUtf8().constData());
  }
  fprintf(stderr, "\n");
  process = new APIProcess(this, callback_id);

  // Ruby path
  std::string ruby_path;

  if (os() == "windows") {
    ruby_path = rootdir + "/ruby/windows/bin/ruby.exe";
  } else {
    ruby_path = "/usr/bin/ruby";
  }

  fprintf(stderr, "Invoking ruby with path '%s'\n", ruby_path.c_str());
  process->process.start(ruby_path.c_str(), args, QIODevice::ReadOnly);
  return true;
}

bool API::killSubprocess() {
  process->process.kill();
  return true;
}

QString API::getRootAppPath()
{
        return QString::fromStdString(rootdir);
}
<commit_msg>searches for chromium-browser too<commit_after>#include <stdio.h>
#include <string>

#include <QDir>
#include <QFileDialog>
#include <QFileInfoList>
#include <QList>
#include <QMessageBox>
#include <QProcess>
#include <QTextStream>
#include <QVariant>

#include "api.h"
#include "apiprocess.h"
#include "cpp_utils.h"
#include "Exif.h"

using namespace std;

APIProcess *process;

API::API(const std::string &rootdir) : rootdir(rootdir) {
}

void API::setFrame(QWebFrame *frame) {
  this->frame = frame;
}

void API::setWindow(MainWindow *mainwindow) {
	this->mainwindow = mainwindow;
}

void API::evaluateJavaScript(const QString & scriptSource) {
  frame->evaluateJavaScript(scriptSource);
}

bool API::closeApp() {
	QVariant v = frame->evaluateJavaScript("isSafeToClose();");
	return v.toBool();
}

void API::doCloseApp() {
        qApp->quit();
}

void API::openBrowser(QString url) {
#if defined Q_WS_WIN
        url = "file:///"+url;
        // search whether user has chrome installed
        QSettings brwCH("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\chrome.exe",QSettings::NativeFormat);
        QString brwPath = brwCH.value( "Default", "0" ).toString();
        if(brwPath!="0") {
                QProcess::startDetached(brwPath, QStringList() << "--allow-file-access-from-files" << url);
                return;
        }

        // search whether user has safari installed
        QSettings brwSA("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Safari.exe",QSettings::NativeFormat);
        brwPath = brwSA.value( "Default", "0" ).toString();
        if(brwPath!="0") {
                QProcess::startDetached(brwPath, QStringList() << url);
                return;
        }

        // tell user that they don't have any compatible browser and exit
        QMessageBox::critical(mainwindow,tr("No Browser"),tr("There is no compatible browser installed on this computer.\nYou need either Chrome or Safari in order to view your time machine."));
        return;

// TODO: must be tested on MAC
#elif defined Q_WS_MAC
        url = "file://"+url;
        if(QFileInfo("/Applications/Google Chrome.app").exists())
                QProcess::startDetached("/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", QStringList() << "--allow-file-access-from-files" << url);
        else if(QFileInfo("/Applications/Safari.app").exists())
                QProcess::startDetached("/Applications/Safari.app/Contents/MacOS/Safari", QStringList() << url);
        else
                QDesktopServices::openUrl(url);

// TODO: must be tested on Linux
#else
        QProcess process;
        process.setReadChannel(QProcess::StandardOutput);
        process.setReadChannelMode(QProcess::MergedChannels);
        process.start("type -p chromium");

        process.waitForStarted(1000);
        process.waitForFinished(1000);

        QByteArray list = process.readAll();

        // if there is chromium installed
        if(list.length()>0)
        {
                QProcess::startDetached(list, QStringList() << url);
                return;
        }

		process.start("type -p chromium-browser");

        process.waitForStarted(1000);
        process.waitForFinished(1000);

        list = process.readAll();

        // if there is chromium-browser installed
        if(list.length()>0)
        {
                QProcess::startDetached(list, QStringList() << url);
                return;
        }

        process.start("type -p google-chrome");

        process.waitForStarted(1000);
        process.waitForFinished(1000);

        list = process.readAll();

        // if there is google-chrome installed
        if(list.length()>0)
        {
                QProcess::startDetached(list, QStringList() << url);
                return;
        }

        // go with the default browser
        QDesktopServices::openUrl(url);
#endif
}

void API::setUndoMenu(bool state) {
	mainwindow->setUndoMenu(state);
}

void API::setRedoMenu(bool state) {
	mainwindow->setRedoMenu(state);
}

void API::setNewProjectMenu(bool state) {
	mainwindow->setNewProjectMenu(state);
}

void API::setOpenProjectMenu(bool state) {
	mainwindow->setOpenProjectMenu(state);
}

void API::setSaveMenu(bool state) {
	mainwindow->setSaveMenu(state);
}

void API::setSaveAsMenu(bool state) {
	mainwindow->setSaveAsMenu(state);
}

void API::setAddImagesMenu(bool state) {
	mainwindow->setAddImagesMenu(state);
}

void API::setAddFoldersMenu(bool state) {
	mainwindow->setAddFoldersMenu(state);
}

void API::setRecentlyAddedMenu(bool state) {
        mainwindow->setRecentlyAddedMenu(state);
}

int API::log() {
  fprintf(stderr, "log!\n");
  QVariantList args;
  args << "hello";
  args << 33;
  requestCallback(44, args);
  return 33;
}

void API::addJSObject() {
  frame->addToJavaScriptWindowObject(QString("_api"), this);
}

// readThumbnail:
// Example
//
//

QPixmap API::readThumbnail(QString path) {
  try {
    string path_utf8 = path.toUtf8().constData();

    FILE *in = fopen_utf8(path_utf8, "rb"); //was rw
    EXIF_ASSERT(in, ExifErr() << "Can't read " << path_utf8);
    ExifView exif(path_utf8);
    size_t offset = exif.get_thumbnail_location();
    int32 length;
    exif.query_by_tag(EXIF_ThumbnailLength, length);
    EXIF_ASSERT(length > 0, ExifErr() << "Illegal thumbnail length");
    vector<unsigned char> buf(length);
    EXIF_ASSERT(fseek(in, offset, SEEK_SET) == 0, ExifErr() << "Error reading thumbnail");
    //EXIF_ASSERT(1 == (int32)fread(&buf[0], length, 1, in), ExifErr() << "Error reading thumbnail");
    fread(&buf[0], length, 1, in);
    fclose(in);

    QPixmap ret;
    ret.loadFromData(&buf[0], length);

    return ret;
  } catch (ExifErr &e) {
    fprintf(stderr, "ExifErr: %s\n", e.what());
    return QPixmap();
  }
}

double API::exifTime(QString path) {
  try {
    string path_utf8 = path.toUtf8().constData();
    ExifView exif(path_utf8);
    ExifDateTime capture_time = exif.get_capture_time();
    struct tm tm;
    memset(&tm, 0, sizeof(tm));
    tm.tm_year = capture_time.m_year - 1900;
    tm.tm_mon = capture_time.m_month - 1;
    tm.tm_mday = capture_time.m_day;
    tm.tm_hour = capture_time.m_hour;
    tm.tm_min = capture_time.m_minute;
    tm.tm_sec = capture_time.m_second;
    double seconds = (double) mktime(&tm);

    int32 hundredths = 0;
    try {
      exif.query_by_tag(EXIF_SubSecTimeDigitized, hundredths);
    } catch (ExifErr &) {}

    return seconds + hundredths / 100.0;
  } catch (ExifErr &e) {
    fprintf(stderr, "ExifErr: %s\n", e.what());
    // Would be nicer to return null here, but don't know how to do that
    return -1.0;
  }
}

QStringList listDirectoryRecursively(QString path) {
  QStringList ret;
  QFileInfoList dir = QDir(path).entryInfoList();
  for (int i = 0; i < dir.length(); i++) {
    if (dir[i].fileName() == "." || dir[i].fileName() == "..") {
      // ignore
    } else if (dir[i].isDir()) {
      ret << listDirectoryRecursively(dir[i].absoluteFilePath());
    } else {
      ret << dir[i].absoluteFilePath();
    }
  }
  return ret;
}

void API::dropPaths(QStringList paths) {
  droppedPaths = paths;
}

void API::requestCallback(int id, QVariantList args) {
  emit callback(id, args);
}

QStringList API::droppedFilesRecursive() {

  QStringList ret;
  for (int i = 0; i < droppedPaths.length(); i++) {
    //fprintf(stderr, "dfr: >%s<\n", droppedPaths[i].toUtf8().constData());
    QFileInfo info(droppedPaths[i]);
    if (info.isDir()) {
      ret << listDirectoryRecursively(droppedPaths[i]);
    } else {
      ret << info.absoluteFilePath();
    }
  }
  ret.removeDuplicates();
  ret.sort();
  return ret;
}

// filter, e.g. "*.tmc"
QString API::saveAsDialog(QString caption, QString startingDirectory, QString filter) {
  return QFileDialog::getSaveFileName(NULL, caption, startingDirectory, filter);
}

bool API::writeFile(QString path, QString data)
{
  QFile file(path);
  if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
    return false;
  }
  QTextStream(&file) << data;
  mainwindow->setCurrentFile(path);
  return true;
}

QString API::readFileDialog(QString caption, QString startingDirectory, QString filter)
{
  QString path = QFileDialog::getOpenFileName(NULL, caption, startingDirectory, filter);
  return readFile(path);
}

QString API::readFile(QString path)
{
  if(path != "") {
    QFile file(path);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) return ""; // null would be better
    openedProject = path;
    mainwindow->setCurrentFile(path);
    return QTextStream(&file).readAll();
  }
  return NULL;
}

QString API::getOpenedProjectPath()
{
	return openedProject;
}

bool API::makeDirectory(QString path)
{
  return QDir().mkdir(path);
}

bool API::makeFullDirectoryPath(QString path)
{
  return QDir().mkpath(path);
}

bool API::fileExists(QString path)
{
  return QDir().exists(path);
}

bool API::invokeRubySubprocess(QStringList args, int callback_id)
{
  fprintf(stderr, "invokeRubySubprocess:");
  for (int i = 0; i < args.length(); i++) {
    fprintf(stderr, " %s", args[i].toUtf8().constData());
  }
  fprintf(stderr, "\n");
  process = new APIProcess(this, callback_id);

  // Ruby path
  std::string ruby_path;

  if (os() == "windows") {
    ruby_path = rootdir + "/ruby/windows/bin/ruby.exe";
  } else {
    ruby_path = "/usr/bin/ruby";
  }

  fprintf(stderr, "Invoking ruby with path '%s'\n", ruby_path.c_str());
  process->process.start(ruby_path.c_str(), args, QIODevice::ReadOnly);
  return true;
}

bool API::killSubprocess() {
  process->process.kill();
  return true;
}

QString API::getRootAppPath()
{
        return QString::fromStdString(rootdir);
}
<|endoftext|>


<commit_before>/* Copyright (c) 2015, Rice University

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

1.  Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.
2.  Redistributions in binary form must reproduce the above
     copyright notice, this list of conditions and the following
     disclaimer in the documentation and/or other materials provided
     with the distribution.
3.  Neither the name of Rice University
     nor the names of its contributors may be used to endorse or
     promote products derived from this software without specific
     prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

 */

/*
 * hcpp-runtime.cpp
 *
 *      Author: Vivek Kumar (vivekk@rice.edu)
 *      Acknowledgments: https://wiki.rice.edu/confluence/display/HABANERO/People
 */

#include "hcpp-internal.h"
#include <stdio.h>

namespace hcpp {

// Control debug statements
#define DEBUG_DDF 0

#define EMPTY_DATUM_ERROR_MSG "can not put sentinel value for \"uninitialized\" as a value into DDF"

// For 'headDDTWaitList' when a DDF has been satisfied
#define DDF_SATISFIED NULL

// Default value of a DDF datum
#define UNINITIALIZED_DDF_DATA_PTR NULL

// For waiting frontier (last element of the list)
#define UNINITIALIZED_DDF_WAITLIST_PTR ((struct ddt_st *) -1)

/**
 * Associate a DDT to a DDF list.
 */
void ddt_init(ddt_t * ddt, ddf_t ** ddf_list) {
	ddt->waitingFrontier = ddf_list;
	ddt->nextDDTWaitingOnSameDDF = NULL;
}

/**
 * Allocate a DDF and initializes it.
 */
ddf_t * ddf_create() {
	ddf_t * ddf = (ddf_t *) malloc(sizeof(ddf_t));
	ddf-> kind = DDF_KIND_SHARED;
	ddf->datum = NULL;
	ddf->headDDTWaitList = UNINITIALIZED_DDF_WAITLIST_PTR;
	return ddf;
}

/**
 * Initialize a pre-Allocated DDF.
 */
void ddf_create_preinit(DDF_t* ddf) {
	ddf-> kind = DDF_KIND_SHARED;
	ddf->datum = NULL;
	ddf->headDDTWaitList = UNINITIALIZED_DDF_WAITLIST_PTR;
}

/**
 * Allocate 'nb_ddfs' DDFs in contiguous memory.
 */
ddf_t ** ddf_create_n(size_t nb_ddfs, int null_terminated) {
	ddf_t ** ddfs = (ddf_t **) malloc((sizeof(ddf_t*) * nb_ddfs));
	int i = 0;
	int lg = (null_terminated) ? nb_ddfs-1 : nb_ddfs;
	while(i < lg) {
		ddfs[i] = ddf_create();
		i++;
	}
	if (null_terminated) {
		ddfs[lg] = NULL;
	}
	return ddfs;
}

/**
 * @brief Destruct a DDF.
 * @param[in] nb_ddfs                           Size of the DDF array
 * @param[in] null_terminated           If true, create nb_ddfs-1 and set the last element to NULL.
 * @param[in] ddf                               The DDF to destruct
 */
void ddf_free_n(ddf_t ** ddfs, size_t nb_ddfs, int null_terminated) {
	int i = 0;
	int lg = (null_terminated) ? nb_ddfs-1 : nb_ddfs;
	while(i < lg) {
		ddf_free(ddfs[i]);
		i++;
	}
	free(ddfs);
}

/**
 * Deallocate a ddf pointer
 */
void ddf_free(ddf_t * ddf) {
	free(ddf);
}

static int register_if_ddf_not_ready(ddt_t * ddt, ddf_t * ddf) {
	int registered = 0;
	ddt_t * headDDTWaitList = (ddt_t *) ddf->headDDTWaitList;
	if (DEBUG_DDF) {
		printf("ddf: register_if_ddf_not_ready ddt = %p, ddf = %p \n", ddt, ddf);
	}
	while (headDDTWaitList != DDF_SATISFIED && !registered) {
		/* headDDTWaitList can not be DDF_SATISFIED in here */
		ddt->nextDDTWaitingOnSameDDF = headDDTWaitList;

		// Try to add the ddt to the ddf's list of ddts waiting.
		registered = __sync_bool_compare_and_swap(&(ddf->headDDTWaitList),
				headDDTWaitList, ddt);

		/* may have failed because either some other task tried to be the head or a put occurred. */
		if (!registered) {
			headDDTWaitList = (ddt_t *) ddf->headDDTWaitList;
			/* if waitListOfDDF was set to DDF_SATISFIED, the loop condition will handle that
			 * if another task was added, now try to add in front of that
			 */
		}
	}
	if (DEBUG_DDF && registered) {
		printf("ddf: %p registered %p as headDDT of ddf %p\n", ddt, ddf->headDDTWaitList, ddf);
	}
	return registered;
}

/**
 * Runtime interface to DDTs.
 * Returns '1' if all ddf dependencies have been satisfied.
 */
int iterate_ddt_frontier(ddt_t * ddt) {
	ddf_t ** currentDDF = ddt->waitingFrontier;

	if (DEBUG_DDF) {
		printf("ddf: Trying to iterate ddt %p, frontier ddf is %p \n", ddt, currentDDF);
	}
	// Try and register on ddf until one is not ready.
	while ((*currentDDF) && !register_if_ddf_not_ready(ddt, *currentDDF)) {
		++currentDDF;
	}
	// Here we either:
	// - Have hit a ddf not ready (i.e. no 'put' on this one yet)
	// - iterated over the whole list (i.e. all 'put' must have happened)
	if (DEBUG_DDF) { printf("ddf: iterate result %d\n", (*currentDDF == NULL)); }
	ddt->waitingFrontier = currentDDF;
	return (*currentDDF == NULL);
}

//
// Task conversion Implementation
//

int iterate_ddt_frontier(ddt_t * ddt);

task_t * rt_ddt_to_async_task(ddt_t * ddt) {
    task_t* t = &(((task_t *)ddt)[-1]);
    return t;
}

ddt_t * rt_async_task_to_ddt(task_t * async_task) {
    return &(((hcpp_task_t*) async_task)->ddt);
}

/**
 * Get datum from a DDF.
 * Note: this is concurrent with the 'put' operation.
 */
void * ddf_get(ddf_t * ddf) {
	if (ddf->datum == UNINITIALIZED_DDF_DATA_PTR) {
		return NULL;
	}
	return (void *) ddf->datum;
}

/**
 * Put datum in the DDF.
 * Close down registration of DDTs on this DDF and iterate over the
 * DDF's frontier to try to advance DDTs that were waiting on this DDF.
 */
void ddf_put(ddf_t * ddf, void * datum) {
	HASSERT(datum != UNINITIALIZED_DDF_DATA_PTR && EMPTY_DATUM_ERROR_MSG);
	HASSERT(ddf != NULL && "error: can't DDF is a pointer to NULL");
	//TODO Limitation: not enough to guarantee single assignment
	if (DEBUG_DDF) { printf("ddf: put datum %p\n", ddf->datum); }
	HASSERT(ddf->datum == NULL && "error: violated single assignment property for DDFs");

	volatile ddt_t * headDDTWaitList = NULL;
	ddf->datum = datum;
	headDDTWaitList = ddf->headDDTWaitList;
	if (DEBUG_DDF) { printf("ddf: Retrieve ddf %p head's ddt %p\n", ddf, headDDTWaitList); }
	// Try to cas the wait list to prevent new DDTs from registering on this ddf.
	// When cas successed, new DDTs see the DDF has been satisfied and proceed.
	while (!__sync_bool_compare_and_swap(&(ddf->headDDTWaitList),
			(struct ddt_st *) headDDTWaitList, DDF_SATISFIED )) {
		headDDTWaitList = ddf->headDDTWaitList;
	}
	if (DEBUG_DDF) {
		printf("ddf: Put successful on ddf %p set head's ddf to %p\n", ddf, ddf->headDDTWaitList);
	}
	// Now iterate over the list of DDTs, and try to advance their frontier.
	ddt_t * currDDT = (ddt_t *) headDDTWaitList;
	while (currDDT != UNINITIALIZED_DDF_WAITLIST_PTR) {
		if (DEBUG_DDF) { printf("ddf: Trying to iterate frontier of ddt %p\n", currDDT); }
		if (iterate_ddt_frontier(currDDT)) {
			// DDT eligible to scheduling
			task_t * async_task = rt_ddt_to_async_task(currDDT);
			if (DEBUG_DDF) { printf("ddf: async_task %p\n", async_task); }
			try_schedule_async(async_task, 0);
		}
		currDDT = currDDT->nextDDTWaitingOnSameDDF;
	}
}

}
<commit_msg>fix ddf bug<commit_after>/* Copyright (c) 2015, Rice University

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

1.  Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.
2.  Redistributions in binary form must reproduce the above
     copyright notice, this list of conditions and the following
     disclaimer in the documentation and/or other materials provided
     with the distribution.
3.  Neither the name of Rice University
     nor the names of its contributors may be used to endorse or
     promote products derived from this software without specific
     prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

 */

/*
 * hcpp-runtime.cpp
 *
 *      Author: Vivek Kumar (vivekk@rice.edu)
 *      Acknowledgments: https://wiki.rice.edu/confluence/display/HABANERO/People
 */

#include "hcpp-internal.h"
#include <stdio.h>

namespace hcpp {

// Control debug statements
#define DEBUG_DDF 0

#define EMPTY_DATUM_ERROR_MSG "can not put sentinel value for \"uninitialized\" as a value into DDF"

// For 'headDDTWaitList' when a DDF has been satisfied
#define DDF_SATISFIED NULL

// Default value of a DDF datum
#define UNINITIALIZED_DDF_DATA_PTR NULL

// For waiting frontier (last element of the list)
#define UNINITIALIZED_DDF_WAITLIST_PTR ((struct ddt_st *) -1)
#define EMPTY_DDF_WAITLIST_PTR NULL

/**
 * Associate a DDT to a DDF list.
 */
void ddt_init(ddt_t * ddt, ddf_t ** ddf_list) {
	ddt->waitingFrontier = ddf_list;
	ddt->nextDDTWaitingOnSameDDF = NULL;
}

/**
 * Allocate a DDF and initializes it.
 */
ddf_t * ddf_create() {
	ddf_t * ddf = (ddf_t *) malloc(sizeof(ddf_t));
	ddf-> kind = DDF_KIND_SHARED;
	ddf->datum = UNINITIALIZED_DDF_DATA_PTR;
	ddf->headDDTWaitList = UNINITIALIZED_DDF_WAITLIST_PTR;
	return ddf;
}

/**
 * Initialize a pre-Allocated DDF.
 */
void ddf_create_preinit(DDF_t* ddf) {
	ddf-> kind = DDF_KIND_SHARED;
	ddf->datum = UNINITIALIZED_DDF_DATA_PTR;
	ddf->headDDTWaitList = UNINITIALIZED_DDF_WAITLIST_PTR;
}

/**
 * Allocate 'nb_ddfs' DDFs in contiguous memory.
 */
ddf_t ** ddf_create_n(size_t nb_ddfs, int null_terminated) {
	ddf_t ** ddfs = (ddf_t **) malloc((sizeof(ddf_t*) * nb_ddfs));
	int i = 0;
	int lg = (null_terminated) ? nb_ddfs-1 : nb_ddfs;
	while(i < lg) {
		ddfs[i] = ddf_create();
		i++;
	}
	if (null_terminated) {
		ddfs[lg] = NULL;
	}
	return ddfs;
}

/**
 * Get datum from a DDF.
 * Note: this is concurrent with the 'put' operation.
 */
void * ddf_get(ddf_t * ddf) {
	if (ddf->datum == UNINITIALIZED_DDF_DATA_PTR) {
		return NULL;
	}
	return (void *) ddf->datum;
}

/**
 * @brief Destruct a DDF.
 * @param[in] nb_ddfs                           Size of the DDF array
 * @param[in] null_terminated           If true, create nb_ddfs-1 and set the last element to NULL.
 * @param[in] ddf                               The DDF to destruct
 */
void ddf_free_n(ddf_t ** ddfs, size_t nb_ddfs, int null_terminated) {
	int i = 0;
	int lg = (null_terminated) ? nb_ddfs-1 : nb_ddfs;
	while(i < lg) {
		ddf_free(ddfs[i]);
		i++;
	}
	free(ddfs);
}

/**
 * Deallocate a ddf pointer
 */
void ddf_free(ddf_t * ddf) {
	free(ddf);
}

__inline__ int __registerIfDDFnotReady_AND ( ddt_t* wrapperTask, DDF_t* ddfToCheck ) {
    int success = 0;
    ddt_t* waitListOfDDF = ( ddt_t* ) ddfToCheck->headDDTWaitList;

    if ( waitListOfDDF != EMPTY_DDF_WAITLIST_PTR ) {

        while ( waitListOfDDF != EMPTY_DDF_WAITLIST_PTR && !success ) {
            /* waitListOfDDF can not be EMPTY_DDF_WAITLIST_PTR in here*/
            wrapperTask->nextDDTWaitingOnSameDDF = waitListOfDDF;

            success = __sync_bool_compare_and_swap(&(ddfToCheck -> headDDTWaitList), waitListOfDDF, wrapperTask);
            /* printf("task:%p registered to DDF:%p\n", pollingTask,ddfToCheck); */

            /* may have failed because either some other task tried to be the head or a put occurred. */
            if ( !success ) {
                waitListOfDDF = ( ddt_t* ) ddfToCheck -> headDDTWaitList;
                /* if waitListOfDDF was set to EMPTY_DDF_WAITLIST_PTR, the loop condition will handle that
                 * if another task was added, now try to add in front of that
                 * */
            }
        }

    }

    return success;
}

/**
 * Runtime interface to DDTs.
 * Returns '1' if all ddf dependencies have been satisfied.
 */
int iterate_ddt_frontier ( ddt_t* wrapperTask) {
	DDF_t** currDDFnodeToWaitOn = wrapperTask->waitingFrontier;

    while (*currDDFnodeToWaitOn && !__registerIfDDFnotReady_AND (wrapperTask, *currDDFnodeToWaitOn) ) {
        ++currDDFnodeToWaitOn;
    }
	wrapperTask->waitingFrontier = currDDFnodeToWaitOn;
    return *currDDFnodeToWaitOn == NULL;
}

//
// Task conversion Implementation
//

task_t * rt_ddt_to_async_task(ddt_t * ddt) {
	task_t* t = &(((task_t *)ddt)[-1]);
	return t;
}

ddt_t * rt_async_task_to_ddt(task_t * async_task) {
	return &(((hcpp_task_t*) async_task)->ddt);
}

/**
 * Put datum in the DDF.
 * Close down registration of DDTs on this DDF and iterate over the
 * DDF's frontier to try to advance DDTs that were waiting on this DDF.
 */
void ddf_put (ddf_t* ddfToBePut, void * datumToBePut ) {
	HASSERT (datumToBePut != UNINITIALIZED_DDF_DATA_PTR && EMPTY_DATUM_ERROR_MSG);
	HASSERT (ddfToBePut != NULL && "can not put into NULL DDF");
	HASSERT (ddfToBePut-> datum == NULL && "violated single assignment property for DDFs");

	volatile ddt_t* waitListOfDDF = NULL;
	ddt_t* currDDT = NULL;
	ddt_t* nextDDT = NULL;

	ddfToBePut-> datum = datumToBePut;
	waitListOfDDF = ddfToBePut->headDDTWaitList;
	/*seems like I can not avoid a CAS here*/
	while ( !__sync_bool_compare_and_swap( &(ddfToBePut -> headDDTWaitList), waitListOfDDF, EMPTY_DDF_WAITLIST_PTR)) {
		waitListOfDDF = ddfToBePut -> headDDTWaitList;
	}

	currDDT = ( ddt_t* ) waitListOfDDF;

	/* printf("DDF:%p was put:%p with value:%d\n", ddfToBePut, datumToBePut,*((int*)datumToBePut)); */
	while ( currDDT != UNINITIALIZED_DDF_WAITLIST_PTR ) {
		nextDDT = currDDT->nextDDTWaitingOnSameDDF;
		if (iterate_ddt_frontier(currDDT) ) {
			/* printf("pushed:%p\n", currDDT); */
			/*deque_push_default(currFrame);*/
			// DDT eligible to scheduling
			task_t * async_task = rt_ddt_to_async_task(currDDT);
			if (DEBUG_DDF) { printf("ddf: async_task %p\n", async_task); }
			try_schedule_async(async_task, 0);
		}
		currDDT = nextDDT;
	}
}
}
<|endoftext|>