#include "OpenRM_atom.h"

#include "Atom.h"
#include "Atom_kit.h"
#include "View_atom_type.h"
#include "OpenRMWidget.h"
#include "HSV.h"
#include "Flaw.h"

#include <rm/rm.h>

namespace MM
{
Atom_kit &          OpenRM_atom::kit ()         {return kit_;}
Atom_kit const &    OpenRM_atom::kit () const   {return kit_;}

OpenRM_atom::
OpenRM_atom (Atom_kit & kit, RMnode *parent_node, OpenRMWidget *rm_widget)
:
    kit_        (kit),
    atom_node_  (0),
    parent_node_(parent_node),
    rm_widget_  (rm_widget),
    show_flag_  (true),
    style_      (Visual_style::CPK),
    CPK_node_   (0),
    sphere_     (0)
{
    REQUIRE ("", parent_node != 0); 
    REQUIRE ("", rm_widget   != 0);
}

OpenRM_atom::
~OpenRM_atom ()
{
    RMenum result;

    // for prototype:
    if (CPK_node_ == 0)
        return;

    show (false);

    result = rmNodeDelete (CPK_node_);
    if (result == RM_WHACKED)
        FLAW ("rmNodeDelete");
    
    show_flag_ = false;
    rm_widget_->update ();
}

Visual_atom * OpenRM_atom::
clone (Atom_kit & kit) const
{
    OpenRM_atom *result = new OpenRM_atom (kit, parent_node_, rm_widget_);

    RMenum      res = RM_WHACKED;
    
    result->sphere_ = rmPrimitiveNew (RM_SPHERES);
    if (result->sphere_ == 0)
        FLAW ("rmPrimitiveNew @ OpenRM_atom::clone");

    //result->atom_node_ = rmNodeNew ("Atom",  RM_RENDERPASS_ALL, RM_RENDERPASS_ALL);
    result->CPK_node_ = rmNodeNew ("Atom",  RM_RENDERPASS_3D, RM_RENDERPASS_OPAQUE);
    if (result->CPK_node_ == 0)
        FLAW ("rmNodeNew @ OpenRM_atom::clone");

    //rmPrimitiveSetModelFlag (result->sphere_, RM_SPHERES_32);    
    //rmPrimitiveSetModelFlag (result->sphere_, RM_SPHERES_128);   
    rmPrimitiveSetModelFlag (result->sphere_, RM_SPHERES_512);

    res = rmNodeAddPrimitive (result->CPK_node_, result->sphere_);      
    if (res == RM_WHACKED)
        FLAW ("rmNodeAddPrimitive @ OpenRM_atom::clone");

    res = rmNodeSetClientData (result->CPK_node_, result, NULL);
    if (res == RM_WHACKED)
        FLAW ("rmNodeSetClientData @ OpenRM_atom::clone");

    result->set_element ();
    result->set_style (style_);
    //result->renew ();

    ENSURE ("", result->sphere_      != 0);
    ENSURE ("", result->CPK_node_    != 0);
    ENSURE ("", result->parent_node_ != 0);
    ENSURE ("", result->rm_widget_   != 0);
    return result;

    //rmNodeSetPreTraversalCallback (atom_node_,RM_VIEW, rmNodeFrustumCullCallback);//*/
}

void OpenRM_atom::
set_element ()
{
    RMcolor4D color;
    style_.color (kit().atom(), color.r, color.g, color.b, color.a);

    rmPrimitiveSetColor4D (sphere_, 1, &color,  RM_COPY_DATA, NULL);
    //rmPrimitiveSetModelFlag (sphere_, RM_SPHERES_512);
}

void OpenRM_atom::
show (bool on)
{
    if (on)
    {
        if (show_flag_ == false)
        {
            rmNodeAddChild (parent_node_, atom_node_);
            show_flag_ = true;
            renew ();
        }
        //show_flag_ = true;
    }
    else
    {
        if (show_flag_ == true && atom_node_ !=0)
        {
            rmNodeRemoveChild (parent_node_, atom_node_);
            show_flag_ = false;
            renew ();
        }
        //show_flag_ = false;
    }
}

void OpenRM_atom::
renew_view ()
{
    RMcolor4D color;
    style_.color (kit().atom(), color.r, color.g, color.b, color.a);

    if (kit_.was_frozen())
    {
        //color.r += 2.5;     color.g += 2.5;     color.b += .7;


        //color.r += 2.5;   color.g += 2.5;     color.b += 2.5;

        //color.r *= .28F;  color.g *= 1.5F;    color.b *= 1.5F;
        ////color.r *= .125F; color.g *= 0.08F;   color.b *= .75F;
        color.r = 0.85F;  color.g = 0.99F;    color.b = 1.F;
   }

    if (kit_.is_selected())
    {
        color.r *= .6F;
        color.g *= .25F;
        color.b *= .6F;
        //color.r *= .3F;
        //color.g *= .2F;
        //color.b *= .3F;

        //color.r += .1F;
        //color.g += .1F;
        //color.b += .1F;
    }

    if (kit_.is_picked())
    {
        color.r = float ((color.r * 0.5) + .40);
        color.g = float ((color.g * 0.5) + .40);
        color.b = float ((color.b * 0.5) + .30);
    }

    rmPrimitiveSetColor4D (sphere_, 1, &color, RM_COPY_DATA, NULL);
    rm_widget_->update ();
}

void OpenRM_atom::
renew_coordinates ()
{
    Atom & atom = kit().atom();

    RMvertex3D  vertex;    
    vertex.x = float(atom.x());    
    vertex.y = float(atom.y());
    vertex.z = float(atom.z());

    rmPrimitiveSetVertex3D (sphere_, 1, &vertex, RM_COPY_DATA, NULL);
    
    rm_widget_->update ();
}

void OpenRM_atom::
set_color (int R, int G, int B)
{
    style_.set_special_color (float (R / 255.0), 
                              float (G / 255.0), 
                              float (B / 255.0));
    renew_view ();
}

void OpenRM_atom::
set_level_of_details (int lod)
{
    switch (lod)
    {
    case 0: rmPrimitiveSetModelFlag (sphere_, RM_SPHERES_8);
            break;
    case 1: rmPrimitiveSetModelFlag (sphere_, RM_SPHERES_32);
            break;
    case 2: rmPrimitiveSetModelFlag (sphere_, RM_SPHERES_128);
            break;
    case 3: rmPrimitiveSetModelFlag (sphere_, RM_SPHERES_512);
            break;
    default: rmPrimitiveSetModelFlag (sphere_, RM_SPHERES_512);
    }
}

void OpenRM_atom::
set_style (Visual_style const & style)
{
    style_ = style;

    if (!show_flag_ || CPK_node_==0) //fix prototype hack
        return;

    if (atom_node_ !=0)
        rmNodeRemoveChild (parent_node_, atom_node_);


    float radius = style.radius (kit_.atom ());

    if (style.type() == Visual_style::wireframe)
        atom_node_ = 0;
    else
        atom_node_ = CPK_node_;

    rmPrimitiveSetRadii (sphere_, 1, &radius, RM_COPY_DATA, NULL);

    if (atom_node_ != 0)
    {
        RMenum res = rmNodeAddChild (parent_node_, atom_node_);
        if (res == RM_WHACKED)
            FLAW ("rmNodeAddChild    @ OpenRM_atom::set_type");
    }

    renew_coordinates ();
    renew_view ();
}

void OpenRM_atom::
renew_model ()
{
    rm_widget_->update ();
}

void OpenRM_atom::
renew ()
{
    set_element ();
    set_style (style_);
    //renew_view ();
    renew_model ();
}

}//MM



