# -*- coding: latin-1; -*-
#
# PgWorksheet - PostgreSQL Front End
# http://pgworksheet.projects.postgresql.org/
#
# Copyright © 2004-2008 Henri Michelon & CML http://www.e-cml.org/
#
# 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; either version 2
# of the License, or (at your option) any later version.
#
# 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 (read LICENSE.txt).
#
# 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
# $Id
#
import string
import pygtk
import gtk

import pgw


class RunSQL:
  """Execute the SQL buffer and fill the GtkNotebook with the results."""

  def __init__(self, execute, txtSQL, tabResult, result):
    self.execute = execute
    self.txtSQL = txtSQL
    self.lblResult = result
    self.tabResult = tabResult
    self.error_font = {}


  def result(self, msg):
    """update status bar text"""
    self.lblResult.set_markup('<span foreground="#004400">' + msg + '</span>')


  def str_limit(self, s, max = 20):
    s = string.replace(s, '\\\\', '\\')
    if (len(s) > (max + 3)):
      return s[:max] + "..."
    return s


  def error(self, msg, title = None):
    """update the error messages"""
    if (title is None):
      title = '<span foreground="#880000">' + _('Errors') + '</span>'
    scroll = gtk.ScrolledWindow()
    txt = gtk.TextView()
    txt.get_buffer().set_text(unicode(msg, pgw.get_user_encoding()))
    pgw.set_proportional(txt.get_buffer())
    txt.set_editable(False)
    scroll.add(txt)
    scroll.show_all()
    label = gtk.Label()
    label.set_markup(title)
    self.tabResult.append_page(scroll, label)


  def add_treeview(self, title):
    """Add a new tree view"""
    scroll = gtk.ScrolledWindow()
    tvw = gtk.TreeView()
    scroll.add(tvw)
    scroll.show()
    label = gtk.Label(title)
    self.tabResult.append_page(scroll, label)
    return (tvw, label)
    

  def fill_treeview(self, sql, result):
    """build the tree view columns and rows"""
    sql = sql.strip()
    treeview, label = self.add_treeview(self.str_limit(sql))
    type_str = ""
    cell = gtk.CellRendererText()
    ncol = 0
    for col in result.description:
      column = gtk.TreeViewColumn(string.replace(col[0], "_", "__"))
      column.pack_start(cell, True)
      column.add_attribute(cell, 'text', ncol)
      column.set_sort_column_id(ncol)
      treeview.append_column(column)
      ncol = ncol + 1
      if (type_str == ""):
        type_str = "str"
      else:  
        type_str = type_str + ",str"
      pass
      
    # dynamically create the liststore
    code = "liststore = gtk.ListStore(" + type_str + ")"
    exec compile(code, "<string>", 'exec')

    # fill the tree view
    row = result.fetchone()
    rows = 0
    while ( row is not None ) :
      c = 0
      while c < len(row):
        if (row[c] is None) and type(row) == list:
          row[c] = '(null)'
        c = c + 1
      liststore.append(row)
      row = result.fetchone()
      rows = rows + 1
    result.close()  
    treeview.set_model(liststore)
    treeview.set_reorderable(True)
    treeview.columns_autosize()
    treeview.show()
    label.set_markup(label.get_text() + ' <span foreground="#555555">: ' + 
                      str(rows) + "</span>")
    return rows


  def run(self):  
    """Run the query and update the results"""
    # clear the treeviews and the error text buffers
    for child in self.tabResult.get_children():
      self.tabResult.remove(child)
    self.result(_("Please wait, executing the query and fetching the results..."))
    # update the display
    while (gtk.events_pending() == True):
      gtk.main_iteration_do(False)

    # execute the query
    sqlbuffer=  self.txtSQL.get_buffer()
    notices = []
    try:
      result = self.execute.execute(sqlbuffer)
      rows = 0
      if (isinstance(result, list)):
        # multiple queries and multiple results...
        parts = self.execute.split(sqlbuffer)
        sqls = []
        have_errors = 0
        for sql in parts :
          sql = string.strip(sql)
          if (len(sql) > 0) :
            sqls.append(sql)
        for res in result:
          sql = sqls.pop(0)
          try:
            if (res['cursor'].description is not None):
              rows += self.fill_treeview(sql, res['cursor'])
            else:  
              rows += res['cursor'].rowcount
            notices = res['notices']
          except KeyError:    
            try:
              self.error(res['text'], "psql : " + self.str_limit(sql))
            except KeyError:  
              notices = res['notices']
              self.error(res['error'],
                          '<span foreground="#880000">' + _('Errors :') + '</span> ' + 
                          self.str_limit(sql))
              have_errors += 1
        self.tabResult.set_current_page(0)
        if (rows > 1):
          res_str = _("%d results or affected rows") % rows
        elif (rows == 1):
          res_str = _("1 result or affected row")
        else:
          res_str = _("No result or no affected row")
        if (have_errors > 1) :
          res_str += ', <span foreground="#880000">' + \
                    _('%d queries failed') % have_errors + '</span>'
        elif (have_errors > 0) :  
          res_str += ', <span foreground="#880000">' +  \
                    _('1 query failed') + '</span>'
        self.result(res_str)  
      else: # one query
        sql = sqlbuffer.get_text(sqlbuffer.get_start_iter(), 
                                 sqlbuffer.get_end_iter())
        try:
          if (result is None):
            self.result(_("No result"))
          elif (result['cursor'].description is None):
            # not a SELECT
            rows = result['cursor'].rowcount
            notices = result['notices']
            if (rows > 1):
              self.result(_("%d rows affected") % rows)
            elif (rows == 1):
              self.result(_("1 row affected"))
            else:
              self.result(_("No row affected"))
          else:
            # only one SELECT
            rows = self.fill_treeview(sql, result['cursor'])
            notices = result['notices']
            if (rows > 1):
              self.result(_("%d results") % rows)
            elif (rows == 1):
              self.result(_("1 result"))
            else:
              self.result(_("No result"))
        except KeyError:
          try:
            self.error(result['text'], "psql : " + self.str_limit(sql))
            self.result("")
          except KeyError:  
            self.error(result['error'])
            self.result('<span foreground="#880000">' + _('query failed') + '</span>')
            notices = result['notices']
      buffer = self.txtSQL.get_buffer()
      buffer.move_mark_by_name('selection_bound', buffer.get_start_iter());
      buffer.move_mark_by_name('insert', buffer.get_end_iter());

    except KeyError, errstr:
      self.result('<span foreground="#880000">' + _('query failed') + '</span>')
      self.error(str(errstr))

    if (len(notices) > 0):
      msg = ""
      while len(notices):
        msg += notices.pop()
      self.error(msg, '<span foreground="#000088">'+ _("log") + '</span>')

    # restore the focus 
    self.txtSQL.grab_focus()

