/* 
 * © 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 "wb_config.h"

#include "editor_user_role.h"
#include "db_object_helpers.h"

using namespace grt;
using namespace bec;


RolePrivilegeListBE::RolePrivilegeListBE(RoleEditorBE *owner)
: _owner(owner)
{
}


int RolePrivilegeListBE::count()
{
  if (_privileges.is_valid())
    return (int)_privileges.count();
  return 0;
}


void RolePrivilegeListBE::refresh()
{
  _role_privilege= _owner->get_object_list()->get_selected_object_info();

  _privileges.clear();
  if (_role_privilege.is_valid())
  {
    grt::ListRef<db_mgmt_PrivilegeMapping> mappings(_owner->get_rdbms()->privilegeNames());

    for (size_t c= mappings.count(), i= 0; i < c; i++)
    {
      if (_role_privilege->databaseObject().is_valid() &&
        _role_privilege->databaseObject().is_instance(mappings[i]->structName()))
      {
        _privileges= mappings[i]->privileges();
        break;
      }
    }
  }
}


bool RolePrivilegeListBE::get_field_grt(const NodeId &node, int column, grt::ValueRef &value)
{
  if (node[0] >= count())
    return false;

  switch ((Columns)column)
  {
  case Enabled:
    if (_role_privilege->privileges().get_index(_privileges.get(node[0])) == BaseListRef::npos)
      value= grt::IntegerRef(0);
    else
      value= grt::IntegerRef(1);
    return true;
  case Name:
    value= _privileges.get(node[0]);
    return true;
  }
  return false;
}


bool RolePrivilegeListBE::set_field(const NodeId &node, int column, int value)
{
  size_t index;

  if (node[0] >= count())
    return false;

  switch ((Columns)column)
  {
  case Enabled:
    if ((index= _role_privilege->privileges().get_index(_privileges.get(node[0]))) == BaseListRef::npos)
    {
      if (value)
      {
        grt::AutoUndo undo(_owner->get_grt());

        _role_privilege->privileges().insert(_privileges.get(node[0]));

        undo.end(strfmt(_("Add Object Privilege to Role '%s'"), _owner->get_name().c_str()));
      }
    }
    else
    {
      if (!value)
      {
        grt::AutoUndo undo(_owner->get_grt());

        _role_privilege->privileges().remove(index);

        undo.end(strfmt(_("Remove Object Privilege to Role '%s'"), _owner->get_name().c_str()));
      }
    }
    return true;

  case Name:
    return false;
  }
  return false;
}



void RolePrivilegeListBE::remove_all()
{
  grt::AutoUndo undo(_owner->get_grt());
  _role_privilege->privileges().remove_all();
  undo.end(strfmt(_("Remove Privileges for '%s' from Role '%s'"), 
                 _role_privilege->databaseObject()->name().c_str(),
                 _owner->get_name().c_str()));
}



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


RoleObjectListBE::RoleObjectListBE(RoleEditorBE *owner)
: _owner(owner)
{
}


void RoleObjectListBE::set_selected_node(const NodeId &node)
{
  _selection= node;
  _owner->get_privilege_list()->refresh();
}


db_RolePrivilegeRef RoleObjectListBE::get_selected_object_info()
{
  if (_selection.is_valid() && _selection[0] < count())
    return _owner->get_role()->privileges().get(_selection[0]);

  return db_RolePrivilegeRef();
}


int RoleObjectListBE::count()
{
  if (_owner->get_role().is_valid())
    return (int)_owner->get_role()->privileges().count();
  return 0;
}


MenuItemList RoleObjectListBE::get_popup_items_for_nodes(const std::vector<NodeId> &nodes)
{
  MenuItemList items;
  
  MenuItem item;
  item.caption = _("Delete Selected");
  item.name    = "deleteObject";
  item.enabled = nodes.size() > 0;
  items.push_back(item);

  return items;
}


bool RoleObjectListBE::activate_popup_item_for_nodes(const std::string &name, const std::vector<NodeId> &nodes)
{
  if (name == "deleteObject")
  {
    for (std::vector<NodeId>::const_reverse_iterator node= nodes.rbegin(); node != nodes.rend(); ++node)
      _owner->remove_object(*node);
  }
  else
    return false;
  
  return true;
}


bool RoleObjectListBE::get_field_grt(const NodeId &node, int column, grt::ValueRef &value)
{
  if (node[0] >= count())
    return false;

  switch ((Columns)column)
  {
  case Name:
    db_RolePrivilegeRef priv(_owner->get_role()->privileges().get(node[0]));
    if (priv.is_valid() && priv->databaseObject().is_valid())
      value= priv->databaseObject()->name();
    else
      value= grt::StringRef("");
    return true;
  }
  return false;
}


IconId RoleObjectListBE::get_field_icon(const NodeId &node, int column, IconSize size)
{
  db_RolePrivilegeRef priv(_owner->get_role()->privileges().get(node[0]));
  if (priv.is_valid() && priv->databaseObject().is_valid())
    return IconManager::get_instance()->get_icon_id(priv->databaseObject());
  else
    return 0;
}

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

RoleEditorBE::RoleEditorBE(GRTManager *grtm, const db_RoleRef &role, const db_mgmt_RdbmsRef &rdbms)
: BaseEditor(grtm, role), _role(role), _rdbms(rdbms), _tree(db_CatalogRef::cast_from(role->owner())),
  _privilege_list(this), _object_list(this)
{
}


void RoleEditorBE::set_name(const std::string &name)
{
  if (get_name() != name)
  {
    AutoUndoEdit undo(this, get_role(), "name");
    std::string name_= rtrim(name);
    get_role()->name(name_);
    undo.end(strfmt(_("Rename Role to '%s'"), name_.c_str()));
  }
}


std::string RoleEditorBE::get_name()
{
  return get_role()->name();
}


void RoleEditorBE::set_parent_role(const std::string &name)
{
  if (name != get_parent_role())
  {
    grt::ListRef<db_Role> roles(db_CatalogRef::cast_from(get_role()->owner())->roles());
    db_RoleRef new_parent_role(grt::find_named_object_in_list(roles, name));

    if (!name.empty())
    {
      db_RoleRef some_parent_role(new_parent_role);
      // check for a role loop
      while (some_parent_role.is_valid())
      {
        // if the new parent somehow reaches back to this role, then there's a loop
        if (some_parent_role == get_role())
          throw std::runtime_error("Cannot set the parent role to a sub-role.");
        some_parent_role= some_parent_role->parentRole();
      }
    }
    
    AutoUndoEdit undo(this);

    if (name.empty())
      get_role()->parentRole(db_RoleRef());
    else
    {
      grt::ListRef<db_Role> roles(db_CatalogRef::cast_from(get_role()->owner())->roles());

      get_role()->parentRole(new_parent_role);
    }
  
    get_role_tree()->refresh();

    undo.end(strfmt(_("Set Parent Role of '%s'"), get_name().c_str()));
  }
}


std::string RoleEditorBE::get_parent_role()
{
  if (get_role()->parentRole().is_valid())
    return *get_role()->parentRole()->name();

  return "";
}


std::vector<std::string> RoleEditorBE::get_role_list()
{
  grt::ListRef<db_Role> roles(db_CatalogRef::cast_from(get_role()->owner())->roles());
  std::vector<std::string> names;

  names.push_back("");
  for (grt::ListRef<db_Role>::const_iterator iter= roles.begin(); iter != roles.end(); ++iter)
  {
    db_RoleRef role((*iter));
    
    // do not include the role itself or descendants of ourselves
    while (role.is_valid())
    {
      if (role == get_role())
        break;
      role= role->parentRole();
    }
    if (role != get_role())
      names.push_back((*iter)->name().c_str());
  }
  return names;
}


bool RoleEditorBE::add_dropped_objectdata(const std::string &data)
{
  std::list<db_DatabaseObjectRef> objects;
  bool flag= false;
  
  objects= bec::CatalogHelper::dragdata_to_dbobject_list(db_CatalogRef::cast_from(get_role()->owner()), data);

  for (std::list<db_DatabaseObjectRef>::const_iterator iter= objects.begin(); 
       iter != objects.end(); ++iter)
  {
    if (add_object(*iter))
      flag= true;
  }
  return flag;
}


bool RoleEditorBE::add_object(db_DatabaseObjectRef object)
{
  grt::ListRef<db_mgmt_PrivilegeMapping> mappings(get_rdbms()->privilegeNames());
  bool ok= false;

  for (size_t c= mappings.count(), i= 0; i < c; i++)
  {
    if (object.is_instance(*mappings[i]->structName()))
    {
      ok= true;
      break;
    }
  }

  if (!ok)
    return false;

  // check if already in list
  for (size_t c= get_role()->privileges().count(), i= 0; i < c; i++)
  {
    if (get_role()->privileges().get(i)->databaseObject() == object)
    {
      ok= false;
      break;
    }
  }

  if (ok)
  {
    db_RolePrivilegeRef priv(_grtm->get_grt());
    priv->databaseObject(object);
    priv->owner(get_role());

    AutoUndoEdit undo(this);

    get_role()->privileges().insert(priv);

    undo.end(strfmt(_("Add Object '%s' to Role '%s'"), object->name().c_str(), get_name().c_str()));
  }
  return true;
}


//!
//! Removes object with index object_node_id from the Role's object list.
//! As it is hard to get to the db_DatabaseObjectRef to remove 
//! via 
//!
void RoleEditorBE::remove_object(const bec::NodeId& object_node_id)
{
  //object_node_id is an id of the object in the role
  size_t object_idx = -1;
  try
  {
    object_idx = object_node_id.back();
  }
  catch (const std::logic_error& e)
  {
    throw std::logic_error(std::string("RoleEditorBE: while removing object from role") + e.what());
  }
  if (object_idx < get_role()->privileges().count())
  {
    AutoUndoEdit undo(this);
    get_role()->privileges().remove(object_idx);
    undo.end(strfmt(_("Remove object from Role '%s'"), get_name().c_str()));
  }
}

