#include "Boundary_conditions.h"

#include "Peep.h"

#include "Box_impl.h"
#include "Model.h"
#include "Model_kit.h"
#include "Command_template.h"

namespace MM
{
Boundary_conditions::
Boundary_conditions (Model_kit & kit)
:
    model_              (kit.model()),
    type_               ("Vacuum"),
    box_                (&kit.crystal_cell()),
    is_auto_box_        (false),
    is_auto_box_valid_  (false)
{
    set_type ("Box");
    ///accept_crystal_cell_as_a_box ();
    set_type ("Vacuum");


    //Model_event &e = model.kit().event();
    //Command *c = create_command (*this, &Boundary_conditions::update);
    //e.when_conformation_changed (c);
}

Boundary_conditions::
~Boundary_conditions ()
{
    box_= 0;
}

Text const & Boundary_conditions::
type_name () const
{
    return type_;
}

void Boundary_conditions::
set_type (Text const & new_type)
{
    if (new_type == "Vacuum")
    {
        type_ = new_type;
    }
    else if (new_type == "Box")
    {
        type_ = new_type;
        if (box_ == 0)
            box_ = box_janitor_.adopt (new Box_impl());
    }
    else
        FLAW (new_type + " - no such type. (Boundary_conditions::set_type)");
}

void Boundary_conditions::
update (Model_event::Hint)
{
    Peep().execute();

    if (type_ == "Vacuum")
    {
    }
    else if (type_ == "Box")
    {
        is_auto_box_valid_ = false;
    }
    else
        FLAW (type_ + " - no such type. (Boundary_conditions::update)");
}

Box & Boundary_conditions::
box ()
{
    REQUIRE ("", type_=="Box");
    REQUIRE ("", box_!=0);

    if (is_auto_box_ && !is_auto_box_valid_)
        recalculate_auto_box ();

    return *box_;
}

Box const& Boundary_conditions::
box () const
{
    REQUIRE ("", type_=="Box");
    REQUIRE ("", box_!=0);

    REQUIRE ("", !(is_auto_box_ && !is_auto_box_valid_));

    return *box_;
}

bool Boundary_conditions::
is_box_a_crystal_cell () const
{
    //return & model_.kit().crystal_cell () == box_;
    return model_.kit().has_crystal_cell () 
        && &model_.kit().crystal_cell () == box_;
}

bool Boundary_conditions::
is_auto_box () const
{
    return is_auto_box_;
}

void Boundary_conditions::
accept_crystal_cell_as_a_box ()
{
	Model_kit & kit = model_.kit();
	Box & box = kit.crystal_cell();
	set_box (box);

//    set_box (model_.kit().crystal_cell ());
}

void Boundary_conditions::
reject_crystal_cell_as_a_box ()
{
    REQUIRE ("Crystal cell is a box.", is_box_a_crystal_cell ());
    REQUIRE ("", box_janitor_.is_not_valid());

    Box *new_box = new Box_impl ();
    new_box->set (box_->a(), box_->b(), box_->c());
    adopt_box (new_box);
}

void Boundary_conditions::
set_box (Box & new_box)
{
    if (box_janitor_.is_valid())
        delete box_janitor_.orphan();

    box_ = &new_box;
    type_="Box";
}

void Boundary_conditions::
adopt_box (Box * adoptee)
{
    box_ =  box_janitor_.adopt (adoptee);
    type_="Box";
}

void Boundary_conditions::
set_auto_box (bool on)
{
    is_auto_box_ = on;
    is_auto_box_valid_ = false;

    model().kit().event().when_model_changed
        (create_command_1 (*this, &Boundary_conditions::update), on);
}

void Boundary_conditions::
recalculate_auto_box()
{
    //FIX;
    auto_box_recalculated_.publish ();
}

void Boundary_conditions::
when_auto_box_recalculated (Command *to_do, bool on)
{
    auto_box_recalculated_.subscribe (to_do, on);
}

}//MM

