
#include "shell_view.h"
#include "grt/grt_manager.h"
#include "auto_completable.h"


ShellCommandView::ShellCommandView(bec::GRTManager *grtm)
  : Gtk::VBox(false, 8)
  , _completion(0)
  , _grtm(grtm)
{  
  _text_scroller.add(_text);
  _text_scroller.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
  
  Gtk::TextBuffer::iterator iter= _text.get_buffer()->end();
  _text.get_buffer()->create_mark("scroll", iter, true);
  _text.set_wrap_mode(Gtk::WRAP_WORD);
  _text.set_left_margin(4);

  pack_start(_text_scroller, true, true);
  
  Gtk::HBox *hbox= Gtk::manage(new Gtk::HBox(false, 4));
  hbox->pack_start(_prompt, false, true);
  hbox->pack_start(_entry, true, true);
  pack_start(*hbox, false, false);

  _text.set_name("shell_text");
  _text.set_editable(false);

  show_all_children();
  _entry.signal_activate().connect(sigc::mem_fun(this, &ShellCommandView::activate_entry));
  _entry.signal_key_press_event().connect(sigc::mem_fun(this, &ShellCommandView::key_press));
  _completion = new AutoCompletable(&_entry);
  _completion->set_popup_enabled(false);
  //fill completion table with history
  bec::ShellBE *sbe = _grtm->get_shell();
  
  std::string line;
  while (sbe->next_history_line(line))
    _completion->add_completion_text(line);  
  
  signal_show().connect(sigc::mem_fun(_entry, &Gtk::Widget::grab_focus));
}


ShellCommandView::~ShellCommandView()
{
  delete _completion;
}

void ShellCommandView::setup_shell_handlers()
{
  _grtm->get_shell()->set_ready_handler(sigc::mem_fun(this, &ShellCommandView::handle_prompt));
  _grtm->get_shell()->set_output_handler(sigc::mem_fun(this, &ShellCommandView::handle_output));
}


void ShellCommandView::activate_entry()
{  
  std::string command= _entry.get_text();
  _completion->add_completion_text(command);
  _entry.set_text("");

  command += '\n';
  _grtm->get_shell()->write(_prompt.get_text()+" "+command);
  _grtm->get_shell()->process_line_async(command);
}


bool ShellCommandView::key_press(GdkEventKey* key)
{
  bool ret = false;
  if (key->keyval == GDK_Up)
  {
    std::string line;
    if (_grtm->get_shell()->previous_history_line(_entry.get_text(), line))
    {
      line.resize(line.length() - 1);
      _entry.set_text(line);
    }
    ret = true;
  }
  else if (key->keyval == GDK_Down)
  {
    std::string line;
    if (_grtm->get_shell()->next_history_line(line))
    {
      if (line.length() > 0)
      {
        line.resize(line.length() - 1);
        _entry.set_text(line);
      }
    }
    ret = true;
  }
  return ret;
}

void ShellCommandView::handle_output(const std::string &text)
{
  _text.get_buffer()->insert(_text.get_buffer()->end(), text);
  
  Gtk::TextBuffer::iterator iter= _text.get_buffer()->end();
  Glib::RefPtr<Gtk::TextMark> mark= _text.get_buffer()->get_mark("scroll");
  _text.get_buffer()->move_mark(mark, iter);
  _text.scroll_mark_onscreen(mark);
}


void ShellCommandView::handle_error(const std::string &text, const std::string &detail)
{  
  _text.get_buffer()->insert(_text.get_buffer()->end(), text);
  
  _text.get_buffer()->insert(_text.get_buffer()->end(), detail);

  Gtk::TextBuffer::iterator iter= _text.get_buffer()->end();
  Glib::RefPtr<Gtk::TextMark> mark= _text.get_buffer()->get_mark("scroll");
  _text.get_buffer()->move_mark(mark, iter);
  _text.scroll_mark_onscreen(mark);
}


void ShellCommandView::handle_prompt(const std::string &text)
{
  _prompt.set_text(text);
}



//--------------------------------------------------------------------------------

ShellTreeViews::ShellTreeViews(bec::GRTManager *grtm)
  : _grtm(grtm)
{
  _value_swin.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
  _value_swin.add(_value_tree);
  _value_swin.set_shadow_type(Gtk::SHADOW_IN);
  _value_tree.set_headers_visible(false);

  _struct_swin.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
  _struct_swin.add(_struct_tree);
  _struct_swin.set_shadow_type(Gtk::SHADOW_IN);
  _struct_tree.set_headers_visible(false);
  
  _module_swin.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
  _module_swin.add(_module_tree);
  _module_swin.set_shadow_type(Gtk::SHADOW_IN);
  _module_tree.set_headers_visible(false);

  _inspector_swin.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
  _inspector_swin.add(_inspector_tree);
  _inspector_swin.set_shadow_type(Gtk::SHADOW_IN);
  _inspector_tree.set_headers_visible(true);
  _inspector_tree.show();

  _grtm->get_shared_structs_tree()->refresh();
  _grtm->get_shared_modules_tree()->refresh();

  _value_tree_be= _grtm->get_shared_value_tree("/");
  _values_model= TreeModelWrapper::create(_value_tree_be, &_value_tree, "ShellTreeViews_value_tree");
  _values_model->model().append_string_column(bec::ValueTreeBE::Name, _("Name"), RO, WITH_ICON);
  _values_model->model().append_string_column(bec::ValueTreeBE::Type, _("Type"), RO, NO_ICON);
  _value_tree.set_model(_values_model);


  _value_tree.get_selection()->signal_changed().connect(sigc::mem_fun(this, &ShellTreeViews::value_selected));

  _structs_model= TreeModelWrapper::create(_grtm->get_shared_structs_tree(), &_struct_tree, "ShellTreeViews_structs_model");
  _structs_model->model().append_string_column(bec::StructsTreeBE::Name, _("Class"), RO, WITH_ICON);
  _struct_tree.set_model(_structs_model);

  _modules_model= TreeModelWrapper::create(_grtm->get_shared_modules_tree(), &_module_tree, "ShellTreeViews_modules_model");
  _modules_model->model().append_string_column(bec::ModulesTreeBE::Name, _("Module"), RO, WITH_ICON);
  _module_tree.set_model(_modules_model);

  _module_text.set_name("module_docs");
  _module_text.set_editable(false);
  _module_text.set_cursor_visible(false);
//  _module_text.set_wrap_mode(Gtk::WRAP_WORD);
  
  _module_text_swin.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_NEVER);
  _module_text_swin.add(_module_text);
  _module_text_swin.set_shadow_type(Gtk::SHADOW_IN);
  _module_text.show();

  _bold_tag= _module_text.get_buffer()->create_tag();
  _bold_tag->property_weight()= Pango::WEIGHT_BOLD;

  _module_tree.get_selection()->signal_changed().connect(sigc::mem_fun(this, &ShellTreeViews::module_selected));

  _inspector= 0;
}


