#
#  Copyright (c) 2017 Helmut Merz helmutm@cy55.de
#
#  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
#

"""
Report type, report concept adapter, and other reporting stuff.
"""

from zope import schema, component
from zope.component import adapts
from zope.interface import Interface, Attribute, implements
from zope.cachedescriptors.property import Lazy
from zope.security.proxy import removeSecurityProxy
from zope.traversing.api import getName

from cybertools.composer.report.base import Report as BaseReport
from cybertools.composer.report.base import LeafQueryCriteria
from cybertools.composer.report.base import CompoundQueryCriteria
from cybertools.composer.report.interfaces import IReport as IBaseReport
from cybertools.composer.report.interfaces import IReportParams
from cybertools.composer.report.result import ResultSet, Row
from cybertools.util.jeep import Jeep
from loops.common import AdapterBase
from loops.expert.concept import IQueryConcept, QueryConcept
from loops.interfaces import ILoopsAdapter
from loops.type import TypeInterfaceSourceList
from loops import util
from loops.util import _


# interfaces

class IReport(ILoopsAdapter, IReportParams, IQueryConcept):
    """ The report adapter for the persistent object (concept) that stores
        the report in the concept map.
    """

    reportType = schema.Choice(
        title=_(u'Report Type'),
        description=_(u'The type of the report.'),
        default=None,
        source='loops.expert.reportTypeSource',
        required=True)

    name = Attribute('The name of the report.')


class IReportInstance(IBaseReport):
    """ The report-type-specific object (an adapter on the report) that
        does the real report execution stuff.
    """


# report concept adapter and instances

class Report(QueryConcept):

    implements(IReport)

    _contextAttributes = list(IReport)

    @Lazy
    def name(self):
        return getName(self.context)

TypeInterfaceSourceList.typeInterfaces += (IReport,)


class ReportInstance(BaseReport):

    implements(IReportInstance)
    adapts(IReport)

    rowFactory = Row
    #headerRowFactory = Row

    view = None     # set upon creation
    #headerRowFactory = Row

    def __init__(self, context):
        self.context = context
        self.name = self.type

    def getResultsRenderer(self, name, macros):
        return macros[name]

    @property
    def queryCriteria(self):
        return self.context.queryCriteria

    def getResults(self, dynaParams=None):
        crit = self.queryCriteria
        limits = self.limits
        if crit is None:
            parts = Jeep()
            #return ResultSet(self, [])
        else:
            if dynaParams is not None:
                for k, v in dynaParams.items():
                    if k == 'limits':
                        limits = v
                        break
                    if k in crit.parts.keys():
                        crit.parts[k].comparisonValue = v
            parts = Jeep(crit.parts)
        if getattr(self, 'limitsCount', ''):
            limits = None
        result = list(self.selectObjects(parts))  # may modify parts
        qc = CompoundQueryCriteria(parts)
        return ResultSet(self, result, rowFactory=self.rowFactory,
                         sortCriteria=self.getSortCriteria(), 
                         sortDescending=self.sortDescending,
                         queryCriteria=qc,
                         limits=limits)

    def selectObjects(self, parts):
        # to be implemented by subclass
        return []

    @Lazy
    def conceptManager(self):
        return self.view.conceptManager

    @Lazy
    def recordManager(self):
        return self.view.loopsRoot.getRecordManager()

    @Lazy
    def hasReportPredicate(self):
        return self.conceptManager['hasreport']


class ReportTypeSourceList(object):

    implements(schema.interfaces.IIterableSource)

    def __init__(self, context):
        self.context = context

    def __iter__(self):
        return iter(self.reportTypes)

    def __contains__(self, value):
        return value in [item[0] for item in self]

    @Lazy
    def reportTypes(self):
        result = []
        for item in component.getAdapters([self.context], IReportInstance):
            name, adapter = item
            adapter = removeSecurityProxy(adapter)
            label = getattr(adapter, 'label', name)
            result.append((name, label,))
        return result

    def __len__(self):
        return len(self.reportTypes)


# default concept report

class DefaultConceptReportInstance(ReportInstance):

    label = u'Default Concept Report'


# specialized rows

class TrackRow(Row):

    @staticmethod
    def getContextAttr(obj, attr):
        if attr in obj.context.metadata_attributes:
            return getattr(obj.context, attr)
        return obj.context.data.get(attr)


