#This file is part of Tryton.  The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
from __future__ import with_statement
from decimal import Decimal
from trytond.model import ModelView, ModelSQL, fields
from trytond.pyson import Not, Equal, Eval
from trytond.transaction import Transaction


class TimesheetLine(ModelSQL, ModelView):
    _name = 'timesheet.line'

    def compute_cost(self, line):
        employee_obj = self.pool.get('company.employee')
        currency_obj = self.pool.get('currency.currency')

        cost_price = employee_obj.compute_cost_price(line.employee.id,
                date=line.date)

        line_company = line.employee.company
        work_company = line.work.company
        if line_company.id != work_company.id and\
                line_company.currency.id != work_company.currency.id:
            with Transaction().set_context(date=line.date):
                cost_price = currency_obj.compute(line_company.currency.id,
                    cost_price, work_company.currency.id)

        return Decimal(str(line.hours)) * cost_price

TimesheetLine()

class Work(ModelSQL, ModelView):
    'Work Effort'
    _name = 'project.work'

    product = fields.Many2One('product.product', 'Product',
            states={
                'invisible': Not(Equal(Eval('type'), 'task')),
            }, on_change=['product', 'party', 'hours', 'company'],
            depends=['type', 'party', 'hours', 'company'])
    list_price = fields.Numeric('List Price',
            digits=(16, Eval('currency_digits', 2)),
            states={
                'invisible': Not(Equal(Eval('type'), 'task')),
            }, depends=['type', 'currency_digits'])
    revenue = fields.Function(fields.Numeric('Revenue',
        digits=(16, Eval('currency_digits', 2)),
        states={
            'invisible': Not(Equal(Eval('type'), 'project')),
        }, depends=['type', 'currency_digits']), 'get_revenue')
    cost = fields.Function(fields.Numeric('Cost',
        digits=(16, Eval('currency_digits', 2)), depends=['currency_digits']),
        'get_cost')
    currency_digits = fields.Function(fields.Integer('Currency Digits',
        on_change_with=['company']), 'get_currency_digits')

    def get_cost(self, ids, name):
        timesheet_line_obj = self.pool.get('timesheet.line')
        all_ids = self.search([
                ('parent', 'child_of', ids),
                ('active', '=', True)]) + ids
        all_ids = list(set(all_ids))
        res = {}
        id2work = {}
        leafs = set()
        for work in self.browse(all_ids):
            id2work[work.id] = work
            if not work.children:
                leafs.add(work.id)

            res[work.id] = Decimal('0')
            for ts_line in work.timesheet_lines:
                res[work.id] += timesheet_line_obj.compute_cost(ts_line)

        while leafs:
            parents = set()
            for work_id in leafs:
                work = id2work[work_id]
                if not work.active:
                    continue
                if work.parent and work.parent.id in res:
                    res[work.parent.id] += res[work_id]
                    parents.add(work.parent.id)
            leafs = parents

        for id in all_ids:
            if id not in ids:
                del res[id]

        return res

    def get_revenue(self, ids, name):
        all_ids = self.search([
                ('parent', 'child_of', ids),
                ('active', '=', True)]) + ids
        all_ids = list(set(all_ids))
        res = {}
        id2work = {}
        leafs = set()
        for work in self.browse(all_ids):
            id2work[work.id] = work
            if not work.children:
                leafs.add(work.id)

            if work.type == 'task':
                res[work.id] = work.list_price * Decimal(str(work.total_effort))
            else:
                res[work.id] = Decimal('0')

        while leafs:
            parents = set()
            for work_id in leafs:
                work = id2work[work_id]
                if not work.active:
                    continue
                if work.parent and work.parent.id in res:
                    res[work.parent.id] += res[work_id]
                    parents.add(work.parent.id)
            leafs = parents

        for id in all_ids:
            if id not in ids:
                del res[id]

        return res

    def get_currency_digits(self, ids, name):
        res = {}
        for work in self.browse(ids):
            res[work.id] = work.company.currency.digits
        return res

    def on_change_with_currency_digits(self, vals):
        company_obj = self.pool.get('company.company')
        if vals.get('company'):
            company = company_obj.browse(vals['company'])
            return company.currency.digits
        return 2

    def default_currency_digits(self):
        company_obj = self.pool.get('company.company')
        company = Transaction().context.get('company')
        if company:
            company = company_obj.browse(company)
            return company.currency.digits
        return 2

    def on_change_product(self, vals):
        product_obj = self.pool.get('product.product')
        user_obj = self.pool.get('res.user')
        company_obj = self.pool.get('company.company')
        model_data_obj = self.pool.get('ir.model.data')
        uom_obj = self.pool.get('product.uom')

        if not vals.get('product'):
            return {}

        context = {}

        product = product_obj.browse(vals['product'])

        if vals.get('party'):
            context['customer'] = vals['party']

        uom_id = model_data_obj.get_id('product', 'uom_hour')
        hour_uom = uom_obj.browse(uom_id)

        with Transaction().set_context(context):
            list_price = uom_obj.compute_price(product.default_uom,
                    product.list_price, hour_uom)

        if vals.get('company'):
            user = user_obj.browse(Transaction().user)
            if user.company.id != vals['company']:
                company = company_obj.browse(vals['company'])
                if user.company.currency.id != company.currency.id:
                    list_price = currency_obj.compute(user.company.currency,
                            list_price, company.currency)

        return {'list_price': list_price}
Work()