void ShellTreeViews::set_globals_tree_path(const std::string &path)
{
  try
  {
    if (path.empty() || path[0] != '/')
      _grtm->get_shared_value_tree("/");
    else
      _grtm->get_shared_value_tree(path);

    refresh_all();
  }
  catch (std::exception &exc)
  {
    g_message("%s", exc.what());
  }
}


void ShellTreeViews::refresh_all()
{  
  //refresh values
  bec::ListModel* m = _values_model->get_be_model();
  _values_model->set_be_model(0);
  _value_tree.unset_model();
  _value_tree.set_model(_values_model);

  _values_model->set_be_model(m);
  _value_tree.unset_model();
  _value_tree_be->refresh();
  _grtm->get_shared_structs_tree()->refresh();
  _grtm->get_shared_modules_tree()->refresh();
  _value_tree.set_model(_values_model);
  
  _value_tree.expand_row(Gtk::TreePath("0"), false);

  //refresh _struct
  m = _structs_model->get_be_model();
  _structs_model->set_be_model(0);
  _struct_tree.unset_model();
  _struct_tree.set_model(_structs_model);

  _structs_model->set_be_model(m);
  _struct_tree.unset_model();
  _struct_tree.set_model(_structs_model);

  // refresh modules
  m = _modules_model->get_be_model();
  _modules_model->set_be_model(0);
  _module_tree.unset_model();
  _module_tree.set_model(_modules_model);

  _modules_model->set_be_model(m);
  _module_tree.unset_model();
  _module_tree.set_model(_modules_model);

  if (_inspector_model)
  {
    m = _inspector_model->get_be_model();
    _inspector_model->set_be_model(0);
    _inspector_tree.unset_model();
    _inspector_tree.set_model(_inspector_model);

    _inspector_model->set_be_model(m);
    _inspector_tree.unset_model();
    _inspector_tree.set_model(_inspector_model);
  }
}


void ShellTreeViews::set_struct_sorting(bec::StructsTreeBE::DisplayMode mode)
{
  _struct_tree.unset_model();
  _grtm->get_shared_structs_tree()->set_display_mode(mode);
  _struct_tree.set_model(_structs_model);
}


void ShellTreeViews::value_selected()
{
  if (_inspector)
  {
    _inspector_tree.unset_model();
    delete _inspector;
    _inspector= 0;
  }
  
  Gtk::TreeIter iter= _value_tree.get_selection()->get_selected();

  if (iter)
  {
    bec::NodeId node(_values_model->node_for_iter(iter));
    grt::ValueRef value(_value_tree_be->get_node_value(node));
  
    if (value.is_valid())
    {
      _inspector_tree.remove_all_columns();
      _inspector= _grtm->get_new_value_inspector(value, false);
      _inspector_model= ListModelWrapper::create(_inspector, &_inspector_tree, "ShellTreeViews_inspector_model");
      _inspector_model->model().append_string_column(bec::ValueInspectorBE::Name, _("Name"), RO, WITH_ICON);
      _inspector_model->model().append_string_column(bec::ValueInspectorBE::Value, _("Value"), EDITABLE);
      _inspector_tree.set_model(_inspector_model);
    }
  }
}


void ShellTreeViews::module_selected()
{  
  Gtk::TreeIter iter= _module_tree.get_selection()->get_selected();

  if (iter)
  {
    bec::NodeId node(_modules_model->node_for_iter(iter));
    std::string text(_grtm->get_shared_modules_tree()->get_field_description(node, 0));
  
    _module_text.get_buffer()->set_text(text);
  }
  else
    _module_text.get_buffer()->set_text("");
  
  Gtk::TextBuffer::iterator end, begin= _module_text.get_buffer()->get_iter_at_line(0);
  end= begin;
  end.forward_line();
  
  _module_text.get_buffer()->apply_tag(_bold_tag, begin, end);
}


//--------------------------------------------------------------------------------

ShellView::ShellView(bec::GRTManager *grtm)
  : _command_view(grtm), _shell_trees(grtm)
{  
  add1(_command_view);
  add2(_note);
  
  _note.append_page(*_shell_trees.get_value_tree_base(), "GRT Tree");  
  _note.append_page(*_shell_trees.get_struct_tree_base(), "Classes");
  _note.append_page(*_shell_trees.get_module_tree_base(), "Modules");

  _note.set_tab_pos(Gtk::POS_BOTTOM);

  _command_view.setup_shell_handlers();
  
  show_all();
}


void ShellView::refresh()
{
  _shell_trees.refresh_all();
}



