/* 
 * © 2007-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
#include "stdafx.h"

#include "model_connection_impl.h"
#include "model_figure_impl.h"
#include "model_diagram_impl.h"
#include "model_model_impl.h"



model_Connection::ImplData::ImplData(model_Connection *self)
  : model_Object::ImplData(self), _line(0),
  _above_caption(0), _below_caption(0), _start_caption(0), _end_caption(0)
{
  self->signal_changed().connect(sigc::mem_fun(this, &ImplData::member_changed));
}


void model_Connection::ImplData::unrealize()
{
   if (_line)
     _line->get_view()->remove_item(_line);

   delete _line;
   _line= 0;

   delete _above_caption;
   delete _below_caption;
   delete _start_caption;
   delete _end_caption;

   _above_caption= 0;
   _below_caption= 0;
   _start_caption= 0;
   _end_caption= 0;
}


void model_Connection::ImplData::object_realized(const model_ObjectRef &object)
{
  if (object == self()->_startFigure || object == self()->_endFigure)
    try_realize();
}


void model_Connection::ImplData::member_changed(const std::string &name, const grt::ValueRef &ovalue)
{
  if (_line)
  {
    if (name == "drawSplit")
      _line->set_splitted(*self()->_drawSplit != 0);
    else if (name == "visible")
    {
      _line->set_visible(*self()->_visible != 0);
      if (_above_caption)
        _above_caption->set_visible(*self()->_visible != 0);
      if (_below_caption)
        _below_caption->set_visible(*self()->_visible != 0);
      if (_start_caption)
        _start_caption->set_visible(*self()->_visible != 0);
      if (_end_caption)
        _end_caption->set_visible(*self()->_visible != 0);
    }
    /* this step should be done by the concrete subclass
    else if (name == "endFigure" || name == "startFigure")
    {
      unrealize();
      try_realize();
    } */
    else if (name == "owner")
    {
      if (!_object_realized && self()->owner().is_valid())
        _object_realized= self()->owner()->get_data()->signal_object_realized().
          connect(sigc::mem_fun(this, &ImplData::object_realized));
    }
  }
}


mdc::CanvasItem *model_Connection::ImplData::get_start_canvas_item()
{
  if (self()->_startFigure.is_valid())
  {
    model_Figure::ImplData *bridge= self()->_startFigure->get_data();
  
    if (bridge)
      return bridge->get_canvas_item();
  }
  return 0;
}


mdc::CanvasItem *model_Connection::ImplData::get_end_canvas_item()
{
  if (self()->_endFigure.is_valid())
  {
    model_Figure::ImplData *bridge= self()->_endFigure->get_data();
  
    if (bridge)
      return bridge->get_canvas_item();
  }
  return 0;
}


bool model_Connection::ImplData::is_realizable()
{
  if (_in_view && self()->owner().is_valid())
  {
    try
    {
      if (get_canvas_view() && get_start_canvas_item() && get_end_canvas_item())
        return true;
    }
    catch (std::exception)
    {
      return false;
    }
  }
  return false;
}


mdc::CanvasView *model_Connection::ImplData::get_canvas_view() const
{
  if (self()->owner().is_valid())
  {
    model_Diagram::ImplData *view= self()->owner()->get_data();
    if (view)
      return view->get_canvas_view();
  }
  return 0;
}


void model_Connection::ImplData::set_above_caption(const std::string &text)
{
  if (text.empty())
  {
    delete _above_caption;
    _above_caption= 0;
    return;
  }

  if (self()->owner()->owner()->get_data()->get_int_option("workbench.physical.Connection:HideCaptions", 0) != 0)
  {
    delete _above_caption;
    _above_caption= 0;
    return;
  }

  if (!_above_caption)
  {
    _above_caption= new wbfig::CaptionFigure(_line->get_layer(), self()->owner()->get_data(), self());
    _above_caption->set_tag(self()->id());
    _above_caption->set_font(_caption_font);
    _line->get_layer()->add_item(_above_caption);
    _above_caption->set_fill_background(false);
    _above_caption->set_draggable(true);
    _above_caption->set_accepts_selection(true);
    _above_caption->set_visible(*self()->_visible != 0);
    _above_caption->signal_bounds_changed().
      connect(sigc::bind<mdc::TextFigure*>(sigc::mem_fun(this, &model_Connection::ImplData::caption_bounds_changed), _above_caption));
  }
  _above_caption->set_text(text);

  update_above_caption_pos();
}


void model_Connection::ImplData::set_below_caption(const std::string &text)
{
  if (text.empty())
  {
    delete _below_caption;
    _below_caption= 0;
    return;
  }

  if (self()->owner()->owner()->get_data()->get_int_option("workbench.physical.Connection:HideCaptions", 0) != 0)
  {
    delete _below_caption;
    _below_caption= 0;
    return;
  }

  if (!_below_caption)
  {
    _below_caption= new wbfig::CaptionFigure(_line->get_layer(), self()->owner()->get_data(), self());
    _below_caption->set_tag(self()->id());
    _below_caption->set_font(_caption_font);
    _line->get_layer()->add_item(_below_caption);
    _below_caption->set_fill_background(false);
    _below_caption->set_draggable(true);
    _below_caption->set_accepts_selection(true);
    _below_caption->set_visible(*self()->_visible != 0);
    _below_caption->signal_bounds_changed().
      connect(sigc::bind<mdc::TextFigure*>(sigc::mem_fun(this, &model_Connection::ImplData::caption_bounds_changed), _below_caption));
  }
  _below_caption->set_text(text);

  update_below_caption_pos();
}


