/*
 * Example source file.
 *
 * Author: Malte J. Ziebarth (malte.ziebarth@tum.de)
 *
 * Copyright (C) 2025 Technische Universität München
 *
 * 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 the copyright holder nor the names of its contributors
 *       may be used to endorse or promote products derived from this software
 *       without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * SPDX-FileCopyrightText: 2025 Technical University of Munich
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "example.hpp"
#include <iostream>
#include <boost/units/systems/si.hpp>

int test_function(
    const char* name,
    size_t i,
    double* result
)
{
    /* This just prints the input arguments: */
    if (name)
        std::cout << "name: '" << name << "'.\n";
    else
        std::cout << "name: nullptr\n";
    std::cout << "i: " << i << "\n";
    std::cout << "result: " << (size_t) result << "\n";
    std::cout << std::flush;
    if (!result)
        std::cout << "no result output vector given!\n";
    else
        *result = 1.7281;
    return 0;
}


int test_function_2(
    std::string& result
)
{
    result = "test test";
    return 0;
}


int test_function_3(
    funktionsklempner::InputNDArray<double> in_,
    funktionsklempner::OutputNDArray<double> out
)
{
    if (in_.size() != out.size()){
        std::cout << "size mismatch: (n_in = "
            << in_.size() << ") != (n_out ="
            << out.size() << ")\n";
        return 1;
    }
    for (size_t i=0; i<in_.size(); ++i)
        out.begin()[i] = 2.0 * in_.begin()[i];

    return 0;
}


int test_function_4(
    funktionsklempner::InputQuantityArray<boost::units::si::length, double> in_,
    funktionsklempner::OutputQuantityArray<boost::units::si::energy, double> out
)
{
    if (in_.size() != out.size()){
        std::cout << "size mismatch: (n_in = "
            << in_.size() << ") != (n_out ="
            << out.size() << ")\n";
        return 1;
    }
    namespace bu = boost::units;
    namespace si = boost::units::si;
    constexpr bu::quantity<si::acceleration> g = 9.81 * si::meter_per_second_squared;
    constexpr bu::quantity<si::mass> M = 1.0 * si::kilogram;
    for (size_t i=0; i<in_.size(); ++i)
        out.begin()[i] = M * g * in_.begin()[i];


    return 0;
}


int test_function_5(
    funktionsklempner::InputQuantityArray<boost::units::si::length, double> in0_,
    funktionsklempner::InputQuantityArray<boost::units::si::mass, double> in1_,
    funktionsklempner::OutputQuantityArray<boost::units::si::energy, double> out
)
{
    size_t n_in = in0_.size() * in1_.size();
    if (n_in != out.size()){
        std::cout << "size mismatch: (n_in = "
            << n_in << ") != (n_out ="
            << out.size() << ")\n";
        return 1;
    }

    namespace bu = boost::units;
    namespace si = boost::units::si;
    constexpr bu::quantity<si::acceleration> g = 9.81 * si::meter_per_second_squared;
    const size_t n0 = in0_.size();
    for (size_t i=0; i<n0; ++i){
        if (i == n0){
            std::cout << "found i=" << i << " == n0=" << n0 << "\n" << std::flush;
            return 1;
        }
        for (size_t j=0; j<in1_.size(); ++j){
            size_t k = (i * in1_.size()) + j;
            out[k] = in1_[j] * g * in0_[i];
        }
    }

    std::cout << "finished test_function_5\n" << std::flush;
    return 0;
}