/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright 2015-2018 Danny Robson <danny@nerdcruft.net>
 */

#pragma once

#include "./fwd.hpp"
#include "../point.hpp"

#include <type_traits>


///////////////////////////////////////////////////////////////////////////////
namespace cruft::geom {
    /// Tests whether any part of two shapes overlap.
    ///
    /// Returns true even if the  the edges of the shapes are co-linear.
    template <
        size_t S,
        typename T,
        template <size_t,typename> class A,
        template <size_t,typename> class B
    >
    bool
    intersects (A<S,T>, B<S,T>);

    /// Tests whether the entirety of shape `B` is inclusively contained
    /// within the shape `A`.
    template <
        size_t S,
        typename T,
        template<size_t,typename> class A,
        template<size_t,typename> class B
    >
    bool covers (A<S,T> const&, B<S,T> const&);


    /// Returns a minimum squared distance between two shapes.
    template <
        size_t S,
        typename T,
        template <size_t,typename> class A,
        template <size_t,typename> class B
    >
    T
    distance2 (A<S,T>, B<S,T>);

    // disable distance for point-point arguments given it's already
    // explicitly specified in the point header.
    template <
        size_t S,
        typename T,
        template <size_t,typename> class A,
        template <size_t,typename> class B,
        typename = std::enable_if_t<
            !std::is_same_v<cruft::point<S,T>, A> &&
            !std::is_same_v<cruft::point<S,T>, B>
        >
    >
    T
    distance (A<S,T>, B<S,T>);


    /// Returns an AABB for the supplied shape.
    template <
        size_t S,
        typename T,
        template <size_t,typename> class K
    >
    aabb<S,T>
    bounds (K<S,T>);


    /// Returns a bounding AABB for all supplied items
    template <typename... Args>
    auto
    bounds (Args &&...args)
    {
        return (bounds (args) | ...);
    }

    /// Returns a maximum distance across a shape.
    template <
        size_t S,
        typename T,
        template <size_t,typename> class K
    >
    T
    diameter (K<S,T>);


    /// Returns the closest point on a shape to the supplied point.
    template <
        size_t S,
        typename T,
        template <size_t,typename> class K
    >
    point<S,T>
    closest (K<S,T>, point<S,T>);


    template <
        size_t S,
        typename T,
        template <size_t,typename> class K
    >
    vector<S,T>
    magnitude (K<S,T>);


    template <
        size_t S,
        typename T,
        template <size_t,typename> class K
    >
    K<S,T>
    scale (K<S,T>, T);
}