/* 
 * © 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 "grt/grt_dispatcher.h"
#include "editor_routinegroup.h"

/**
 * @file  editor_routinegroup.cpp
 * @brief 
 */

using namespace grt;
using namespace bec;


RoutineGroupEditorBE::RoutineGroupEditorBE(GRTManager *grtm, const db_RoutineGroupRef &group, const db_mgmt_RdbmsRef &rdbms)
  : DBObjectEditorBE(grtm, group, rdbms), _group(group), _has_syntax_error(false)
{
}

std::string RoutineGroupEditorBE::get_routines_sql()
{
  std::string sql;

  grt::ListRef<db_Routine> routines= _group->routines();
  
  if(!routines.is_valid())
    return sql; // empty
  
  sql.append("-- --------------------------------------------------------------------------------\n");
  sql.append("-- ").append(_group->name().c_str()).append(" Group Routines\n");
  sql.append("-- --------------------------------------------------------------------------------\n");
  sql.append("DELIMITER //\n\n");

  size_t count= routines.count();
  typedef std::map<int, db_RoutineRef> OrderedRoutines;
  typedef std::list<db_RoutineRef> UnorderedRoutines;
  OrderedRoutines ordered_routines;
  UnorderedRoutines unordered_routines; // routines with duplicated sequence number. to upgrade old models smoothly, where sequence numbers are 0.

  for(size_t i= 0; i < count; i++)
  {
    db_RoutineRef routine= routines.get(i);
    int sequenceNumber= routine->sequenceNumber();
    if (ordered_routines.find(sequenceNumber) == ordered_routines.end())
      ordered_routines[sequenceNumber]= routine;
    else
      unordered_routines.push_back(routine);
  }

  for (OrderedRoutines::iterator i= ordered_routines.begin(), i_end= ordered_routines.end(); i != i_end; ++i)
    sql.append(i->second->sqlDefinition()).append("//");

  for (UnorderedRoutines::iterator i= unordered_routines.begin(), i_end= unordered_routines.end(); i != i_end; ++i)
    sql.append((*i)->sqlDefinition()).append("//");

  return sql;
}

std::vector<std::string> RoutineGroupEditorBE::get_routines_names()
{
  std::vector<std::string> retval;

  grt::ListRef<db_Routine> routines= _group->routines();
  
  if(!routines.is_valid())
    return retval; // empty
  
  size_t count= routines.count();
  for(size_t i= 0; i < count; i++)
  {
    std::string qname(routines.get(i)->owner()->name());
    qname.append(".").append(routines.get(i)->name());
    retval.push_back(qname);
  }

  return retval;
}

std::string RoutineGroupEditorBE::get_routine_sql(db_RoutineRef routine)
{
  return std::string(routine->sqlDefinition().c_str());
}

void RoutineGroupEditorBE::delete_routine_with_name(const std::string& str)
{
  grt::ListRef<db_Routine> routines= _group->routines();
  
  if(!routines.is_valid())
    return;

  size_t count= routines.count();
  for(size_t i= 0; i < count; i++)
  {
    std::string qname(routines.get(i)->owner()->name());
    qname.append(".").append(routines.get(i)->name());

    if(str == qname)
    {
      routines.remove(i);
      break;
    }
  }
}

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

/**
 * Removes the routine at the given index from this group. Does nothing if index is out of range.
 */
void RoutineGroupEditorBE::remove_routine_by_index(size_t index)
{
  grt::ListRef<db_Routine> routines= _group->routines();
  
  if(!routines.is_valid())
    return;
  
  size_t count= routines.count();
  if (index < 0 || index >= count)
    return;
  
  grt::AutoUndo undo(get_grt());
  routines.remove(index);
  undo.end(strfmt(_("Remove routine from routine group `%s`.%s`"), get_schema_name().c_str(), get_name().c_str()));
}

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

/**
 * Returns the name of a routine given by its id.
 */
std::string RoutineGroupEditorBE::get_routine_name(const std::string& id)
{
  grt::ListRef<db_Routine> routines= _group->routines();
  
  if (!routines.is_valid())
    return "";

  size_t count= routines.count();
  for (size_t i= 0; i < count; i++)
  {
    std::string next_id(routines.get(i).id());

    if(id == next_id)
    {
      std::string qname(routines.get(i)->owner()->name());
      qname.append(".").append(routines.get(i)->name());
      return qname;
    }
  }
  return "";
}

void RoutineGroupEditorBE::append_routine_with_id(const std::string& id)
{
  
  // first ensure no routine with such id already in group
  {
    grt::ListRef<db_Routine> routines= _group->routines();
    
    if(!routines.is_valid())
      return;
  
    size_t count= routines.count();
    for(size_t i= 0; i < count; i++)
    {
      std::string next_id(routines.get(i).id());
  
      if(id == next_id)
        return;
    }
  }
  // now find the routine and add it
  {
    db_SchemaRef schema(db_SchemaRef::cast_from(_group->owner()));

    grt::ListRef<db_Routine> routines(schema->routines());

    size_t count= routines.count();
    for(size_t i= 0; i < count; i++)
    {
      std::string next_id(routines.get(i).id());
  
      if(id == next_id)
      {
        grt::AutoUndo undo(get_grt());
        _group->routines().insert(routines.get(i));
        undo.end(strfmt(_("Add routine(s) to routine group `%s`.%s`"), get_schema_name().c_str(), get_name().c_str()));
        return;
      }
    }
  }
}


std::string RoutineGroupEditorBE::get_object_type()
{
  return "routine group";
}


void RoutineGroupEditorBE::set_routines_sql(const std::string &sql)
{
  if (get_sql() != sql)
  {
    set_sql_parser_task_cb(sigc::mem_fun(this, &RoutineGroupEditorBE::parse_sql));
    set_sql(sql, _group);
  }
}


grt::ValueRef RoutineGroupEditorBE::parse_sql(grt::GRT* grt, grt::StringRef sql)
{
  grt::AutoUndo undo(grt);

  // QQQ
  //_group->routines().remove_all();
//  get_grt_manager()->get_messages_list()->signal_changed().block();
  int err_count= _sql_parser->parse_routines(_group, sql.c_str());
//  get_grt_manager()->get_messages_list()->signal_changed().unblock();
  _has_syntax_error= 0 < err_count;

  undo.end(strfmt(_("Edit routine group `%s`.`%s`"), get_schema_name().c_str(), get_name().c_str()));

  return grt::IntegerRef(err_count);
}


Sql_editor * RoutineGroupEditorBE::get_sql_editor()
{
  Sql_editor * sql_editor= DBObjectEditorBE::get_sql_editor();
  if (sql_editor)
  {
    sql_editor->sql_checker()->only_object_type_of(Sql_syntax_check::ot_routine);
    sql_editor->sql_checker()->context_object(_group);
  }
  return sql_editor;
}
