// Copyright (c)       2015 Martin Stumpf
//
//  SPDX-License-Identifier: BSL-1.0
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <hpx/config.hpp>
#if !defined(HPX_COMPUTE_DEVICE_CODE)
#include <hpx/hpx.hpp>
#include <hpx/hpx_start.hpp>
#include <hpx/iostream.hpp>
#include <hpx/modules/testing.hpp>

#include <atomic>
#include <chrono>

struct test
{
    test()
    {
        ++count;
    }
    test(test const&)
    {
        ++count;
    }
    test& operator=(test const&)
    {
        ++count;
        return *this;
    }
    ~test()
    {
        --count;
    }

    static std::atomic<int> count;
};

std::atomic<int> test::count(0);

test call()
{
    return test();
}
HPX_PLAIN_ACTION(call)

void test_leak()
{
    {
        hpx::shared_future<test> f;

        {
            hpx::distributed::promise<test> p;
            f = p.get_future();
            hpx::post_c<call_action>(p.get_id(), hpx::find_here());
        }

        test t = f.get();
        (void) t;
    }

    hpx::agas::garbage_collect();
    hpx::this_thread::yield();
    hpx::agas::garbage_collect();
    hpx::this_thread::yield();
    HPX_TEST_EQ(test::count, 0);
}

int hpx_main()
{
    {
        test_leak();

        hpx::id_type promise_id;
        hpx::future<int> f;
        {
            hpx::distributed::promise<int> p;
            f = p.get_future();
            {
                auto local_promise_id = p.get_id();
                hpx::cout << local_promise_id << std::endl;
            }

            hpx::this_thread::sleep_for(std::chrono::milliseconds(100));

            promise_id = p.get_id();
            hpx::cout << promise_id << std::endl;
        }

        hpx::this_thread::sleep_for(std::chrono::milliseconds(100));

        HPX_TEST(!f.is_ready());
        // This segfaults, because the promise is not alive any more.
        // It SHOULD get kept alive by AGAS though.
        hpx::set_lco_value(promise_id, 10, false);
        HPX_TEST(f.is_ready());
        HPX_TEST_EQ(f.get(), 10);
    }
    {
        hpx::id_type promise_id;
        {
            hpx::distributed::promise<int> p;
            p.get_future();
            {
                auto local_promise_id = p.get_id();
                hpx::cout << local_promise_id << std::endl;
            }

            hpx::this_thread::sleep_for(std::chrono::milliseconds(100));

            promise_id = p.get_id();
            hpx::cout << promise_id << std::endl;
        }

        hpx::this_thread::sleep_for(std::chrono::milliseconds(100));

        // This segfaults, because the promise is not alive any more.
        // It SHOULD get kept alive by AGAS though.
        hpx::set_lco_value(promise_id, 10, false);
    }
    return hpx::finalize();
}

int main(int argc, char* argv[])
{
    // initialize HPX, run hpx_main.
    hpx::start(argc, argv);

    // wait for hpx::finalize being called.
    return hpx::stop();
}
#endif
