##############################################################################
#
# Copyright (c) 2002, 2005 Nexedi SARL and Contributors. All Rights Reserved.
#                    Jean-Paul Smets-Solanes <jp@nexedi.com>
#                    Romain Courteaud <romain@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 AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.Accessor.Constant import PropertyGetter as ConstantGetter
from Products.ERP5Type.XMLMatrix import XMLMatrix
from Products.ERP5.Document.Path import Path
from Products.ERP5Type.Utils import convertToUpperCase


class SupplyLine(Path, XMLMatrix):
    """A Supply Line is a path to define price 
    """

    meta_type = 'ERP5 Supply Line'
    portal_type = 'Supply Line'
    add_permission = Permissions.AddPortalContent
    isPredicate = ConstantGetter('isPredicate', value=True)

    # Declarative security
    security = ClassSecurityInfo()
    security.declareObjectProtected(Permissions.AccessContentsInformation)

    # Declarative properties
    property_sheets = ( PropertySheet.Base
                      , PropertySheet.XMLObject
                      , PropertySheet.CategoryCore
                      , PropertySheet.Amount
                      , PropertySheet.Task
                      , PropertySheet.Arrow
                      , PropertySheet.Movement
                      , PropertySheet.Price
                      , PropertySheet.SupplyLine
                      , PropertySheet.VariationRange
                      , PropertySheet.Path
                      , PropertySheet.FlowCapacity
                      , PropertySheet.Predicate
                      , PropertySheet.Comment
                      , PropertySheet.Reference
                      )

    #############################################
    # Pricing methods
    #############################################
    security.declareProtected(Permissions.AccessContentsInformation,
                              'getPrice')
    def getPrice(self):
      if getattr(self, 'price', None) is None:
        self.price = 0.0
      # Return the price
      return self.price

    security.declareProtected(Permissions.AccessContentsInformation,
                              'getTotalPrice')
    def getTotalPrice(self):
      """
        Returns the totals price for this line
      """
      quantity = self.getQuantity() or 0.0
      price = self.getPrice() or 0.0
      return quantity * price

    def _getPrice(self, context):
       return 0.0

    def _getDefaultPrice(self, context):
       return 0.0

    def _getTotalPrice(self, context):
      return 0.0

    def _getDefaultTotalPrice(self, context):
      return 0.0

    security.declareProtected(Permissions.AccessContentsInformation,
                              'isAccountable')
    def isAccountable(self):
      """Supply Line are not accounted.
      """
      return 0

    security.declareProtected(Permissions.AccessContentsInformation,
                              'getDefaultPrice')
    def getDefaultPrice(self, context=None, REQUEST=None, **kw):
      """
      """
      return self._getDefaultPrice(self.asContext(context=context,
                                                  REQUEST=REQUEST, **kw))

    security.declareProtected(Permissions.AccessContentsInformation,
                              'getDefaultTotalPrice')
    def getDefaultTotalPrice(self, context=None, REQUEST=None, **kw):
      """
      """
      return self._getDefaultTotalPrice(self.asContext(context=context,
                                                       REQUEST=REQUEST, **kw))

    #############################################
    # Predicate method
    #############################################
    asPredicate = Path.asPredicate

    #############################################
    # XMLMatrix methods
    # XXX to be removed if possible
    #############################################
    security.declareProtected(Permissions.AccessContentsInformation,
                              'hasCellContent')
    def hasCellContent(self, base_id='path'):
      """
          This method can be overriden
      """
      return XMLMatrix.hasCellContent(self, base_id=base_id)

    security.declareProtected(Permissions.AccessContentsInformation,
                              'getCellValueList' )
    def getCellValueList(self, base_id='path'):
      """
          This method can be overriden
      """
      return XMLMatrix.getCellValueList(self, base_id=base_id)

    security.declareProtected(Permissions.AccessContentsInformation, 'getCell')
    def getCell(self, *kw , **kwd):
      """
          This method can be overriden
      """
      kwd.setdefault('base_id', 'path')
      return XMLMatrix.getCell(self, *kw, **kwd)

    security.declareProtected(Permissions.ModifyPortalContent, 'newCell')
    def newCell(self, *kw, **kwd):
      """
          This method creates a new cell
      """
      kwd.setdefault('base_id', 'path')
      return XMLMatrix.newCell(self, *kw, **kwd)

    ############################################################
    # Quantity predicate API
    ############################################################
    security.declareProtected(Permissions.AccessContentsInformation,
                              'getQuantityPredicateIdList')
    def getQuantityPredicateIdList(self, price_parameter):
      """
        Return predicate id related to a price parameter.
      """
      predicate_id_start_with = "quantity_range_"
      if price_parameter != "base_price":
        predicate_id_start_with = "%s_%s" % \
            (price_parameter, predicate_id_start_with)
      # XXX Hardcoded portal type name
      predicate_list = self.contentIds(filter={'portal_type': 'Predicate'})
      result = [x for x in predicate_list \
              if x.startswith(predicate_id_start_with)]
      return result

    security.declareProtected(Permissions.AccessContentsInformation,
                              'getQuantityPredicateValueList')
    def getQuantityPredicateValueList(self, price_parameter):
      """
        Return predicate related to a price parameter.
      """
      result = [getattr(self, x) for x in \
              self.getQuantityPredicateIdList(price_parameter)]
      return result

    security.declareProtected(Permissions.AccessContentsInformation,
                              'getQuantityStepList')
    def getQuantityStepList(self, *args, **kw):
      """
        Return predicate step related to a price_parameter
      """
      # We need to keep compatibility with generated accessor
      price_parameter = kw.get('price_parameter', "base_price")
      if price_parameter == "base_price":
        method_name = "_baseGetQuantityStepList"
      else:
        method_name = 'get%sList' % \
                     convertToUpperCase("%s_quantity_step" % price_parameter)
      return getattr(self, method_name)()

    security.declareProtected(Permissions.ModifyPortalContent,
                              'updateQuantityPredicate')
    def updateQuantityPredicate(self, price_parameter):
      """
        Update the quantity predicate for this price parameter
      """
      quantity_step_list = self.getQuantityStepList(price_parameter=price_parameter)
      quantity_step_list.sort()
      
      # remove old predicates
      for pid in self.getQuantityPredicateIdList(price_parameter):
        self.deleteContent(pid)
      
      if quantity_step_list:
        quantity_step_list = [None] + quantity_step_list + [None]
        # With this script, we can change the title of the predicate
        script = getattr(self, 'SupplyLine_getTitle', None)
        predicate_id_start_with = "quantity_range"
        if price_parameter != "base_price":
          predicate_id_start_with = "%s_%s" % \
              (price_parameter, predicate_id_start_with)
        for i in range(0, len(quantity_step_list)-1):
          min_quantity = quantity_step_list[i]
          max_quantity = quantity_step_list[i+1]
          # XXX Hardcoded portal type name
          p = self.newContent(id='%s_%s' % (predicate_id_start_with, str(i)),
                              portal_type='Predicate', int_index=i+1)
          p.setCriterionPropertyList(('quantity', ))
          p.setCriterion('quantity', min=min_quantity, max=max_quantity)
          if script is not None:
            title = script(min=min_quantity, max=max_quantity)
            p.setTitle(title)
          else:
            if min_quantity is None:
              p.setTitle('quantity < %s' % max_quantity)
            elif max_quantity is None:
              p.setTitle('%s <= quantity' % min_quantity)
            else:
              p.setTitle('%s <= quantity < %s' % (min_quantity, max_quantity))