#include "Collect_scalar.h"

#include "Path.h"
#include "Collect_scalar_to_file.h"
#include "Collect_scalar_to_graph.h"
#include "Mach_eps.h"

#include <math.h>
//class MM::Monitor_presentation_frame;

namespace MM
{

Collect_scalar::
Collect_scalar (Atom_group  & atom_group, Text in)
:
    Collect_quantity (atom_group, in)
{
}

Collect_scalar::
Collect_scalar (Atom_group  &                 atom_group,
                Collect_scalar_presentation * new_presentation,
                Text                          in)
:
    Collect_quantity (atom_group, in)
{
    adopt (new_presentation);
}

void Collect_scalar::
clear ()
{
    Monitor_frame::clear();//fix

    quantity_sum_.       clear();
    quantity_2_sum_.     clear();

    quantity_sum_10_.    clear();
    block_sum_10_.		 clear();
    block_2_sum_10_.     clear();

    quantity_sum_100_.   clear();
    block_sum_100_.		 clear();
    block_2_sum_100_.     clear();
}

void Collect_scalar::
handle_execute ()
{
    double current_value   = extract_current_value ();
    double current_value_2 = current_value * current_value;
    
    double last_value      = quantity_sum_.size() == 0 
        ? 0. : quantity_sum_.  back();

    double last_value_2    = quantity_sum_.size() == 0 
        ? 0. : quantity_2_sum_.back();

    quantity_sum_.  push_back (last_value   + current_value);
    quantity_2_sum_.push_back (last_value_2 + current_value_2);

    int calls = collected ();

    double last_value_10 = quantity_sum_10_.size() == 0 
        ? 0. : quantity_sum_10_.back();
    quantity_sum_10_.	push_back (last_value_10 + current_value);
    if (calls % 10 == 0 && calls != 0)
    {
        double A   = quantity_sum_10_  [9] / 10.;
        double A_2 = A * A;
        double last_block_2 = block_2_sum_10_.size() == 0 
            ? 0. : block_2_sum_10_.back();
        block_2_sum_10_.push_back (last_block_2 + A_2);

        for (int i=0;  i<10;  ++i)
            block_sum_10_.  push_back (A);

        quantity_sum_10_.clear();
    }

    double last_value_100 = quantity_sum_100_.size() == 0 
        ? 0. : quantity_sum_100_.back();
    quantity_sum_100_.	push_back (last_value_100   + current_value);
    if (calls % 100 == 0 && calls != 0)
    {
        double A   = quantity_sum_100_  [99] / 100.;
        double A_2 = A * A;
        double last_block_2 = block_2_sum_100_.size() == 0 
            ? 0. : block_2_sum_100_.back();
        block_2_sum_100_.push_back (last_block_2 + A_2);

        for (int i=0;  i<100;  ++i)
            block_sum_100_.  push_back (A);

        quantity_sum_100_.clear();
    }

    for (int i=0;  i<presentation_count();  ++i)
        presentation (i).add_data ();
}

std::string  Collect_scalar::
rmsd_10 () const        
{
    if(collected()>=20)
    {
        std::ostringstream out;
        out << rmsd_10 (collected()-1);
        return out.str();
    }
    else return "";
}

std::string  Collect_scalar::
rmsd_100() const
{
    if(collected()>=200)
    {
        std::ostringstream out;
        out << rmsd_100 (collected()-1);
        return out.str();
    }
    else return "";
}

double Collect_scalar::
rmsd (int i) const
{
    REQUIRE ("", has_values ());

    double average_2 = average(i);
    average_2 *= average_2;
    return sqrt (quantity_2_sum_[i] / (i+1) - average_2);
}

double Collect_scalar::
rmsd_10 (int i) const
{
    int index = (i + 1)/10 - 1;

    double average_2 = average((i + 1) - (i + 1)%10 - 1);
    average_2 *= average_2;
    return sqrt (block_2_sum_10_[index] / (index+1) - average_2/* + d_mach_eps*/);
}

double Collect_scalar::
rmsd_100 (int i) const
{
    int index = (i + 1)/100 - 1;

    double average_2 = average((i + 1) - (i + 1)%100 - 1);
    average_2 *= average_2;
    return sqrt (block_2_sum_100_[index] / (index+1) - average_2);
}

Collect_scalar * Collect_scalar::
adopt (Collect_scalar_presentation *new_presentation)
{
    adopt_presentation (new_presentation);
    return this;
}

Monitor_presentation * Collect_scalar::
create_file_presentation (Text const& filename)
{
    return new Collect_scalar_to_file (filename, *this);
}

Monitor_presentation * Collect_scalar::
create_graph_presentation (Text const& graphname)
{
    return new Collect_scalar_to_graph (graphname, *this);
}

}//MM




