/* 
 * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; version 2 of the
 * License.
 * 
 * This program 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */
#include "stdafx.h"

#include "grtdb_connection_editor.h"

#include "cppdbc.h"
#include <grt/common.h>
#include "base/string_utilities.h"

#include "mforms/uistyle.h"
#include "mforms/utilities.h"

//------------------------------------------------------------------------------
grtui::DbConnectionEditor::DbConnectionEditor(const db_mgmt_ManagementRef &mgmt)
  : mforms::Form(0)
  , _mgmt(mgmt)
  , _panel(false)
  , _top_vbox(false)
  , _top_hbox(true)
  , _conn_list_buttons_hbox(true)
  , _stored_connection_list(mforms::TreeDefault)
  , _bottom_hbox(true)
{
  set_title(_("Manage DB Connections"));
  
  _top_vbox.set_padding(MF_WINDOW_PADDING);
  _top_vbox.set_spacing(12);
  _top_hbox.set_spacing(8);
  _top_vbox.add(&_top_hbox, true, true);
  _top_vbox.add(&_bottom_hbox, false, true);
  
  _bottom_hbox.set_spacing(12);
  
  _panel.init(_mgmt);
  
  scoped_connect(_stored_connection_list.signal_changed(),boost::bind(&grtui::DbConnectionEditor::change_active_stored_conn, this));

  _conn_name= _panel.get_name_entry();
  scoped_connect(_conn_name->signal_changed(),boost::bind(&grtui::DbConnectionEditor::name_changed, this));


  _dup_conn_button.set_text(_("Duplicate"));
  scoped_connect(_dup_conn_button.signal_clicked(),boost::bind(&grtui::DbConnectionEditor::add_stored_conn, this, true));
  _del_conn_button.set_text(_("Delete"));
  scoped_connect(_del_conn_button.signal_clicked(),boost::bind(&grtui::DbConnectionEditor::del_stored_conn, this));
  _add_conn_button.set_text(_("New"));
  scoped_connect(_add_conn_button.signal_clicked(),boost::bind(&grtui::DbConnectionEditor::add_stored_conn, this, false));
  _move_up_button.set_text(_("Move Up"));
  scoped_connect(_move_up_button.signal_clicked(),boost::bind(&grtui::DbConnectionEditor::reorder_conn, this, true));
  _move_down_button.set_text(_("Move Down"));
  scoped_connect(_move_down_button.signal_clicked(),boost::bind(&grtui::DbConnectionEditor::reorder_conn, this, false));
  
  _top_hbox.add(&_stored_connection_list, false, true);  
  _top_hbox.add(&_panel, true, true);

  _bottom_hbox.add(&_add_conn_button, false, true);
  _bottom_hbox.add(&_del_conn_button, false, true);
  _bottom_hbox.add(&_dup_conn_button, false, true);
  _bottom_hbox.add(&_move_up_button, false, true);
  _bottom_hbox.add(&_move_down_button, false, true);
  
  _bottom_hbox.add_end(&_ok_button, false, true);
//  _bottom_hbox.add_end(&_cancel_button, false, true);
  _bottom_hbox.add_end(&_test_button, false, true);
  
  _ok_button.set_text(_("Close"));
  scoped_connect(_ok_button.signal_clicked(),boost::bind(&DbConnectionEditor::ok_clicked, this));
//  _cancel_button.set_text(_("Cancel"));
//  _cancel_button.signal_clicked().connect(boost::bind(&DbConnectionEditor::cancel_clicked, this));
  _test_button.set_text(_("Test Connection"));
  scoped_connect(_test_button.signal_clicked(),boost::bind(&DbConnectPanel::test_connection, boost::ref(_panel)));

  _add_conn_button.enable_internal_padding(true);
  _del_conn_button.enable_internal_padding(true);
  _ok_button.enable_internal_padding(true);
  _cancel_button.enable_internal_padding(true);  
  _test_button.enable_internal_padding(true);
  
  _stored_connection_list.set_size(180, -1);
  
  set_content(&_top_vbox);
  

  _stored_connection_list.add_column(::mforms::StringColumnType, _("Stored Connections"), 150, false);
  _stored_connection_list.end_columns();

  set_size(900, 500);
}

