/* 
 * © 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 "sql_parser_base.h"
#include "module_utils.h"
#include "grtdb/charset_utils.h"
#include <sstream>


using namespace grt;
using namespace bec;


Sql_parser_base::Null_state_keeper::~Null_state_keeper()
{
  //_sql_parser->_grt= NULL;
  //_sql_parser->_grtm= NULL;
  //_sql_parser->_parse_error_cb.disconnect();
  _sql_parser->_active_obj= db_DatabaseObjectRef();
  _sql_parser->_messages_enabled= true;
  _sql_parser->_progress_state= 0.f;
  _sql_parser->_processed_obj_count= 0;
  _sql_parser->_warn_count= 0;
  _sql_parser->_err_count= 0;
  _sql_parser->_sql_script_preamble= std::string();
  _sql_parser->_sql_statement= std::string();
}
#define NULL_STATE_KEEPER Null_state_keeper _nsk(this);


Sql_parser_base::Sql_parser_base(grt::GRT *grt)
:
_grt(grt),
_grtm(GRTManager::get_instance_for(_grt))
{
  {
    NULL_STATE_KEEPER // reset all members to null-values
  }

  grt::DictRef options= grt::DictRef::cast_from(_grt->get("/wb/options/options"));
  _case_sensitive_identifiers= options.is_valid() ? (options.get_int("SqlIdentifiersCS", 1) != 0) : true;
}


void Sql_parser_base::set_options(const grt::DictRef &options)
{
}


std::string Sql_parser_base::normalize_identifier_case(const std::string &ident)
{
  return _case_sensitive_identifiers ? ident : toupper(ident);
}


void Sql_parser_base::add_log_message(const std::string &text, int entry_type)
{
  if (_messages_enabled && _grtm)
    _grtm->add_log_file_entry(text.c_str(), text.size());

  if (_grtm->in_main_thread())
    return;

  switch (entry_type)
  {
  case 0:
    {
      if (_messages_enabled)
        _grt->send_info(text);
      break;
    }
  case 1:
    {
      ++_warn_count;
      if (_messages_enabled)
        _grt->send_warning(text);
      break;
    }
  case 2:
    {
      if (_messages_enabled)
        _grt->send_error(text);
      break;
    }
  }
}


void Sql_parser_base::report_sql_error(int lineno, bool calc_abs_lineno, int err_tok_line_pos, int err_tok_len, const std::string &err_msg, int entry_type, std::string resolution)
{
  ++_err_count;

  if (calc_abs_lineno)
  {
    // count statement line count
    int stmt_lc= std::count(_sql_statement.begin(), _sql_statement.end(), '\n');
    int sql_script_preamble_line_count= std::count(_sql_script_preamble.begin(), _sql_script_preamble.end(), '\n');
    lineno= total_line_count() - stmt_lc - sql_script_preamble_line_count + lineno;
  }

  if (_messages_enabled)
    _parse_error_cb(lineno, err_tok_line_pos, err_tok_len, err_msg);

  std::ostringstream oss;
  if (_active_obj.is_valid())
    oss << _active_obj.get_metaclass()->get_attribute("caption") << " " << *_active_obj->name() << ". ";
  oss << "Line " << lineno << ": " << err_msg << "." << (resolution.empty() ? "" : " ") << resolution;
  add_log_message(oss.str(), entry_type);
}


void Sql_parser_base::step_progress(const std::string &text)
{
  if (!_messages_enabled)
    return;

  //!cycling progress state for now. statement count estimation is needed.
  _progress_state= (float)(div((int)(_progress_state*10) + 1, 10).rem) / 10;

  _grt->send_progress(_progress_state, _("Processing object"), text);
}


void Sql_parser_base::set_progress_state(float state, const std::string &text)
{
  if (!_messages_enabled)
    return;
  _grt->send_progress(state, text);
}


const std::string & Sql_parser_base::sql_statement()
{
  return _sql_statement;
}


void Sql_parser_base::parse_error_cb(Parse_error_cb &cb)
{
  _parse_error_cb= cb;
}


Sql_parser_base::Parse_error_cb & Sql_parser_base::parse_error_cb()
{
  return _parse_error_cb;
}
