#include "Composite_interaction.h"

#include "Lock.h"

#include "Profiler.h"
//#include "Timer.h"
//#define TIME(ref) ;

namespace MM
{

double Composite_interaction::
potential ()
{
    Lock<Interaction>   lock(common_());

    start ();

    double result = 0;

    if (common_.was_initialized() && common_on_)
        result += common_().potential ();

    if (addition_on_)
        for (int i=0;  i<interaction_.size();  ++i)
            result += interaction_[i].potential ();

    finish ();
    return result;
}

void Composite_interaction::
start ()
{
    if (common_.was_initialized() && common_on_)
        common_().start ();

    if (addition_on_)
        for (int i=0;  i<interaction_.size();  ++i)
            interaction_[i].start ();
}

void Composite_interaction::
finish ()
{
    if (common_.was_initialized() && common_on_)
        common_().finish ();

    if (addition_on_)
        for (int i=0;  i<interaction_.size();  ++i)
            interaction_[i].finish ();
}

void Composite_interaction::
zero_virial ()
{
    if (common_.was_initialized() && common_on_)
        common_().zero_virial ();

    if (addition_on_)
        for (int i=0;  i<interaction_.size();  ++i)
            interaction_[i].zero_virial ();
}

void Composite_interaction::
zero_forces ()
{
    if (common_.was_initialized() && common_on_)
        common_().zero_forces ();

    if (addition_on_)
        for (int i=0;  i<interaction_.size();  ++i)
            interaction_[i].zero_forces ();
}

double Composite_interaction::
virial () const
{
    double result = 0;

    if (common_.was_initialized() && common_on_)
        result += common_().virial ();

    if (addition_on_)
        for (int i=0;  i<interaction_.size();  ++i)
            result += interaction_[i].virial ();

    return result;
}

double Composite_interaction::
virial (double *x, double *y, double *z) const
{
    double result = 0;

    if (common_.was_initialized() && common_on_)
        result += common_().virial (x, y, z);

    if (addition_on_)
        for (int i=0;  i<interaction_.size();  ++i)
            result += interaction_[i].virial (x, y, z);

    return result;
}

void Composite_interaction::
add_force ()
{
    Lock<Interaction>   lock(common_()); 

    if (common_.was_initialized() && common_on_)
        common_().add_force ();

    if (addition_on_)
        for (int i=0;  i<interaction_.size();  ++i)
            interaction_[i].add_force ();
}

void Composite_interaction::
add_long_force (std::deque <Atom_chunk_big> & chunk)
//add_long_force (Array <Atom_chunk> & chunk)
{
    if (common_.was_initialized() && common_on_)
        common_().add_long_force (chunk);

    if (addition_on_)
        for (int i=0;  i<interaction_.size();  ++i)
            interaction_[i].add_long_force (chunk);
}

void Composite_interaction::
add_long_force (double R, double Switching, Array <Atom_chunk_small> & chunk)
//add_long_force (double R, double Switching, Array <Atom_chunk> & chunk)
{
    if (common_.was_initialized() && common_on_)
        common_().add_long_force (R, Switching, chunk);

    if (addition_on_)
        for (int i=0;  i<interaction_.size();  ++i)
            interaction_[i].add_long_force (R, Switching, chunk);
}
/*
void Composite_interaction::
add_long_force (Array <double> &fx_,
                Array <double> &fy_,
                Array <double> &fz_,
                double R,
                Array <Atom_chunk> & chunk)
{
    if (common_.was_initialized() && common_on_)
        common_().add_long_force (fx_, fy_, fz_, R, chunk);

    if (addition_on_)
        for (int i=0;  i<interaction_.size();  ++i)
            interaction_[i].add_long_force (fx_, fy_, fz_, R, chunk);
} */

void Composite_interaction::
add_short_force ()
{
    //TIME ("Composite 1              ");
    if (common_.was_initialized() && common_on_)
        common_().add_short_force ();
    //TIME ("Composite 2              ");

    if (addition_on_)
        for (int i=0;  i<interaction_.size();  ++i)
            interaction_[i].add_short_force ();
    //TIME ("Composite 3              ");
}

void Composite_interaction::
list (double skin)
{
    if (common_.was_initialized() && common_on_)
        common_().list (skin);

    if (addition_on_)
        for (int i=0;  i<interaction_.size();  ++i)
            interaction_[i].list (skin);
}

void Composite_interaction::
list (std::deque<Atom_chunk_big> & chunk, double skin)
//list (Array<Atom_chunk> & chunk, double skin)
{
    if (common_.was_initialized() && common_on_)
        common_().list (chunk, skin);

    if (addition_on_)
        for (int i=0;  i<interaction_.size();  ++i)
            interaction_[i].list (chunk, skin);
}


void Composite_interaction::
list (Array<Atom_chunk_small> & chunk, double R, 
      std::deque<Atom_chunk_big> & from)
//list (Array<Atom_chunk> & chunk, double R, 
//      Array<Atom_chunk> & from)
{
    if (common_.was_initialized() && common_on_)
        common_().list (chunk, R, from);

    if (addition_on_)
        for (int i=0;  i<interaction_.size();  ++i)
            interaction_[i].list (chunk, R, from);
}

void Composite_interaction::
list (Array<Atom_chunk_small> & chunk, double R, 
      Array<Atom_chunk_small> & from)
//list (Array<Atom_chunk> & chunk, double R, 
//      Array<Atom_chunk> & from)
{
    if (common_.was_initialized() && common_on_)
        common_().list (chunk, R, from);

    if (addition_on_)
        for (int i=0;  i<interaction_.size();  ++i)
            interaction_[i].list (chunk, R, from);
}

void Composite_interaction::
report (Text *result, Text const & hint)
{
    if (addition_on_)
        for (int i=0;  i<interaction_.size();  ++i)
            interaction_[i].report (result, hint);

    if (common_.was_initialized() && common_on_)
        common_().report (result, hint);
}

void Composite_interaction::
adopt (Interaction *adoptee)
{
    interaction_.adopt (adoptee);
}

void Composite_interaction::
clear ()
{
    interaction_.clear ();
}

bool Composite_interaction::
locked () const
{
    bool result = true;

    for (int i=0;  i<interaction_.size();  ++i)
        result &= interaction_[i].locked ();

    if (common_.was_initialized())
        result &= common_().locked ();

    return result;
}

void Composite_interaction::
set_lock (bool on)
{
    profile ().interactions___add_force___others ();

    for (int i=0;  i<interaction_.size();  ++i)
        interaction_[i].set_lock (on);

    if (common_.was_initialized())
        common_().set_lock (on);

    profile ().lock ();
}

}//MM