void model_Connection::ImplData::set_start_caption(const std::string &text)
{
  if (text.empty())
  {
    delete _start_caption;
    _start_caption= 0;
    return;
  }

  if (!_start_caption)
  {
    _start_caption= new wbfig::CaptionFigure(_line->get_layer(), self()->owner()->get_data(), self());
    _start_caption->set_tag(self()->id());
    _start_caption->set_font(_caption_font);
    _line->get_layer()->add_item(_start_caption);
    _start_caption->set_fill_color(mdc::Color::White());
    _start_caption->set_fill_background(true);
    _start_caption->set_draggable(true);
    _start_caption->set_accepts_selection(true);
    _start_caption->set_visible(*self()->_visible != 0);
    _start_caption->signal_bounds_changed().
      connect(sigc::bind<mdc::TextFigure*>(sigc::mem_fun(this, &model_Connection::ImplData::caption_bounds_changed), _start_caption));
  }
  _start_caption->set_text(text);

  update_start_caption_pos();
}


void model_Connection::ImplData::set_end_caption(const std::string &text)
{
  if (text.empty())
  {
    delete _end_caption;
    _end_caption= 0;
    return;
  }

  if (!_end_caption)
  {
    _end_caption= new wbfig::CaptionFigure(_line->get_layer(), self()->owner()->get_data(), self());
    _end_caption->set_tag(self()->id());
    _end_caption->set_font(_caption_font);
    _line->get_layer()->add_item(_end_caption);
    _end_caption->set_fill_color(mdc::Color::White());
    _end_caption->set_fill_background(true);
    _end_caption->set_draggable(true);
    _end_caption->set_accepts_selection(true);
    _end_caption->set_visible(*self()->_visible != 0);
    _end_caption->signal_bounds_changed().
      connect(sigc::bind<mdc::TextFigure*>(sigc::mem_fun(this, &model_Connection::ImplData::caption_bounds_changed), _end_caption));
  }
  _end_caption->set_text(text);

  update_end_caption_pos();
}



void model_Connection::ImplData::caption_bounds_changed(const mdc::Rect &obounds, mdc::TextFigure *figure)
{
  if (figure == _above_caption)
    _above_offset= figure->get_root_position() - _line->get_middle_caption_pos(_above_caption->get_size(), wbfig::Connection::Above);
  else if (figure == _below_caption)
    _below_offset= figure->get_root_position() - _line->get_middle_caption_pos(_below_caption->get_size(), wbfig::Connection::Below);
  else if (figure == _start_caption)
    _start_offset= figure->get_root_position() - _line->get_start_caption_pos(_start_caption->get_size());
  else if (figure == _end_caption)
    _end_offset= figure->get_root_position() - _line->get_end_caption_pos(_end_caption->get_size());
}


void model_Connection::ImplData::update_above_caption_pos()
{
  mdc::Point pos= _line->get_middle_caption_pos(_above_caption->get_min_size(), wbfig::Connection::Above);

  _above_caption->move_to(pos + _above_offset);
}


void model_Connection::ImplData::update_below_caption_pos()
{
  mdc::Point pos= _line->get_middle_caption_pos(_below_caption->get_min_size(), wbfig::Connection::Below);

  _below_caption->move_to(pos + _below_offset);
}


void model_Connection::ImplData::update_start_caption_pos()
{
  mdc::Point pos= _line->get_start_caption_pos(_start_caption->get_min_size());

  _start_caption->move_to(pos + _start_offset);
}


void model_Connection::ImplData::update_end_caption_pos()
{
  mdc::Point pos= _line->get_end_caption_pos(_end_caption->get_min_size());

  _end_caption->move_to(pos + _end_offset);
}


void model_Connection::ImplData::layout_changed()
{
  if (_above_caption)
    update_above_caption_pos();

  if (_below_caption)
    update_below_caption_pos();

  if (_start_caption)
    update_start_caption_pos();

  if (_end_caption)
    update_end_caption_pos();
}


void model_Connection::ImplData::finish_realize()
{  
  _line->set_tag(self()->id());

  _line->set_splitted(*self()->_drawSplit != 0);

  if (self()->owner()->owner()->get_data()->get_int_option("workbench.physical.Connection:CenterCaptions", 0) != 0)
    _line->set_center_captions(true);
  else
    _line->set_center_captions(false);

  _line->set_visible(*self()->_visible != 0);
  if (_above_caption)
    _above_caption->set_visible(*self()->_visible != 0);
  if (_below_caption)
    _below_caption->set_visible(*self()->_visible != 0);
  if (_start_caption)
    _start_caption->set_visible(*self()->_visible != 0);
  if (_end_caption)
    _end_caption->set_visible(*self()->_visible != 0);

  std::string font= self()->owner()->owner()->get_data()->get_string_option(strfmt("%s:CaptionFont", self()->class_name().c_str()), "");
  if (!font.empty())
    _caption_font= parse_font_spec(font);

  _line->signal_layout_changed().connect(sigc::mem_fun(this, &model_Connection::ImplData::layout_changed));

  self()->owner()->get_data()->stack_connection(model_ConnectionRef(self()), _line);

  _object_realized.disconnect();
}

