#include "util.hpp"

#include <cmath>
#include <cstdlib>

#include <sstream>

namespace util {
    float randf_m1_1()
    {
        return 2.0f*randf_0_1() - 1.0f;
    }

    float randf_0_1()
    {
        return static_cast<float>(static_cast<double>(rand()) / (double) RAND_MAX);
    }

    glm::vec2 randv2_m1_1()
    {
        return glm::vec2(randf_m1_1(), randf_m1_1());
    }

    glm::vec2 randv2_0_1()
    {
        return glm::vec2(randf_0_1(), randf_0_1());
    }

    float deg2rad(float deg)
    {
        return M_PI*deg/180.0;
    }

    float rad2deg(float rad)
    {
        return 180.0 * rad / M_PI;
    }

    IntersectionTest::IntersectionTest() : m_valid(false), m_distance(INFINITY)
    {
    }

    IntersectionTest::IntersectionTest(float d) : m_valid(true), m_distance(d)
    {
    }

    float IntersectionTest::distance() const { assert(m_valid); return m_distance; }
    bool  IntersectionTest::valid()    const { return m_valid; }

    glm::vec3 IntersectionTest::pointAtDistance(float d)
    {
        assert(m_valid);
        return m_rayPos + m_rayDir * d;
    }

    bool IntersectionTest::raySphere(
            const glm::vec3 &rayPos,    const glm::vec3 &rayDir,
            const glm::vec3 &spherePos, float sphereRadius)
    {
        m_valid = false;

        (void) spherePos;
        (void) sphereRadius;

        // TODO: save if hit.
        m_valid = true;
        m_rayPos = rayPos;
        m_rayDir = rayDir;
        m_distance = 0.5;

        // TODO: get code
        return m_valid;

#if 0
        const glm::vec3 &o = ray.pos();
        const glm::vec3 &l = ray.dir();
        const glm::vec3 &c = m_pos;
        const float     &r = m_radius;

        const glm::vec3 omc = o-c;
        const float     dot = glm::dot(l, omc);
        const float     s   = dot*dot - util::dotSelf(omc) + r*r;

        if (s < 0.001) {
            return RayIntersection();
        }

        const float t = -dot;

#if 0
        // TODO: is that meant as t?
        if (s == 0) {
            // not interested in touch point
            return RayIntersection();

            //d1 = t;
            //return RayTouchesOnePoint;
        }
#endif

        const float sr = sqrt(s);

        d1 = t - sr;
        d2 = t + sr;

        // if end intersection lies behind it, this is completely uninteresting for us
        // 0.01 because to get rid of rounding/precision errors
        if (d2 <= 0.01) {
            return RayIntersection();
        }

        // if the start of the interval lies behind us, make it 0 because we just
        // want to know whats before us.
        // 0.01 because to get rid of rounding/precision errors
        if (d1 < 0.0) {
            d1 = 0.0;
        }
#endif
    }

    bool splitIntoTokenAndRest(const std::string &str, std::string &token, std::string &rest)
    {
        std::istringstream iss(str);
        iss >> token;

        if (token.size() == 0) {
            return false;
        }

        // skip token + next whitespace
        rest = str.substr(std::min(str.size(), token.size()+1));

        return true;
    }
}
