// 
// This file is part of MolMeccano, a cross-platform C++ chemical library.
//
// Copyright (C) 2001-2007 Alexey Nikitin
//
#if defined WIN32
#pragma warning (disable: 4503)
#pragma warning (disable: 4355)
#endif

#include "Atom_kit.h"

#include "View_atom_type_manager.h"

#include "Pdb_attributes.h"
#include "MOT.h"
#include "Molecule.h"
#include "Bond.h"
#include "Bond_kit.h"
#include "Residue_impl.h"
#include "Atom.h"
#include "User.h"
#include "Fine_type_impl.h"
#include "Vector_3D_impl.h"

#include <string.h>

namespace MM
{

Atom_kit::
Atom_kit (Atom & atom)
:
    in_molecule_    (&Molecule::none()),
    in_residue_     (&Residue ::none()),
    mm_type_        (0),   //fix   -1
    number_         (-1),
    ff_mass_        (0.),
    induction_charge_(0.),
    atom_           (atom),
    fine_type_      (Fine_type::none),

    potential_force_(0,0,0),
    bond_stretch_force_     (0,0,0),
    angle_force_            (0,0,0),
    torsion_force_          (0,0,0),
    improper_force_         (0,0,0),
    nonbonded_force_        (0,0,0),
    short_nonbonded_force_  (0,0,0),
    long_nonbonded_force_   (0,0,0),

