//#####################################################################
// Copyright 2002-2008, Robert Bridson, Ronald Fedkiw, Eran Guendelman, Jon Gretarsson, Andrew Selle.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
// Class RAY_HIT
//#####################################################################
#ifndef __RAY_HIT__
#define __RAY_HIT__

#include <Core/Basic_Geometry/SEGMENT_1D.h>
#include <Core/Basic_Geometry/SEGMENT_2D.h>
#include <Core/Basic_Geometry/SEGMENT_3D.h>
#include <Core/Math_Tools/RANGE.h>
#include <Core/Vectors/VECTOR.h>
#include <cmath>
namespace PhysBAM{

template<class T>
class RAY_HIT
{
public:
    bool intersection=false; // indicates whether the ray is semi_infinite or should stop at t_max
    T dist=FLT_MAX; // maximum value of t allowed for the ray
    int id=-1; // indicates the piece of an aggregate object that is intersected by dist

    RAY_HIT() = default;

    explicit RAY_HIT(T dist)
        :intersection(true),dist(dist)
    {}

    template<class U>
    explicit RAY_HIT(const RAY_HIT<U>& h)
        :intersection(h.intersection),dist(h.dist),id(h.id)
    {}

    RAY_HIT(T dist,int id)
        :intersection(true),dist(dist),id(id)
    {}
    
    bool Hit() const {return intersection;}
    bool Hit(T d) const {return intersection && dist<=d;}

    void Set(T d,int i=-1)
    {
        intersection=true;
        dist=d;
        id=i;
    }

    RAY_HIT<T>& Set_Id(int i)
    {
        id=i;
        return *this;
    }

    RAY_HIT<T> Best(const RAY_HIT<T>& ray_hit) const
    {
        if(!ray_hit.intersection) return *this;
        if(!intersection) return ray_hit;
        return dist<=ray_hit.dist?*this:ray_hit;
    }
};

template<class T,int d>
void Set_Id(VECTOR<RAY_HIT<T>,d>& v,int i)
{
    for(auto&u:v) u.Set_Id(i);
}

template<class T,int d>
RAY_HIT<T> Ray_Hit(const VECTOR<RAY_HIT<T>,d>& v)
{
    if(d<1 || !v(0).Hit()) return {};
    if(v(0).dist>0) return v(0);
    if(d<2 || !v(1).Hit()) return {};
    return v(1);
}
}
#endif
