/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#pragma once

#include <cfloat>
#include <limits>
#include <memory>
#include <vector>

namespace metview
{

class StatsCompute : public std::enable_shared_from_this<StatsCompute>
{
public:
    StatsCompute() = default;
    virtual ~StatsCompute() = default;
    void setInvalidValue(double v) { invalidVal_ = v; }
    virtual void reset() = 0;
    virtual void add(double v) = 0;
    virtual void add(double v, double weight) = 0;
    virtual double compute(bool weighted) = 0;
    bool isInvalidValue(double v) const { return invalidVal_ == v; }

protected:
    double invalidVal_{0};
};

class AggregateStatsCompute : public StatsCompute
{
public:
    AggregateStatsCompute() = default;
    void reset() override;

protected:
    double aggr_{0.};
    double aggr2_{0.};
    double weight_{0.};
    std::size_t cnt_{0};
};

class MeanStatsCompute : public AggregateStatsCompute
{
public:
    using AggregateStatsCompute::AggregateStatsCompute;
    void add(double) override;
    void add(double, double) override;
    double compute(bool weighted) override;
};

class VarianceStatsCompute : public AggregateStatsCompute
{
public:
    using AggregateStatsCompute::AggregateStatsCompute;
    void add(double) override;
    void add(double, double) override;
    double compute(bool weighted) override;
};

class StdevStatsCompute : public VarianceStatsCompute
{
public:
    using VarianceStatsCompute::VarianceStatsCompute;
    double compute(bool weighted) override;
};

class MaxStatsCompute : public StatsCompute
{
public:
    using StatsCompute::StatsCompute;
    void reset() override;
    void add(double) override;
    void add(double, double) override;
    double compute(bool weighted) override;

protected:
    const double startVal_{std::numeric_limits<double>::lowest()};
    double val_{std::numeric_limits<double>::lowest()};
};

class MinStatsCompute : public StatsCompute
{
public:
    using StatsCompute::StatsCompute;
    void reset() override;
    void add(double) override;
    void add(double, double) override;
    double compute(bool weighted) override;

protected:
    const double startVal_{std::numeric_limits<double>::max()};
    double val_{std::numeric_limits<double>::max()};
};

class ArrayStatsCompute : public StatsCompute
{
    using StatsCompute::StatsCompute;
    void reset() override;
    void add(double v) override { vals_.push_back(v); }
    void add(double v, double) override { vals_.push_back(v); }

protected:
    std::vector<double> vals_;
};

class MedianStatsCompute : public ArrayStatsCompute
{
public:
    using ArrayStatsCompute::ArrayStatsCompute;
    double compute(bool weighted) override;
};

}  // namespace metview
