#include "Project_impl.h"

#include "New_model.h"
#include "Model_proxy.h"
#include "Model_kit.h"

namespace MM
{

namespace//fix names or move to method
{
    /*struct Set_current_model : public Command
    {
        void execute () 
        {
            Protocol & protocol = Project::singleton().kit().protocol();
            Model    & current  = Project::singleton().current_model ();
            protocol.set_model (current);
        }
    };//*/

    /*struct Orphan_model : public Command_1 <Model *>
    {
        void execute (Model *model) 
        {
            Project  & project  = Project::singleton();
            Protocol & protocol = project.kit().protocol();
            
            Model    & current  = project.model_count() == 0 
                ? Model::none ()
                : project.current_model ();
            
            Model    * model_in_protocol = protocol.model().real_model ();

            if (model_in_protocol == model)
                protocol.set_model (current);
        }
    };//*/
}

Project_impl::
Project_impl () : current_model_(&Model::none())
{
    //on_change_current (new Set_current_model, true);
    //on_orphan         (new Orphan_model,      true);
}

Model * Project_impl::
orphan (Model & model)
{
    int model_count = model_.size();

    Model * result = model_.orphan (model);

    if (model_.size() == 0)
        set_current_model (Model::none());
    else
        set_current_model (model_[0]);

    orphan_event_.publish (*result);

    ENSURE ("One model removed.",  model_.size() == 1 ||
        model_.size() == model_count - 1);
    return result;
}

Model * Project_impl::
orphan (int index)
{
    int model_count = model_.size();

    Model * result = model_.orphan (index);

    if (model_.size() == 0)
        set_current_model (Model::none());
    else
        set_current_model (model_[0]);

    orphan_event_.publish (*result);

    ENSURE ("One model removed.", 
        model_.size() == model_count - 1);
    return result;
}

void Project_impl::
adopt (Model * adoptee)
{
    model_.push_back     (adoptee);
    set_current_model    (adoptee);       //fix remove? Check active windows managment

    adopt_event_.publish (*adoptee);
}

Model & Project_impl::
current_model ()
{
    if (current_model_ == &Model::none()) 
        New_model().execute();

    ENSURE ("", current_model_ != &Model::none());
    return *current_model_;
}

const Model & Project_impl::
current_model () const
{
    if (current_model_ == &Model::none()) 
        New_model().execute();

    ENSURE ("", current_model_ != &Model::none());
    return *current_model_;
}

void Project_impl::
set_current_model (Model & model)
{
    set_current_model (&model);
}

void Project_impl::
set_current_model (Model * model)
{
    if (model != current_model_)
    {
        if (model != 0 && model != &Model::none ())
        {
            current_model_ = model;
            Protocol & protocol = kit().protocol();
            protocol.set_model (*model);
            model->kit().visual().set_focus();
        }
        else
        {
            current_model_ = &Model::none ();
            Protocol & protocol = kit().protocol();
            protocol.set_model (Model::none ());
        }
    }
    change_current_event_.publish (*current_model_);
}

void Project_impl::
on_change_current (Command_1 <Model&> *adoptee, bool on)
{
    change_current_event_.subscribe (adoptee, on);
}

void Project_impl::
on_adopt (Command_1<Model&> *adoptee, bool on)
{
    adopt_event_.subscribe (adoptee, on);
}

void Project_impl::
on_orphan (Command_1<Model&> *adoptee, bool on)
{
    orphan_event_.subscribe (adoptee, on);
}

int Project_impl::
model_count () const
{
    return model_.size();
}

Model & Project_impl::
model (int i) 
{
    return model_[i];
}

const Model & Project_impl::
model (int i) const
{
    return model_[i];
}

}//MM
