#ifndef COLLECT_SCALAR_H
#define COLLECT_SCALAR_H

#ifndef COLLECT_QUANTITY_H
#include "Collect_quantity.h"
#endif

#ifndef ARRAY_H
#include "Array.h"
#endif

#ifndef COLLECT_SCALAR_PRESENTATION_H
#include "Collect_scalar_presentation.h"
#endif

#include <string>
#include <sstream>

namespace MM
{

class Collect_scalar : public Collect_quantity
{
protected:
    Array <double>      quantity_sum_;
    Array <double>      quantity_2_sum_;

    Array <double>      quantity_sum_10_;
    Array <double>      block_sum_10_;
    Array <double>      block_2_sum_10_;
    
    Array <double>      quantity_sum_100_;
    Array <double>      block_sum_100_;
    Array <double>      block_2_sum_100_;

public:
    explicit Collect_scalar (Atom_group  & atom_group, Text in);
    explicit Collect_scalar (Atom_group  & atom_group,
                             Collect_scalar_presentation *new_presentation,
                             Text                         in);

    void                clear();

    double  value   (int i) const   
    {
        REQUIRE ("In range.", i >= 0 && i < collected());

        return i == 0 
            ? quantity_sum_[0] 
            : quantity_sum_[i] - quantity_sum_[i-1];
    }

    std::string  value_block_10   (int i) const   
    {
        REQUIRE ("In range.", i >= 0 && i < collected());
        if (i < 9)
            return "";

        ++i;
        int index = i - i%10 - 11;

        std::ostringstream out;
        double result = block_sum_10_[index+1];
        out << result << std::flush;
        return out.str();
    }

    std::string  value_block_100   (int i) const   
    {
        REQUIRE ("In range.", i >= 0 && i < collected());
        if (i < 99)
            return "";

        ++i;
        int index = i - i%100 - 101;

        std::ostringstream out;
        double result = block_sum_100_[index+1];
        out << result << std::flush;
        return out.str();
    }

    bool    has_values () const             {return quantity_sum_.size() > 0;}
    double  last_value () const                  {REQUIRE ("", has_values ());   return value           (collected()-1);}
    std::string  last_block_10_value  () const   {REQUIRE ("", has_values ());   return value_block_10  (collected()-1);}
    std::string  last_block_100_value () const   {REQUIRE ("", has_values ());   return value_block_100 (collected()-1);}
    double  average () const        {REQUIRE ("", has_values ());   return average (collected()-1);}
    double  rmsd    () const        {REQUIRE ("", has_values ());   return rmsd    (collected()-1);}
    std::string rmsd_10 () const;
    std::string rmsd_100() const;

    double  average (int i) const
    {
        REQUIRE ("", has_values ());
        REQUIRE ("i>=0", i>=0);
        REQUIRE ("i<0", i<quantity_sum_.size());
        return quantity_sum_[i] / (i+1);
    }
    double  rmsd     (int i) const;
    double  rmsd_10  (int i) const;
    double  rmsd_100 (int i) const;

    Collect_scalar *    adopt (Collect_scalar_presentation *new_presentation);

protected:
    virtual double      extract_current_value () =0;

    void                    handle_execute ();
    Monitor_presentation *  create_file_presentation  (Text const& filename);
    Monitor_presentation *  create_graph_presentation (Text const& graphname);
};

}//MM

#endif //COLLECT_SCALAR_H
