#pragma once
#ifndef PIF_H__
#define PIF_H__

#include "fwd.h"
#include "sampler.h"

#include <string>

struct PIF {
    PIF() {}
    PIF(Float _tau, Float _deltaTau, int _num_bins, Float _stepTau) : 
            tau(_tau), deltaTau(_deltaTau), num_bins(_num_bins), stepTau(_stepTau) {}
    virtual ~PIF() {};

    Float eval(Float x, int bin_index) const;
    FloatAD evalAD(const FloatAD &x, int bin_index) const;
    Float sample(RndSampler *sampler, int &bin_index, Float &pdf) const;
    Vector2 sampleAntithetic(RndSampler *sampler, int &bin_index, Float &pdf) const; // Antithetic sampling of path length
    Vector2 sampleBoundary(Float rnd, int &bin_index, Float &pdf) const; // Sampling two ends of a box time gate.
    int getBinIndex(Float x) const;
    int getPotentialBinIndex(Float x, int which_end) const;

    virtual Float evalSingle(Float x, Float centerTau) const = 0;
    virtual FloatAD evalSingleAD(const FloatAD &x, const FloatAD &centerTau) const = 0;
    virtual Float sampleSingle(RndSampler *sampler, const Vector2 &rnd2, Float centerTau, Float &pdf) const = 0;
    virtual Vector2 sampleSingleBoundary(Float centerTau, Float &pdf) const = 0;
    virtual Vector2i getBinIndexRange(Float x) const = 0;

    std::string name;
    FloatAD tau;
    FloatAD deltaTau;
    int num_bins;
    Float stepTau;
    Float tau_extent;
};

#endif //PIF_H__