/* 
 * 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 "db_sql_editor_log.h"
#include "sqlide/recordset_data_storage.h"
#include "base/string_utilities.h"
#include <boost/foreach.hpp>


using namespace bec;
using namespace grt;

// in the Actions log, truncate anything that's longer than this
#define MAX_LOG_STATEMENT_TEXT 4098


DbSqlEditorLog::DbSqlEditorLog(GRTManager *grtm)
  : VarGridModel(grtm)
{
  reset();

  _context_menu.add_item("Copy Row", "copy_row");
  _context_menu.add_separator();
  _context_menu.add_item("Append Selected Items to SQL script", "append_selected_items");
  _context_menu.add_item("Replace SQL Script With Selected Items", "replace_sql_script");
  _context_menu.add_separator();
  _context_menu.add_item("Clear", "clear");
}


void DbSqlEditorLog::reset()
{
  VarGridModel::reset();

  _readonly= true;

  add_column("", int()); // msg type (icon)
  add_column("", int()); // sequence no.
  add_column("Time", std::string());
  add_column("Action", std::string());
  add_column("Message", std::string());
  add_column("Duration / Fetch", std::string());

  boost::shared_ptr<sqlite::connection> data_swap_db= this->data_swap_db();
  Recordset_data_storage::create_data_swap_tables(data_swap_db.get(), _column_names, _column_types);

  refresh_ui();
}


class MsgTypeIcons
{
public:
  MsgTypeIcons()
  {
    IconManager *icon_man= IconManager::get_instance();
    _error_icon= icon_man->get_icon_id("mini_error.png");
    _warning_icon= icon_man->get_icon_id("mini_warning.png");
    _info_icon= icon_man->get_icon_id("mini_notice.png");
    _ok_icon= icon_man->get_icon_id("mini_ok.png");
    _edit_icon= icon_man->get_icon_id("mini_edit.png");
  }
private:
  IconId _error_icon;
  IconId _warning_icon;
  IconId _info_icon;
  IconId _edit_icon;
  IconId _ok_icon;
public:
  IconId icon(DbSqlEditorLog::MessageType msg_type)
  {
    switch (msg_type)
    {
      case DbSqlEditorLog::BusyMsg: return 0;
      case DbSqlEditorLog::EditMsg: return _edit_icon;
      case DbSqlEditorLog::NoteMsg: return _info_icon;
      case DbSqlEditorLog::OKMsg: return _ok_icon;
      case DbSqlEditorLog::ErrorMsg: return _error_icon;
      case DbSqlEditorLog::WarningMsg: return _warning_icon;
    }
    return _info_icon;
  }
};
IconId DbSqlEditorLog::get_field_icon(const NodeId &node, int column, IconSize size)
{
  IconId icon= 0;

  static MsgTypeIcons msg_type_icons;
  switch (column)
  {
  case 0:
    Cell cell;
    if (get_cell(cell, node, column, false))
    {
      int msg_type= boost::get<int>(*cell);
      icon= msg_type_icons.icon((DbSqlEditorLog::MessageType)msg_type);
    }
    break;
  }

  return icon;
}

static std::string sanitize_text(const std::string &text)
{
  std::string output;
  for (std::string::const_iterator end = text.end(), ch = text.begin(); ch != end; ++ch)
  {
    if (*ch == '\n' || *ch == '\r' || *ch == '\t')
      output.push_back(' ');
    else
      output.push_back(*ch);
  }
  return output;
}


bool DbSqlEditorLog::get_field(const bec::NodeId &node, int column, std::string &value)
{
  if (VarGridModel::get_field(node, column, value))
  {
    if (column == 3)
      value = sanitize_text(base::truncate_text(value, MAX_LOG_STATEMENT_TEXT));
    else if (column == 4)
      value = sanitize_text(value);
    return true;
  }
  return false;
}

bool DbSqlEditorLog::get_field_description(const bec::NodeId &node, int column, std::string &value)
{
  return VarGridModel::get_field(node, column, value);
}

RowId DbSqlEditorLog::add_message(int msg_type, const std::string &context, const std::string &msg, const std::string &duration)
{
  if (msg.empty())
    return -1;

  int new_row;
  {
    GStaticRecMutexLock data_mutex(_data_mutex);

    _data.reserve(_data.size() + _column_count);

    try
    {
      _data.push_back(msg_type);
      _data.push_back((int)_row_count+1);
      _data.push_back(current_time());
      _data.push_back(base::strip_text(context));
      _data.push_back(msg);
      _data.push_back(duration);
    }
    catch(...)
    {
      _data.resize(_row_count * _column_count);
      throw;
    }

    new_row= _row_count;
    ++_row_count;
    ++_data_frame_end;
  }

  // for optimization purposes class user has to decide when to refresh
  //refresh_ui();

  return new_row;
}


void DbSqlEditorLog::set_message(RowId row, int msg_type, const std::string &context, const std::string &msg, const std::string &duration)
{
  GStaticRecMutexLock data_mutex(_data_mutex);

  RowId cell_index= row * _column_count;
  if (cell_index > _data.size())
    return;
  Data::iterator cell= _data.begin() + cell_index;

  *cell++= msg_type;
  ++cell; //*cell++= (int)row+1;
  ++cell; //*cell++= current_time();
  *cell++= base::strip_text(context);
  *cell++= msg;
  *cell++= duration;

  // for optimization purposes class user has to decide when to refresh
  //refresh_ui();
}

mforms::Menu* DbSqlEditorLog::get_context_menu()
{
  return &_context_menu;
}
