##############################################################################
#
# Copyright (c) 2002-2006 Nexedi SARL and Contributors. All Rights Reserved.
# Copyright (c) 2007-2009 Nexedi SA and Contributors. All Rights Reserved.
#                    Jean-Paul Smets-Solanes <jp@nexedi.com>
#                    Vincent Pelletier <vincent@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# 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.
#
# 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.
#
##############################################################################

from Query import Query
from Products.ZSQLCatalog.interfaces.query import IQuery
from zope.interface.verify import verifyClass
from Products.ZSQLCatalog.SQLCatalog import profiler_decorator, list_type_list
from zLOG import LOG, WARNING

NULL_SEARCH_TEXT_OPERATOR_DICT = {
  '=': 'is',
  '!=': 'is not',
}
for value in NULL_SEARCH_TEXT_OPERATOR_DICT.values():
  NULL_SEARCH_TEXT_OPERATOR_DICT[value] = value

class SimpleQuery(Query):
  """
    A SimpleQuery represents a single comparison between a single column and
    one or more values.
  """
  @profiler_decorator
  def __init__(self, search_key=None, comparison_operator='=', group=None, **kw):
    """
      search_key (None, SearchKey instance)
        If given, the instance of SearchKey which is responsible for column
        map registration and rendering (SQL and SearchText).
      comparison_operator (string)
        The comparison operator which will be applied between column and
        values.
        See Operator/ComparisonOperator.py for possible values.
      group
        See ColumnMap.
      **kw
        Must contain exactly one item.
        item key (string)
          column name
        item value
          one or more values
    """
    self.search_key = search_key
    if len(kw) != 1:
      raise ValueError, 'SimpleQuery can support one and one only column. Got %r.' % (kw, )
    self.column, value = kw.popitem()
    # Usability improvement code (those changes should not be needed when
    # this Query is instanciated by a SearchKey, as operator should be correct
    # already).
    comparison_operator = comparison_operator.lower()
    if comparison_operator == 'in':
      if isinstance(value, list_type_list):
        if len(value) == 0:
          raise ValueError, 'Empty lists are not allowed.'
        elif len(value) == 1:
          value, = value
          comparison_operator = '='
      else:
        comparison_operator = '='
    elif comparison_operator == '=':
      if isinstance(value, list_type_list):
        if len(value) == 0:
          raise ValueError, 'Empty lists are not allowed.'
        elif len(value) == 1:
          value, = value
        else:
          comparison_operator = 'in'
    if value is None:
      try:
        comparison_operator = NULL_SEARCH_TEXT_OPERATOR_DICT[
          comparison_operator]
      except KeyError:
        raise ValueError('Unexpected comparison_operator %r for None value.'
          % (comparison_operator, ))
    elif comparison_operator == 'is':
      raise ValueError, 'Non-None value (%r) with "is" comparison_operator. Not sure what to do.' % (value, )
    self.value = value
    self.comparison_operator = comparison_operator
    self.group = group

  @profiler_decorator
  def _asSearchTextExpression(self, sql_catalog, column=None):
    return False, self.getSearchKey(sql_catalog).buildSearchTextExpression(self.getOperator(sql_catalog), self.getValue(), column=column)

  @profiler_decorator
  def asSQLExpression(self, sql_catalog, column_map, only_group_columns):
    return self.getSearchKey(sql_catalog).buildSQLExpression(
      self.getOperator(sql_catalog), self.getValue(),
      column_map, only_group_columns, group=self.group)

  @profiler_decorator
  def registerColumnMap(self, sql_catalog, column_map):
    self.group = self.getSearchKey(sql_catalog).registerColumnMap(column_map, group=self.group, simple_query=self)

  def getOperator(self, sql_catalog):
    """
      Return an instance of OperatorBase class.
    """
    return sql_catalog.getComparisonOperator(self.comparison_operator)

  def getSearchKey(self, sql_catalog):
    """
      Return an instance of SearchKey class.
    """
    if self.search_key is None:
      self.search_key = sql_catalog.getSearchKey(self.getColumn())
    return self.search_key

  def getColumn(self):
    return self.column

  def getValue(self):
    return self.value

  def __repr__(self):
    return '<%s %r %s %r>' % (self.__class__.__name__, self.getColumn(), self.comparison_operator, self.getValue())

  def setGroup(self, group):
    self.group = group

verifyClass(IQuery, SimpleQuery)