//------------------------------------------------------------------------------
grtui::DbConnectionEditor::~DbConnectionEditor()
{
}

//------------------------------------------------------------------------------
db_mgmt_ConnectionRef grtui::DbConnectionEditor::run(const db_mgmt_ConnectionRef &connection)
{ 
  size_t index;
  // check if the connection is a pre-saved one and if so, just select it in the list
  if ((index = _panel.get_be()->get_db_mgmt()->storedConns().get_index(connection)) != grt::BaseListRef::npos)
  {
    reset_stored_conn_list();
    _stored_connection_list.set_selected(index);
    change_active_stored_conn();
  }
  else
  {
    reset_stored_conn_list();

    // set the displayed params to the one given to us
    if (connection.is_valid())
      _panel.get_be()->set_connection(connection);
    // switch the connection object with the anon connection from the panel object
    _panel.get_be()->set_connection_keeping_parameters(_panel.get_default_connection());
    _conn_name->set_value(_("Press New to save these settings"));
  }
  // return the selected connection object
  if (run_modal(&_ok_button, &_cancel_button))
    return _panel.get_be()->get_connection();

  return db_mgmt_ConnectionRef();
}


//------------------------------------------------------------------------------
void grtui::DbConnectionEditor::run()
{
  reset_stored_conn_list();
    
  run_modal(&_ok_button, &_cancel_button);
}

//------------------------------------------------------------------------------
void grtui::DbConnectionEditor::reset_stored_conn_list()
{
  grt::ListRef<db_mgmt_Connection> list(_panel.get_be()->get_db_mgmt()->storedConns());
  std::string selected_name;
  
  if (_panel.get_be()->get_connection().is_valid())
    selected_name= _panel.get_be()->get_connection()->name();
  
  _stored_connection_list.clear_rows();

  int selected_idx= -1;
  int added_row_idx = -1;
  grt::ListRef<db_mgmt_Connection>::const_iterator iter = list.begin();
  grt::ListRef<db_mgmt_Connection>::const_iterator last = list.end();
  for (; iter != last; ++iter)
  {
    added_row_idx = _stored_connection_list.add_row();
    if (added_row_idx >= 0)
    {
      _stored_connection_list.set(added_row_idx, 0, (*iter)->name());
      if ((*iter)->name() == selected_name)
        selected_idx= added_row_idx;
    }
  }

  if (selected_idx >= 0)
  {
    selected_idx = selected_idx >= 0 ? selected_idx : 0;
    _stored_connection_list.set_selected(selected_idx);
  }
  change_active_stored_conn();
}

//------------------------------------------------------------------------------
void grtui::DbConnectionEditor::add_stored_conn(bool copy)
{
  grt::ListRef<db_mgmt_Connection> list(_panel.get_be()->get_db_mgmt()->storedConns());
  const int length = (std::string("New connection 1")).length() - 1;
  int max_conn_nr = 0;
  for (size_t i = 0; i < list.count(); ++i)
  {
    std::string itname = list[i]->name();
    if (itname.find("New connection") == 0)
    {
      int conn_nr = atoi(itname.substr(length).c_str());
      if (conn_nr > max_conn_nr)
        max_conn_nr = conn_nr;
    }
  }
  char buf[128];
  sprintf(buf, "New connection %i", max_conn_nr + 1);

  // use the current values to create a new connection
  db_mgmt_ConnectionRef new_connection(_panel.get_be()->get_grt());
  
  new_connection->owner(_panel.get_be()->get_db_mgmt());
  new_connection->name(buf);
  list.insert(new_connection);
  
  if (copy)
    _panel.get_be()->set_connection_keeping_parameters(new_connection);
  else
  {
    _panel.set_active_driver(0);
    _panel.get_be()->set_connection(new_connection);
  }
  reset_stored_conn_list();
  change_active_stored_conn();
}

