#include "Profiler.h"

#include "Log.h"

namespace MM
{

Profiler & Profiler::singleton ()
{
    static Profiler instance;
    return instance;
}

void Profiler::
report ()
{
    Text result;

    result += "\n";

    result += "List_interactions ";
    result += interactions___add_force___start_count_;
    result += "\n";

    if (interactions___add_force___start_ !=0.)
    {
    result += interactions___add_force___start_;
    result += " outer\n";
    }

    if (interactions___add_force___others_ !=0.)
    {
    result += interactions___add_force___others_;
    result += " other\n";
    }

    if (interactions___add_force___make_list_ !=0.)
    {
    result += interactions___add_force___make_list_;
    result += " make_list\n";
    }

    if (interactions___add_force___make_sublist_ !=0.)
    {
    result += interactions___add_force___make_sublist_;
    result += " make_list\n";
    }

    if (interactions___add_force___calc_nonbonded_force_ !=0.)
    {
    result += interactions___add_force___calc_nonbonded_force_;
    result += " calc_nonbonded_force\n";
    }

    if (interactions___add_force___add_atom_force_ !=0.)
    {
    result += interactions___add_force___add_atom_force_;
    result += " add_atom_force\n";
    }

    if (interactions___add_force___add_bond_force_ !=0.)
    {
    result += interactions___add_force___add_bond_force_;
    result += " add_bond_force\n";
    }

    if (interactions___add_force___add_full_nonbonded_force_ !=0.)
    {
    result += interactions___add_force___add_full_nonbonded_force_;
    result += " add_full_nonbonded_force\n";
    }

    if (interactions___add_force___add_long_force_ !=0.)
    {
    result += interactions___add_force___add_long_force_;
    result += " add_long_force\n";
    }

    if (interactions___add_force___add_switching_force_ !=0.)
    {
    result += interactions___add_force___add_switching_force_;
    result += " add_switching_force\n";
    }

    if (interactions___add_force___add_water_force_ !=0.)
    {
    result += interactions___add_force___add_water_force_;
    result += " add_switching_force\n";
    }

    //=========================================================================
    result += "CUDA_interactions\n...";

    if (CUDA_interactions___add_nonbonded_force___start_ !=0.)
    {
    result += CUDA_interactions___add_nonbonded_force___start_;
    result += " outer\n...";
    }

    if (CUDA_interactions___add_nonbonded_force___set_atom_force_ !=0.)
    {
    result += CUDA_interactions___add_nonbonded_force___set_atom_force_;
    result += " set_atom_force\n...";
    }

    if (CUDA_interactions___add_nonbonded_force___atom_force_to_device_ !=0.)
    {
    result += CUDA_interactions___add_nonbonded_force___atom_force_to_device_;
    result += " atom_force_to_device\n...";
    }

    if (CUDA_interactions___add_nonbonded_force___nonbonded_force_ !=0.)
    {
    result += CUDA_interactions___add_nonbonded_force___nonbonded_force_;
    result += " nonbonded_force\n...";
    }

    if (CUDA_interactions___add_nonbonded_force___atom_force_from_device_ !=0.)
    {
    result += CUDA_interactions___add_nonbonded_force___atom_force_from_device_;
    result += " atom_force_from_device\n...";
    }

    if (CUDA_interactions___add_nonbonded_force___get_atom_force_ !=0.)
    {
    result += CUDA_interactions___add_nonbonded_force___get_atom_force_;
    result += " get_atom_force\n...";
    }

    if (CUDA_interactions___add_nonbonded_force___free_ !=0.)
    {
    result += CUDA_interactions___add_nonbonded_force___free_;
    result += " free\n";
    }
    //=========================================================================

    if (interactions___add_force___flush_force_ !=0.)
    {
    result += interactions___add_force___flush_force_;
    result += " flush_force\n";
    }

    result += " \n";

    double sum = 
        interactions___add_force___start_ +
        interactions___add_force___others_ +
        interactions___add_force___make_list_ +
        interactions___add_force___make_sublist_ +
        interactions___add_force___calc_nonbonded_force_ +
        interactions___add_force___add_atom_force_ +
        interactions___add_force___add_bond_force_ +
        interactions___add_force___add_full_nonbonded_force_ +
        interactions___add_force___add_long_force_ +
        interactions___add_force___add_switching_force_ +
        interactions___add_force___add_water_force_ +
        interactions___add_force___flush_force_ +
        CUDA_interactions___add_nonbonded_force___start_ +
        CUDA_interactions___add_nonbonded_force___set_atom_force_ +
        CUDA_interactions___add_nonbonded_force___atom_force_to_device_ +
        CUDA_interactions___add_nonbonded_force___nonbonded_force_ +
        CUDA_interactions___add_nonbonded_force___atom_force_from_device_ +
        CUDA_interactions___add_nonbonded_force___get_atom_force_ +
        CUDA_interactions___add_nonbonded_force___free_;

    result += sum * interactions___add_force___start_count_;
    result += " Sum\n";


    result += " \n";
    result += "\n";

    log () << result;
}

void Profiler::
restart ()
{
    interactions___add_force___start_count_ = 0;
    clear ();
    timer_.restart ();
}

void Profiler::
clear ()
{

    interactions___add_force___start_                            = 0.;
    interactions___add_force___others_                           = 0.;
    kick_                                                        = 0.;
    drift_                                                       = 0.;
    lock_                                                        = 0.;
    update_                                                      = 0.;
    interactions___add_force___make_list_                        = 0.;
    interactions___add_force___make_sublist_                     = 0.;
    interactions___add_force___calc_nonbonded_force_             = 0.;
    interactions___add_force___add_atom_force_                   = 0.;
    interactions___add_force___add_bond_force_                   = 0.;
    interactions___add_force___add_full_nonbonded_force_         = 0.;
    interactions___add_force___add_long_force_                   = 0.;
    interactions___add_force___add_switching_force_              = 0.;
    interactions___add_force___add_water_force_                  = 0.;
    interactions___add_force___flush_force_                      = 0.;

    CUDA_interactions___add_nonbonded_force___start_                  = 0.;
    CUDA_interactions___add_nonbonded_force___set_atom_force_         = 0.;
    CUDA_interactions___add_nonbonded_force___atom_force_to_device_   = 0.;
    CUDA_interactions___add_nonbonded_force___nonbonded_force_        = 0.;
    CUDA_interactions___add_nonbonded_force___atom_force_from_device_ = 0.;
    CUDA_interactions___add_nonbonded_force___get_atom_force_         = 0.;
    CUDA_interactions___add_nonbonded_force___free_                   = 0.;
}

}//MM

