## $Id: export.py 12297 2014-12-22 16:42:50Z henrik $
##
## Copyright (C) 2014 Uli Fouquet & Henrik Bettermann
## 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
##
"""Exporters for customer related stuff.
"""
import os
import grok
from datetime import datetime
from zope.component import getUtility
from waeup.ikoba.interfaces import (
    IExtFileStore, IFileStoreNameChooser)
from waeup.ikoba.interfaces import MessageFactory as _
from waeup.ikoba.customers.catalog import CustomersQuery
from waeup.ikoba.customers.interfaces import (
    ICustomer, ICSVCustomerExporter,
    ICustomerSampleDocument, ISampleContract)
from waeup.ikoba.utils.batching import ExporterBase
from waeup.ikoba.utils.helpers import iface_names, to_timezone

def get_customers(site, cust_filter=CustomersQuery()):
    """Get all customers registered in catalog in `site`.
    """
    return cust_filter.query()

def get_documents(customers, class_name):
    """Get all documents of `customers`.
    """
    documents = []
    for customer in customers:
        for document in customer.get('documents', {}).values():
            if document.class_name == class_name:
                documents.append(document)
    return documents

def get_contracts(customers, class_name):
    """Get all contracts of `customers`.
    """
    contracts = []
    for customer in customers:
        for contract in customer.get('contracts', {}).values():
            if contract.class_name == class_name:
                contracts.append(contract)
    return contracts

class CustomerExporterBase(ExporterBase):
    """Exporter for customers or related objects.

    This is a baseclass.
    """
    grok.baseclass()
    grok.implements(ICSVCustomerExporter)
    grok.provides(ICSVCustomerExporter)

    def filter_func(self, x, **kw):
        return x

    def get_filtered(self, site, **kw):
        """Get customers from a catalog filtered by keywords.

        customers_catalog is the default catalog. The keys must be valid
        catalog index names.
        Returns a simple empty list, a list with `Customer`
        objects or a catalog result set with `Customer`
        objects.

        .. seealso:: `waeup.ikoba.customers.catalog.CustomersCatalog`

        """
        # Pass only given keywords to create FilteredCatalogQuery objects.
        # This way we avoid
        # trouble with `None` value ambivalences and queries are also
        # faster (normally less indexes to ask). Drawback is, that
        # developers must look into catalog to see what keywords are
        # valid.
        query = CustomersQuery(**kw)
        return query.query()

    def export(self, values, filepath=None):
        """Export `values`, an iterable, as CSV file.

        If `filepath` is ``None``, a raw string with CSV data is returned.
        """
        writer, outfile = self.get_csv_writer(filepath)
        for value in values:
            self.write_item(value, writer)
        return self.close_outfile(filepath, outfile)

    def export_all(self, site, filepath=None):
        """Export customers into filepath as CSV data.

        If `filepath` is ``None``, a raw string with CSV data is returned.
        """
        return self.export(self.filter_func(get_customers(site)), filepath)

    def export_customer(self, customer, filepath=None):
        return self.export(self.filter_func([customer]), filepath=filepath)

    def export_filtered(self, site, filepath=None, **kw):
        """Export items denoted by `kw`.

        If `filepath` is ``None``, a raw string with CSV data should
        be returned.
        """
        data = self.get_filtered(site, **kw)
        return self.export(self.filter_func(data, **kw), filepath=filepath)


class CustomerExporter(grok.GlobalUtility, CustomerExporterBase):
    """Exporter for Customers.
    """
    grok.name('customers')

    iface = ICustomer

    #: The title under which this exporter will be displayed
    title = _(u'Customers')

    #: Fieldnames considered by this exporter
    @property
    def fields(self):
        return tuple(sorted(iface_names(self.iface))) + (
            'password', 'state', 'history',)

    def mangle_value(self, value, name, context=None):
        if name == 'history':
            value = value.messages
        if name == 'phone' and value is not None:
            # Append hash '#' to phone numbers to circumvent
            # unwanted excel automatic
            value = str('%s#' % value)
        return super(
            CustomerExporter, self).mangle_value(
            value, name, context=context)


class CustomerDocumentExporterBase(grok.GlobalUtility, CustomerExporterBase):
    """Exporter for Customer Document instances.

    This is a baseclass.
    """
    grok.baseclass()
    iface = None
    class_name = None
    title = None

    #: Fieldnames considered by this exporter
    @property
    def fields(self):
        return tuple(
            sorted(iface_names(
                self.iface, exclude_attribs=False,
                omit=['is_editable_by_customer',
                      'is_editable_by_manager',
                      'is_verifiable',
                      'translated_state',
                      'formatted_transition_date',
                      'translated_class_name',
                      'connected_files',   # Could be used to export file URLs
                      ])))

    def filter_func(self, x, **kw):
        return get_documents(x, self.class_name)

    def mangle_value(self, value, name, context=None):

        if name == 'history':
            value = value.messages
        return super(
            CustomerDocumentExporterBase, self).mangle_value(
            value, name, context=context)


class CustomerSampleDocumentExporter(CustomerDocumentExporterBase):
    """Exporter for CustomerSampleDocument instances.
    """
    grok.name('customersampledocuments')

    iface = ICustomerSampleDocument
    class_name = 'CustomerSampleDocument'
    title = _(u'Customer Sample Documents')


class ContractExporterBase(grok.GlobalUtility, CustomerExporterBase):
    """Exporter for Contract instances.

    This is a baseclass.
    """
    grok.baseclass()
    iface = None
    class_name = None
    title = None

    #: Fieldnames considered by this exporter
    @property
    def fields(self):
        return tuple(
            sorted(iface_names(
                self.iface, exclude_attribs=False,
                omit=['translated_state',
                      'formatted_transition_date',
                      'translated_class_name',
                      'is_editable_by_customer',
                      'is_approvable'])))

    def filter_func(self, x, **kw):
        return get_contracts(x, self.class_name)

    def mangle_value(self, value, name, context=None):

        if name == 'history':
            value = value.messages
        if name.endswith('_object'):
            mangled_value = getattr(value, 'document_id', None)
            if mangled_value:
                return mangled_value
            mangled_value = getattr(value, 'product_id', None)
            if mangled_value:
                return mangled_value
        return super(
            ContractExporterBase, self).mangle_value(
            value, name, context=context)


class SampleContractExporter(ContractExporterBase):
    """Exporter for sample contracts.
    """
    grok.name('samplecontracts')
    iface = ISampleContract
    class_name = 'SampleContract'
    title = _(u'Customer Sample Contracts')