#pragma once
#include "light.hpp"
#include "common.hpp"


class GlobalLight: public Light {
    private:
        const light_t val;

    public:
        GlobalLight(unsigned brightness);
        light_t get(std::vector<const Object*>&, const vertex_t& hit, const vertex_t* raynorm, const vertex_t& norm) const;

        bool occlude_box(const Object* o, vertex_t& bound_min, vertex_t& bound_max) const;
        bool reachable(const Object* o) const;
};


class RayLight: public Light { // e.g. for camera angle
    private:
        const light_t intensity;

    public:
        RayLight(unsigned brightness);
        light_t get(std::vector<const Object*>&, const vertex_t& hit, const vertex_t* raynorm, const vertex_t& norm) const;

        bool occlude_box(const Object* o, vertex_t& bound_min, vertex_t& bound_max) const;
        bool reachable(const Object* o) const;
};


class PointLight: public Light {
    private:
        const vertex_t pos;
        const light_t intensity;
        const unsigned maxlen, maxsqlen;

    public:
        PointLight(const vertex_t& p, Img::rgb_t, unsigned brightness, unsigned len);
        light_t get(std::vector<const Object*>&, const vertex_t& hit, const vertex_t* raynorm, const vertex_t& norm) const;

        bool occlude_box(const Object* o, vertex_t& bound_min, vertex_t& bound_max) const;
        bool reachable(const Object* o) const;
};


class AreaLight: public Light {
    private:
        vertex_t minp;
        const light_t intensity;
        const unsigned maxlen, maxsqlen, maxmaxlen, maxmaxsqlen;
        const vertex_t bound_min, bound_max;
        const unsigned samples;

        vertex_t stepa, stepb;
        vertex_t starta, startb;

    public:
        AreaLight(const vertex_t& a, const vertex_t& b, unsigned brightness, unsigned len);
        light_t get(std::vector<const Object*>&, const vertex_t& hit, const vertex_t* raynorm, const vertex_t& norm) const;

        bool occlude_box(const Object* o, vertex_t& bound_min, vertex_t& bound_max) const;
        bool reachable(const Object* o) const;
};