//------------------------------------------------------------------------------
void grtui::DbConnectionEditor::del_stored_conn()
{
  const int idx = _stored_connection_list.get_selected();
  if (idx >= 0 && idx < (int)_mgmt->storedConns().count())
  {
    grt::ListRef<db_mgmt_Connection> conns(_mgmt->storedConns());
    db_mgmt_ConnectionRef conn(conns[idx]);
    bool found = false;
    grt::ListRef<db_mgmt_ServerInstance> instances(_mgmt->storedInstances());
    for (grt::ListRef<db_mgmt_ServerInstance>::const_iterator i = instances.begin();
         i != instances.end(); ++i)
    {
      if ((*i)->connection() == conn)
      {
        found = true;
        break;
      }
    }
    if (found)
    {
      mforms::Utilities::show_message(_("Cannot Delete Connection"),
                                      _("One or more Database Server Instances use this connection.\n"
                                        "You must remove them before deleting this connection."),
                                      _("OK"));
      return;
    }

    if (idx < (int)conns.count())
      conns.remove(idx);
    
    reset_stored_conn_list();
    change_active_stored_conn();
  }
}

//------------------------------------------------------------------------------
void grtui::DbConnectionEditor::change_active_stored_conn()
{
  const int selected = _stored_connection_list.get_selected();
  if (selected >= 0)
  {
    _panel.set_enabled(true);
    _panel.suspend_layout();
    _panel.set_active_stored_conn(selected+1);
    _panel.resume_layout();
    
    _test_button.set_enabled(true);
    _del_conn_button.set_enabled(true);
    _dup_conn_button.set_enabled(true);
    _move_up_button.set_enabled(true);
    _move_down_button.set_enabled(true);
  }
  else
  {
    _panel.set_enabled(false);
    _test_button.set_enabled(false);
    _del_conn_button.set_enabled(false);
    _dup_conn_button.set_enabled(false);
    _move_up_button.set_enabled(false);
    _move_down_button.set_enabled(false);
  }
}

//------------------------------------------------------------------------------
void grtui::DbConnectionEditor::name_changed()
{
  std::string name= _conn_name->get_string_value();
  
  std::string oname= _stored_connection_list.get_string(_stored_connection_list.get_selected(), 0);
  
  if (rename_stored_conn(oname, name))
    _stored_connection_list.set(_stored_connection_list.get_selected(), 0, name);
}

//------------------------------------------------------------------------------
void grtui::DbConnectionEditor::ok_clicked()
{
  // dont need to do anything, the modal handler will interpret the close butto
}

//------------------------------------------------------------------------------
void grtui::DbConnectionEditor::cancel_clicked()
{
}

//------------------------------------------------------------------------------
bool grtui::DbConnectionEditor::rename_stored_conn(const std::string &oname, const std::string &name)
{
  if (name == oname) return true;
  
  grt::ListRef<db_mgmt_Connection> conns= _mgmt->storedConns();
  db_mgmt_ConnectionRef conn= find_named_object_in_list(conns, oname);
  
  if (conn.is_valid())
  {
    // check for duplicate
    if (find_named_object_in_list(conns, name).is_valid())
      return false;
    
    conn->name(name);
    return true;
  }
  return false;
}

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

void grtui::DbConnectionEditor::reorder_conn(bool up)
{
  grt::ListRef<db_mgmt_Connection> conns= _mgmt->storedConns();
  int i= _stored_connection_list.get_selected();
  
  if (i < 0)
    return;
  
  if (up)
  {
    if (i > 0)
    {
      conns.reorder(i, i-1);
      _stored_connection_list.set_selected(i-1);
    }
  }
  else
  {
    if (i < _stored_connection_list.count()-1)
    {
      conns.reorder(i, i+1);
      _stored_connection_list.set_selected(i+1);
    }
  }
  
  i= 0;
  GRTLIST_FOREACH(db_mgmt_Connection, conns, inst)
  {
    _stored_connection_list.set(i++, 0, (*inst)->name().c_str());
  }    
}