    velocity_       (0,0,0),
    overlap_flag_   (false),
    born_radius_    (0.),
    V_              (0.),
    Gpol_           (0.),
    Gpol13_         (0.),
    transparency_   (1.),
    visual_         (*this),
    cache___        (0),
    picked_         (false),
    selected_       (false),
    illusory_       (false),
    frozen_         (false)
{
    //visual_.adopt (new Visual_atom_composite (*this));
}

void Atom_kit::
pick (bool on)
{
    picked_ = on;

    visual().renew_view ();

    Atom & self = atom();
    for (int i=0;  i<self.bound_count();  ++i)
        self.bond (i).kit().visual().renew_view ();
}

void Atom_kit::
select (bool on)
{
    selected_ = on;

    visual().renew_view ();

    Atom & self = atom();
    for (int i=0;  i<self.bound_count();  ++i)
        self.bond (i).kit().visual().renew_view ();
}


void Atom_kit::
set_illusory (bool on)
{
    illusory_ = on;
    visual().renew_view ();
}

void Atom_kit::
freeze (bool on)
{
    frozen_ = on;
    visual().renew_view ();
}

bool Atom_kit::
has_pdb_attributes () const
{
    return pdb_attributes_.was_initialized();
}

void Atom_kit::
add_pdb_attributes (Pdb_attributes * adoptee)
{
    REQUIRE ("",  !has_pdb_attributes());
    pdb_attributes_.adopt (adoptee);
    ENSURE  ("",  has_pdb_attributes());
}

void Atom_kit::
remove_pdb_attributes()
{
    REQUIRE ("",  has_pdb_attributes());
    delete pdb_attributes_.orphan();
    ENSURE  ("",  !has_pdb_attributes());
}


bool Atom_kit::
has_hyperchem_attributes() const
{
    return hyperchem_attributes_.was_initialized();
}

void Atom_kit::
add_hyperchem_attributes (Hyperchem_attributes * adoptee)
{
    //REQUIRE ("",  !has_hyperchem_attributes());
    hyperchem_attributes_.adopt (adoptee);
    ENSURE  ("",  has_hyperchem_attributes());
}

void Atom_kit::
remove_hyperchem_attributes()
{
    REQUIRE ("",  has_hyperchem_attributes());
    delete hyperchem_attributes_.orphan();
    ENSURE  ("",  !has_hyperchem_attributes());
}

bool Atom_kit::
has_visual () const
{
    //return visual_.was_initialized();
    return visual_.count() != 0;
}

void Atom_kit::
add_visual (Visual_atom *adoptee)
{
    visual_.adopt (adoptee);
}

bool Atom_kit::
has_mm_type () const
{
    return mm_type_ != Micro_object_type::undefined_type ||
           !mm_type_name_.is_empty ();
}

const char * Atom_kit::
mm_type_c_str    () const
{
    if (mm_type_ == Micro_object_type::undefined_type)
        return mm_type_name_.c_str();

    return ::mot().itoa (mm_type_);
}

void Atom_kit::
set_mm_type (const char * str)
{
    mm_type_ = ::mot().atoi (str);
    mm_type_name_ = str;
}
/*
const char * Atom_kit::
flag_c_str (char * str ) const
{
    strcpy( str, "" );
    if( flag_.is( Atom_kit::hetero )               ) strcat( str, "h" );
    if( flag_.is( Atom_kit::has_improper_torsion ) ) strcat( str, "i" );
    if( flag_.is( Atom_kit::united )               ) strcat( str, "x" );
    if( flag_.is( Atom_kit::selected )             ) strcat( str, "s" );

    if( strlen( str ) == 0 )  strcat( str, "-" );
    return str;
}

void Atom_kit::
set_flag (const char * str)
{
    int i, size = strlen (str);

    for (i = 0;  i < size;  i++)
    {
        switch (str[i])
        {
            case '-':
                flag_.clear (Atom_kit::hetero);
                flag_.clear (Atom_kit::has_improper_torsion);
                flag_.clear (Atom_kit::united);
                flag_.clear (Atom_kit::selected);
                break;

            case 'h':
                flag_.set (Atom_kit::hetero);
                break;
            case 'i':
                flag_.set (Atom_kit::has_improper_torsion);
                break;
            case 'x':
                flag_.set (Atom_kit::united);
                break;
            case 's':
                flag_.set (Atom_kit::selected);
                break;
            default :
                MM::to_user().error ("Atom_kit::set_flag");
        }
    }
}//*/

char const * Atom_kit::
fine_type_name () const
{
    //return Fine_type::singleton().name (fine_type_);
    return Fine_type::name (fine_type_);
}

void Atom_kit::
set_fine_type (char const* name)
{
    //fine_type_ = Fine_type::singleton().id (name);
    fine_type_ = Fine_type::id (name);
}

void Atom_kit::
set_potential_force (Vector_3D const & new_value)
{
    potential_force_.set_x (new_value.x());
    potential_force_.set_y (new_value.y());
    potential_force_.set_z (new_value.z());
}

void Atom_kit::
set_velocity (Vector_3D const & new_value)
{
    velocity_.set_x (new_value.x());
    velocity_.set_y (new_value.y());
    velocity_.set_z (new_value.z());
}

void Atom_kit::
set_velocity (double fx, double fy, double fz)
{
    velocity_.set_x (fx);
    velocity_.set_y (fy);
    velocity_.set_z (fz);
}

void Atom_kit::
add_potential_force (Vector_3D const & value)
{
    potential_force_ += value;
}

void Atom_kit::
add_velocity (Vector_3D const & value)
{
    velocity_ += value;
}

void Atom_kit::
scale_velocity (double value)
{
    velocity_ *= value;
}


void Atom_kit::
set_bond_stretch_force (Vector_3D const & new_value)
{
    bond_stretch_force_.set_x (new_value.x());
    bond_stretch_force_.set_y (new_value.y());
    bond_stretch_force_.set_z (new_value.z());
}

void Atom_kit::
add_bond_stretch_force (Vector_3D const & value)
{
    bond_stretch_force_ += value;
}

void Atom_kit::
set_angle_force (Vector_3D const & new_value)
{
    angle_force_.set_x (new_value.x());
    angle_force_.set_y (new_value.y());
    angle_force_.set_z (new_value.z());
}

void Atom_kit::
add_angle_force (Vector_3D const & value)
{
    angle_force_ += value;
}

void Atom_kit::
set_torsion_force (Vector_3D const & new_value)
{
    torsion_force_.set_x (new_value.x());
    torsion_force_.set_y (new_value.y());
    torsion_force_.set_z (new_value.z());
}

void Atom_kit::
add_torsion_force (Vector_3D const & value)
{
    torsion_force_ += value;
}

void Atom_kit::
set_improper_force (Vector_3D const & new_value)
{
    improper_force_.set_x (new_value.x());
    improper_force_.set_y (new_value.y());
    improper_force_.set_z (new_value.z());
}

void Atom_kit::
add_improper_force (Vector_3D const & value)
{
    improper_force_ += value;
}

void Atom_kit::
set_nonbonded_force (Vector_3D const & new_value)
{
    nonbonded_force_.set_x (new_value.x());
    nonbonded_force_.set_y (new_value.y());
    nonbonded_force_.set_z (new_value.z());
}

void Atom_kit::
add_nonbonded_force (Vector_3D const & value)
{
    nonbonded_force_ += value;
}

void Atom_kit::
set_short_nonbonded_force (Vector_3D const & new_value)
{
    short_nonbonded_force_.set_x (new_value.x());
    short_nonbonded_force_.set_y (new_value.y());
    short_nonbonded_force_.set_z (new_value.z());
}

void Atom_kit::
add_short_nonbonded_force (Vector_3D const & value)
{
    short_nonbonded_force_ += value;
}

void Atom_kit::
set_long_nonbonded_force (Vector_3D const & new_value)
{
    long_nonbonded_force_.set_x (new_value.x());
    long_nonbonded_force_.set_y (new_value.y());
    long_nonbonded_force_.set_z (new_value.z());
}

void Atom_kit::
add_long_nonbonded_force (Vector_3D const & value)
{
    long_nonbonded_force_ += value;
}



}//MM
