# -*- coding: UTF-8 -*-

# Copyright (c) 2007 Daniele Favara <nomed@dsslive.org>.
#
# This 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, or (at your option) any
# later version.
#
# This software 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 software; see the file COPYING.  If not, write to the Free
# Software Foundation, Inc., 51 Franilin St, Fifth Floor, Boston, MA


from turbogears import expose, flash
from tginvoice.controllers import ControllerObj
from tginvoice.model import tables
from tginvoice.utils import form
from genshi.template import TemplateLoader
from genshi import XML, escape
from tginvoice import trml2pdf
from formencode import Invalid
from turbogears import identity, redirect, url
from cherrypy import request, response, session
import logging, os
log = logging.getLogger("tginvoice.controllers.invoice")

class Invoices(ControllerObj):

    def _get_summary_vat(self, products):
        ret = {}
        for p in products:
            vat = float(p.vat)
            if not ret.has_key(vat):
                ret[vat] = float(0)
            ret[vat] += float(p.gross_price - p.tot_price)
        return ret

    def _get_tot_price(self, product):
        return float(float(product['unit_price']))*float(product['qty'])

    def _get_gross_price(self, product):
        vat = float( product['vat'])
        tot_price = float(product['tot_price'])
        return tot_price + float(float(tot_price/100)*vat)

    def _set_summary(self, products):
        #FIXME: to be substituted with mapper properties (tot, gross)
        session['summary'] = {}
        for val in ['tot', 'gross']:
            session['summary'][val] = float(0)
        session['summary']['vat'] = {}
        for p in products:
            session['summary']['tot'] += float(p.tot_price)
            session['summary']['gross'] += float(p.gross_price)
            vat = float(p.vat)
            if not session['summary']['vat'].has_key(vat):
                session['summary']['vat'][vat] = float(0)
            session['summary']['vat'][vat] += float(p.gross_price) - float(p.tot_price)

    @identity.require(identity.not_anonymous())
    def _get_invoice_dict(self, invoice, var='invoice', dummy=False, **kw):
        errors = {}
        if kw.has_key('errors'):
            errors = kw['errors']
        if invoice:
            if kw.has_key('currency'):
                invoice.currency = kw['currency']
            if kw.has_key('tmpl'):
                invoice.tmpl = kw['tmpl']
            if kw.has_key('created'):
                validdate = form.Created().to_python(
                        dict(created=self.date_validate(kw['created'])))
                invoice.created = validdate['created']
            self._set_summary(invoice.products)
        else:
            self._set_summary([])
        if hasattr(invoice, 'created'):
            created = invoice.created
        else:
            from datetime import datetime
            created = datetime.now()
        new_product = {}
        if kw.has_key('new_product'):
            new_product = kw['new_product']
        for col in self.iterator_product_form:
            if not new_product.has_key(col):
                new_product[col] = ''
        if kw.has_key('actions'):
            if kw['actions'].has_key('add_product'):
                validate = form.InvoiceProduct()
                try:
                    new_product = validate.to_python(new_product)
                    if new_product:
                        new_product['tot_price'] = float(self._get_tot_price(new_product))
                        new_product['gross_price'] = float(self._get_gross_price(new_product))
                        #if var == 'invoice':
                        if dummy:
                            product_obj = form.ProductObj(tables.Product, {})
                            platest = 0
                            index = len(invoice.products)
                            if index > 0:
                                platest = 1 + invoice.products[index -1].product_id
                            setattr(product_obj, 'product_id', platest)
                        else:
                            product_obj = tables.Product()

                        #elif var == 'proforma':
                        #    product_obj = tables.TmpProduct()
                        for key,value in new_product.iteritems():
                            setattr(product_obj, key, value)
                            new_product[key] = ''
                        invoice.products.append(product_obj)
                        self._set_summary(invoice.products)
                except Invalid, e:
                    errors = e.unpack_errors()
            elif kw['actions'].has_key('del_product'):
                pid = int(kw['del_product'])
                action = 'edit'
                if dummy:
                    invoice.products.pop(pid)
                    action = 'new'
                else:
                    tables.session.delete(self._get_product(pid))
                raise redirect(url(action,
                                   id=invoice.invoice_id,
                                   var=var))
            elif kw['actions'].has_key('save'):
                if dummy:
                    invoice = invoice.save()
                tables.session.begin()
                tables.session.commit()
                session['invoice'] = None
                pdf = self._get_pdf(invoice, var=var)
                filename = "%s-%s.pdf"%(invoice.number, invoice.invoice_id)
                output = os.path.join(self.output_path, var, filename)
                if not os.path.exists(os.path.dirname(output)):
                    os.makedirs(os.path.dirname(output))
                f = open(output, 'w')
                f.write(pdf)
                f.close()

                raise redirect(url('show',
                                   id=invoice.invoice_id,
                                   var=var))
        return dict(this=self,
                    csession = session,
                    errors = errors,
                    new_product = new_product,
                    invoice = invoice,
                    summary = session.get('summary'),
                    var=var,
                    calendar = self.calendar(id='created', value=created),)


    @identity.require(identity.not_anonymous())
    @expose(template="tginvoice.templates.invoices")
    def index(self, *args, **kw):
        self.pinvoices
        self._get_invoice_tmpl()
        return dict(this=self)

    def _get_pdf(self, invoice, var='invoice'):
        summary = {}
        summary['tot'] = invoice.tot
        summary['gross'] = invoice.gross
        summary['vat'] = self._get_summary_vat(invoice.products)
        tmplloader = TemplateLoader([])
        tmpl = tmplloader.load(self.invoice_rml(invoice.tmpl))
        stream = tmpl.generate(invoice=invoice,
                               logo = self.biller_logo,
                               date = self.date_i18n(invoice.created),
                               summary = summary,
                               var = var)
        source = stream.render('xml')
        return trml2pdf.parseString(source)

    @identity.require(identity.not_anonymous())
    @expose()
    def pdf(self, id=None, var='invoice', *args, **kw):
        invoice = self._get_invoice(id, var=var)

        if not self.check_identity_user(invoice.biller):
            return None
        pdf = self._get_pdf(invoice, var=var)
        filename = "%s_%s.pdf"%(invoice.biller.vat_code, invoice.number)
        #pdf = unicode(pdf, "UTF-8", "replace")
        response.headerMap["Content-Type"] = "application/x-pdf"
        response.headerMap["Content-Disposition"] = "attachment; filename=%s"%(filename)
        return pdf

    @identity.require(identity.not_anonymous())
    @expose(template="tginvoice.templates.invoices_show")
    def show(self, id=None, var='invoice', format=None, *args, **kw):
        invoice = self._get_invoice(id, var=var)

        if not self.check_identity_user(invoice.biller):
            return None

        customer = invoice.customer
        biller = invoice.biller
        products = invoice.products
        currency = invoice.currency
        summary = {}
        summary['tot'] = invoice.tot
        summary['gross'] = invoice.gross
        summary['vat'] = self._get_summary_vat(products)
        if var == 'proforma' and kw.has_key('actions'):
            if kw['actions'].has_key('save'):
                new = tables.Invoice()
                new.customer = invoice.customer
                new.biller = invoice.biller
                for key in tables.Invoice.c.keys():
                    if not key == 'number':
                        if not getattr(tables.Invoice.c, key).primary_key:
                            setattr(new, key, getattr(invoice, key))
                for product in invoice.products:
                    new.products.append(product)
                year, month,day = self.date
                num = int(len(self.pinvoices) + 1)
                number = "%s-%s"%(num, year)
                new.number = number
                tables.session.begin()
                tables.session.commit()
                var = 'invoice'
                pdf = self._get_pdf(new, var=var)
                filename = "%s-%s.pdf"%(invoice.number, invoice.invoice_id)
                output = os.path.join(self.output_path, var, filename)
                if not os.path.exists(os.path.dirname(output)):
                    os.makedirs(os.path.dirname(output))
                f = open(output, 'w')
                f.write(pdf)
                f.close()
                raise redirect(url('show',
                                   id=new.invoice_id,
                                   var='invoice'))

        return dict(this=self,
                        invoice=invoice,
                        var = var,
                        biller = biller,
                        customer = customer,
                        products = products,
                        currency = currency,
                        summary = summary,
                        errors = {})

    @identity.require(identity.not_anonymous())
    @expose(template="tginvoice.templates.invoices_edit")
    def edit(self, id=None, var='invoice', *args, **kw):

        invoice = self._get_invoice(id, var=var)
        if kw.has_key('customer'):
            invoice.customer = self._get_customer(kw['customer'])
        if not self.check_identity_user(invoice.biller):
            return None

        return self._get_invoice_dict(invoice, var=var, **kw)

    @identity.require(identity.not_anonymous())
    @expose()
    def delete(self, id=None, var='proforma', *args, **kw):

        invoice = self._get_invoice(id, var=var)

        if not self.check_identity_user(invoice.biller):
            return None
        tables.session.delete(invoice)
        tables.session.begin()
        tables.session.commit()
        raise redirect(url('.'))

    @identity.require(identity.not_anonymous())
    @expose(template="tginvoice.templates.invoices_new")
    def new(self, var='invoice', *args, **kw):

        if var == 'invoice':
            obj = form.InvoiceObj
            origobj = tables.Invoice
        elif var == 'proforma':
            obj = form.ProformaObj
            origobj = tables.Proforma

        if not kw.has_key('id'):
            session['invoice'] = None
        if kw.has_key('customer'):
            if not session.get('invoice'):
                year, month,day = self.date
                if var == 'invoice':
                    num = int(len(self.pinvoices) + 1)
                elif var == 'proforma':
                    num = int(len(self.pproformas) + 1)

                invoice = obj(origobj,
                              {'products':[],
                               'biller': self.pbiller,
                               'customer': None},
                              number = "%s-%s"%(num, year),
                              invoice_id = session['_id'])
                session['invoice'] = invoice
            invoice = session.get('invoice')
            invoice.customer = self._get_customer(kw['customer'])
        invoice = session.get('invoice')

        return self._get_invoice_dict(invoice, var, dummy=True, **kw)