# This file is part of lims_industry module for Tryton.
# The COPYRIGHT file at the top level of this repository contains
# the full copyright notices and license terms.

from trytond.model import fields
from trytond.wizard import Wizard, StateAction
from trytond.pool import Pool, PoolMeta
from trytond.pyson import PYSONEncoder, Eval, If
from trytond.transaction import Transaction
from trytond.i18n import gettext


class ResultsReport(metaclass=PoolMeta):
    __name__ = 'lims.results_report'

    plants_list = fields.Function(fields.Char('Plants'),
        'get_plants_list', searcher='search_plants_list')
    equipments_list = fields.Function(fields.Char('Equipments'),
        'get_equipments_list', searcher='search_equipments_list')
    components_list = fields.Function(fields.Char('Components'),
        'get_components_list', searcher='search_components_list')

    @classmethod
    def get_plants_list(cls, reports, name):
        cursor = Transaction().connection.cursor()
        pool = Pool()
        Plant = pool.get('lims.plant')
        Equipment = pool.get('lims.equipment')
        Sample = pool.get('lims.sample')
        Fraction = pool.get('lims.fraction')
        Notebook = pool.get('lims.notebook')
        ResultsSample = pool.get('lims.results_report.version.detail.sample')
        ResultsDetail = pool.get('lims.results_report.version.detail')
        ResultsVersion = pool.get('lims.results_report.version')

        result = {}
        for r in reports:
            result[r.id] = ''
            cursor.execute('SELECT DISTINCT(p.name) '
                'FROM "' + Plant._table + '" p '
                    'INNER JOIN "' + Equipment._table + '" e '
                    'ON p.id = e.plant '
                    'INNER JOIN "' + Sample._table + '" s '
                    'ON e.id = s.equipment '
                    'INNER JOIN "' + Fraction._table + '" f '
                    'ON s.id = f.sample '
                    'INNER JOIN "' + Notebook._table + '" n '
                    'ON f.id = n.fraction '
                    'INNER JOIN "' + ResultsSample._table + '" rs '
                    'ON n.id = rs.notebook '
                    'INNER JOIN "' + ResultsDetail._table + '" rd '
                    'ON rs.version_detail = rd.id '
                    'INNER JOIN "' + ResultsVersion._table + '" rv '
                    'ON rd.report_version = rv.id '
                'WHERE rv.results_report = %s '
                    'AND rd.state != \'annulled\' '
                'ORDER BY p.name', (r.id,))
            samples = [x[0] for x in cursor.fetchall()]
            if samples:
                result[r.id] = ', '.join(samples)
        return result

    @classmethod
    def search_plants_list(cls, name, clause):
        cursor = Transaction().connection.cursor()
        pool = Pool()
        Plant = pool.get('lims.plant')
        Equipment = pool.get('lims.equipment')
        Sample = pool.get('lims.sample')
        Fraction = pool.get('lims.fraction')
        Notebook = pool.get('lims.notebook')
        ResultsSample = pool.get('lims.results_report.version.detail.sample')
        ResultsDetail = pool.get('lims.results_report.version.detail')
        ResultsVersion = pool.get('lims.results_report.version')

        value = clause[2]
        cursor.execute('SELECT rv.results_report '
            'FROM "' + Plant._table + '" p '
                'INNER JOIN "' + Equipment._table + '" e '
                'ON p.id = e.plant '
                'INNER JOIN "' + Sample._table + '" s '
                'ON e.id = s.equipment '
                'INNER JOIN "' + Fraction._table + '" f '
                'ON s.id = f.sample '
                'INNER JOIN "' + Notebook._table + '" n '
                'ON f.id = n.fraction '
                'INNER JOIN "' + ResultsSample._table + '" rs '
                'ON n.id = rs.notebook '
                'INNER JOIN "' + ResultsDetail._table + '" rd '
                'ON rs.version_detail = rd.id '
                'INNER JOIN "' + ResultsVersion._table + '" rv '
                'ON rd.report_version = rv.id '
            'WHERE p.name ILIKE %s '
                'AND rd.state != \'annulled\'',
            (value,))
        details_ids = [x[0] for x in cursor.fetchall()]
        if not details_ids:
            return [('id', '=', -1)]
        return [('id', 'in', details_ids)]

    @classmethod
    def get_equipments_list(cls, reports, name):
        cursor = Transaction().connection.cursor()
        pool = Pool()
        Equipment = pool.get('lims.equipment')
        Sample = pool.get('lims.sample')
        Fraction = pool.get('lims.fraction')
        Notebook = pool.get('lims.notebook')
        ResultsSample = pool.get('lims.results_report.version.detail.sample')
        ResultsDetail = pool.get('lims.results_report.version.detail')
        ResultsVersion = pool.get('lims.results_report.version')

        result = {}
        for r in reports:
            result[r.id] = ''
            cursor.execute('SELECT DISTINCT(e.name) '
                'FROM "' + Equipment._table + '" e '
                    'INNER JOIN "' + Sample._table + '" s '
                    'ON e.id = s.equipment '
                    'INNER JOIN "' + Fraction._table + '" f '
                    'ON s.id = f.sample '
                    'INNER JOIN "' + Notebook._table + '" n '
                    'ON f.id = n.fraction '
                    'INNER JOIN "' + ResultsSample._table + '" rs '
                    'ON n.id = rs.notebook '
                    'INNER JOIN "' + ResultsDetail._table + '" rd '
                    'ON rs.version_detail = rd.id '
                    'INNER JOIN "' + ResultsVersion._table + '" rv '
                    'ON rd.report_version = rv.id '
                'WHERE rv.results_report = %s '
                    'AND rd.state != \'annulled\' '
                'ORDER BY e.name', (r.id,))
            samples = [x[0] for x in cursor.fetchall()]
            if samples:
                result[r.id] = ', '.join(samples)
        return result

    @classmethod
    def search_equipments_list(cls, name, clause):
        cursor = Transaction().connection.cursor()
        pool = Pool()
        Equipment = pool.get('lims.equipment')
        Sample = pool.get('lims.sample')
        Fraction = pool.get('lims.fraction')
        Notebook = pool.get('lims.notebook')
        ResultsSample = pool.get('lims.results_report.version.detail.sample')
        ResultsDetail = pool.get('lims.results_report.version.detail')
        ResultsVersion = pool.get('lims.results_report.version')

        value = clause[2]
        cursor.execute('SELECT rv.results_report '
            'FROM "' + Equipment._table + '" e '
                'INNER JOIN "' + Sample._table + '" s '
                'ON e.id = s.equipment '
                'INNER JOIN "' + Fraction._table + '" f '
                'ON s.id = f.sample '
                'INNER JOIN "' + Notebook._table + '" n '
                'ON f.id = n.fraction '
                'INNER JOIN "' + ResultsSample._table + '" rs '
                'ON n.id = rs.notebook '
                'INNER JOIN "' + ResultsDetail._table + '" rd '
                'ON rs.version_detail = rd.id '
                'INNER JOIN "' + ResultsVersion._table + '" rv '
                'ON rd.report_version = rv.id '
            'WHERE e.name ILIKE %s '
                'AND rd.state != \'annulled\'',
            (value,))
        details_ids = [x[0] for x in cursor.fetchall()]
        if not details_ids:
            return [('id', '=', -1)]
        return [('id', 'in', details_ids)]

    @classmethod
    def get_components_list(cls, reports, name):
        cursor = Transaction().connection.cursor()
        pool = Pool()
        ComponentKind = pool.get('lims.component.kind')
        Component = pool.get('lims.component')
        Sample = pool.get('lims.sample')
        Fraction = pool.get('lims.fraction')
        Notebook = pool.get('lims.notebook')
        ResultsSample = pool.get('lims.results_report.version.detail.sample')
        ResultsDetail = pool.get('lims.results_report.version.detail')
        ResultsVersion = pool.get('lims.results_report.version')

        result = {}
        for r in reports:
            result[r.id] = ''
            cursor.execute('SELECT DISTINCT(ct.name) '
                'FROM "' + ComponentKind._table + '" ct '
                    'INNER JOIN "' + Component._table + '" c '
                    'ON ct.id = c.kind '
                    'INNER JOIN "' + Sample._table + '" s '
                    'ON c.id = s.component '
                    'INNER JOIN "' + Fraction._table + '" f '
                    'ON s.id = f.sample '
                    'INNER JOIN "' + Notebook._table + '" n '
                    'ON f.id = n.fraction '
                    'INNER JOIN "' + ResultsSample._table + '" rs '
                    'ON n.id = rs.notebook '
                    'INNER JOIN "' + ResultsDetail._table + '" rd '
                    'ON rs.version_detail = rd.id '
                    'INNER JOIN "' + ResultsVersion._table + '" rv '
                    'ON rd.report_version = rv.id '
                'WHERE rv.results_report = %s '
                    'AND rd.state != \'annulled\' '
                'ORDER BY ct.name', (r.id,))
            samples = [x[0] for x in cursor.fetchall()]
            if samples:
                result[r.id] = ', '.join(samples)
        return result

    @classmethod
    def search_components_list(cls, name, clause):
        cursor = Transaction().connection.cursor()
        pool = Pool()
        ComponentKind = pool.get('lims.component.kind')
        Component = pool.get('lims.component')
        Sample = pool.get('lims.sample')
        Fraction = pool.get('lims.fraction')
        Notebook = pool.get('lims.notebook')
        ResultsSample = pool.get('lims.results_report.version.detail.sample')
        ResultsDetail = pool.get('lims.results_report.version.detail')
        ResultsVersion = pool.get('lims.results_report.version')

        value = clause[2]
        cursor.execute('SELECT rv.results_report '
            'FROM "' + ComponentKind._table + '" ct '
                'INNER JOIN "' + Component._table + '" c '
                'ON ct.id = c.kind '
                'INNER JOIN "' + Sample._table + '" s '
                'ON c.id = s.component '
                'INNER JOIN "' + Fraction._table + '" f '
                'ON s.id = f.sample '
                'INNER JOIN "' + Notebook._table + '" n '
                'ON f.id = n.fraction '
                'INNER JOIN "' + ResultsSample._table + '" rs '
                'ON n.id = rs.notebook '
                'INNER JOIN "' + ResultsDetail._table + '" rd '
                'ON rs.version_detail = rd.id '
                'INNER JOIN "' + ResultsVersion._table + '" rv '
                'ON rd.report_version = rv.id '
            'WHERE ct.name ILIKE %s '
                'AND rd.state != \'annulled\'',
            (value,))
        details_ids = [x[0] for x in cursor.fetchall()]
        if not details_ids:
            return [('id', '=', -1)]
        return [('id', 'in', details_ids)]


class ResultsReport2(metaclass=PoolMeta):
    __name__ = 'lims.results_report'

    def _get_name_substitutions(self):
        pool = Pool()
        ResultsSample = pool.get('lims.results_report.version.detail.sample')

        res = super()._get_name_substitutions()

        samples = ResultsSample.search([
            ('version_detail.report_version.results_report',
                '=', self.id),
            ('version_detail.valid', '=', True),
            ], order=[('id', 'ASC')], limit=1)
        sample = samples and samples[0] or None

        substitutions = {
            'party_fantasy_name': sample and sample.party.fantasy_name or '',
            'equipment_name': (sample and sample.equipment and
                sample.equipment.name or ''),
            'equipment_serial_number': (sample and sample.equipment and
                sample.equipment.serial_number or ''),
            'equipment_type': (sample and sample.equipment and
                sample.equipment.type.name or ''),
            'plant_name': sample and sample.plant and sample.plant.name or '',
            'component_customer_description': (sample and sample.component and
                sample.component.customer_description or ''),
            'component_kind': (sample and sample.component and
                sample.component.kind.name or ''),
            'ind_equipment': (sample and
                sample.notebook.fraction.sample.ind_equipment and
                (str(sample.notebook.fraction.sample.ind_equipment) +
                sample.notebook.fraction.sample.ind_equipment_uom) or '')
            }
        for key, value in list(substitutions.items()):
            substitutions[key.upper()] = value.upper()
        res.update(substitutions)
        return res


class ResultsReportVersionDetail(metaclass=PoolMeta):
    __name__ = 'lims.results_report.version.detail'

    plants_list = fields.Function(fields.Char('Plants'),
        'get_plants_list', searcher='search_plants_list')
    equipments_list = fields.Function(fields.Char('Equipments'),
        'get_equipments_list', searcher='search_equipments_list')
    components_list = fields.Function(fields.Char('Components'),
        'get_components_list', searcher='search_components_list')

    @classmethod
    def get_plants_list(cls, details, name):
        cursor = Transaction().connection.cursor()
        pool = Pool()
        Plant = pool.get('lims.plant')
        Equipment = pool.get('lims.equipment')
        Sample = pool.get('lims.sample')
        Fraction = pool.get('lims.fraction')
        Notebook = pool.get('lims.notebook')
        ResultsSample = pool.get('lims.results_report.version.detail.sample')

        result = {}
        for d in details:
            result[d.id] = ''
            cursor.execute('SELECT DISTINCT(p.name) '
                'FROM "' + Plant._table + '" p '
                    'INNER JOIN "' + Equipment._table + '" e '
                    'ON p.id = e.plant '
                    'INNER JOIN "' + Sample._table + '" s '
                    'ON e.id = s.equipment '
                    'INNER JOIN "' + Fraction._table + '" f '
                    'ON s.id = f.sample '
                    'INNER JOIN "' + Notebook._table + '" n '
                    'ON f.id = n.fraction '
                    'INNER JOIN "' + ResultsSample._table + '" rs '
                    'ON n.id = rs.notebook '
                'WHERE rs.version_detail = %s '
                'ORDER BY p.name', (d.id,))
            samples = [x[0] for x in cursor.fetchall()]
            if samples:
                result[d.id] = ', '.join(samples)
        return result

    @classmethod
    def search_plants_list(cls, name, clause):
        cursor = Transaction().connection.cursor()
        pool = Pool()
        Plant = pool.get('lims.plant')
        Equipment = pool.get('lims.equipment')
        Sample = pool.get('lims.sample')
        Fraction = pool.get('lims.fraction')
        Notebook = pool.get('lims.notebook')
        ResultsSample = pool.get('lims.results_report.version.detail.sample')

        value = clause[2]
        cursor.execute('SELECT rs.version_detail '
            'FROM "' + Plant._table + '" p '
                'INNER JOIN "' + Equipment._table + '" e '
                'ON p.id = e.plant '
                'INNER JOIN "' + Sample._table + '" s '
                'ON e.id = s.equipment '
                'INNER JOIN "' + Fraction._table + '" f '
                'ON s.id = f.sample '
                'INNER JOIN "' + Notebook._table + '" n '
                'ON f.id = n.fraction '
                'INNER JOIN "' + ResultsSample._table + '" rs '
                'ON n.id = rs.notebook '
            'WHERE p.name ILIKE %s',
            (value,))
        details_ids = [x[0] for x in cursor.fetchall()]
        if not details_ids:
            return [('id', '=', -1)]
        return [('id', 'in', details_ids)]

    @classmethod
    def get_equipments_list(cls, details, name):
        cursor = Transaction().connection.cursor()
        pool = Pool()
        Equipment = pool.get('lims.equipment')
        Sample = pool.get('lims.sample')
        Fraction = pool.get('lims.fraction')
        Notebook = pool.get('lims.notebook')
        ResultsSample = pool.get('lims.results_report.version.detail.sample')

        result = {}
        for d in details:
            result[d.id] = ''
            cursor.execute('SELECT DISTINCT(e.name) '
                'FROM "' + Equipment._table + '" e '
                    'INNER JOIN "' + Sample._table + '" s '
                    'ON e.id = s.equipment '
                    'INNER JOIN "' + Fraction._table + '" f '
                    'ON s.id = f.sample '
                    'INNER JOIN "' + Notebook._table + '" n '
                    'ON f.id = n.fraction '
                    'INNER JOIN "' + ResultsSample._table + '" rs '
                    'ON n.id = rs.notebook '
                'WHERE rs.version_detail = %s '
                'ORDER BY e.name', (d.id,))
            samples = [x[0] for x in cursor.fetchall()]
            if samples:
                result[d.id] = ', '.join(samples)
        return result

    @classmethod
    def search_equipments_list(cls, name, clause):
        cursor = Transaction().connection.cursor()
        pool = Pool()
        Equipment = pool.get('lims.equipment')
        Sample = pool.get('lims.sample')
        Fraction = pool.get('lims.fraction')
        Notebook = pool.get('lims.notebook')
        ResultsSample = pool.get('lims.results_report.version.detail.sample')

        value = clause[2]
        cursor.execute('SELECT rs.version_detail '
            'FROM "' + Equipment._table + '" e '
                'INNER JOIN "' + Sample._table + '" s '
                'ON e.id = s.equipment '
                'INNER JOIN "' + Fraction._table + '" f '
                'ON s.id = f.sample '
                'INNER JOIN "' + Notebook._table + '" n '
                'ON f.id = n.fraction '
                'INNER JOIN "' + ResultsSample._table + '" rs '
                'ON n.id = rs.notebook '
            'WHERE e.name ILIKE %s',
            (value,))
        details_ids = [x[0] for x in cursor.fetchall()]
        if not details_ids:
            return [('id', '=', -1)]
        return [('id', 'in', details_ids)]

    @classmethod
    def get_components_list(cls, details, name):
        cursor = Transaction().connection.cursor()
        pool = Pool()
        ComponentKind = pool.get('lims.component.kind')
        Component = pool.get('lims.component')
        Sample = pool.get('lims.sample')
        Fraction = pool.get('lims.fraction')
        Notebook = pool.get('lims.notebook')
        ResultsSample = pool.get('lims.results_report.version.detail.sample')

        result = {}
        for d in details:
            result[d.id] = ''
            cursor.execute('SELECT DISTINCT(ct.name) '
                'FROM "' + ComponentKind._table + '" ct '
                    'INNER JOIN "' + Component._table + '" c '
                    'ON ct.id = c.kind '
                    'INNER JOIN "' + Sample._table + '" s '
                    'ON c.id = s.component '
                    'INNER JOIN "' + Fraction._table + '" f '
                    'ON s.id = f.sample '
                    'INNER JOIN "' + Notebook._table + '" n '
                    'ON f.id = n.fraction '
                    'INNER JOIN "' + ResultsSample._table + '" rs '
                    'ON n.id = rs.notebook '
                'WHERE rs.version_detail = %s '
                'ORDER BY ct.name', (d.id,))
            samples = [x[0] for x in cursor.fetchall()]
            if samples:
                result[d.id] = ', '.join(samples)
        return result

    @classmethod
    def search_components_list(cls, name, clause):
        cursor = Transaction().connection.cursor()
        pool = Pool()
        ComponentKind = pool.get('lims.component.kind')
        Component = pool.get('lims.component')
        Sample = pool.get('lims.sample')
        Fraction = pool.get('lims.fraction')
        Notebook = pool.get('lims.notebook')
        ResultsSample = pool.get('lims.results_report.version.detail.sample')

        value = clause[2]
        cursor.execute('SELECT rs.version_detail '
            'FROM "' + ComponentKind._table + '" ct '
                'INNER JOIN "' + Component._table + '" c '
                'ON ct.id = c.kind '
                'INNER JOIN "' + Sample._table + '" s '
                'ON c.id = s.component '
                'INNER JOIN "' + Fraction._table + '" f '
                'ON s.id = f.sample '
                'INNER JOIN "' + Notebook._table + '" n '
                'ON f.id = n.fraction '
                'INNER JOIN "' + ResultsSample._table + '" rs '
                'ON n.id = rs.notebook '
            'WHERE ct.name ILIKE %s',
            (value,))
        details_ids = [x[0] for x in cursor.fetchall()]
        if not details_ids:
            return [('id', '=', -1)]
        return [('id', 'in', details_ids)]


class ResultsReportVersionDetailSample(metaclass=PoolMeta):
    __name__ = 'lims.results_report.version.detail.sample'

    plant = fields.Function(fields.Many2One('lims.plant', 'Plant'),
        'get_notebook_field')
    equipment = fields.Function(fields.Many2One('lims.equipment', 'Equipment'),
        'get_notebook_field')
    equipment_template = fields.Function(fields.Many2One(
        'lims.equipment.template', 'Equipment Template'), 'get_notebook_field')
    equipment_model = fields.Function(fields.Char('Equipment Model'),
        'get_notebook_field')
    equipment_serial_number = fields.Function(fields.Char(
        'Equipment Serial Number'), 'get_notebook_field')
    equipment_name = fields.Function(fields.Char(
        'Equipment Name'), 'get_notebook_field')
    component = fields.Function(fields.Many2One('lims.component', 'Component'),
        'get_notebook_field')
    comercial_product = fields.Function(fields.Many2One(
        'lims.comercial.product', 'Comercial Product'), 'get_notebook_field')
    precedent1 = fields.Many2One('lims.notebook', 'Precedent 1',
        domain=[If(~Eval('free_precedents'),
            [('component', '=', Eval('component')),
            ('fraction.sample.state', '!=', 'annulled')],
            [('fraction.sample.state', '!=', 'annulled')])],
        depends=['free_precedents', 'component'])
    precedent2 = fields.Many2One('lims.notebook', 'Precedent 2',
        domain=[If(~Eval('free_precedents'),
            [('component', '=', Eval('component')),
            ('fraction.sample.state', '!=', 'annulled')],
            [('fraction.sample.state', '!=', 'annulled')])],
        depends=['free_precedents', 'component'])
    precedent3 = fields.Many2One('lims.notebook', 'Precedent 3',
        domain=[If(~Eval('free_precedents'),
            [('component', '=', Eval('component')),
            ('fraction.sample.state', '!=', 'annulled')],
            [('fraction.sample.state', '!=', 'annulled')])],
        depends=['free_precedents', 'component'])
    precedent4 = fields.Many2One('lims.notebook', 'Precedent 4',
        domain=[If(~Eval('free_precedents'),
            [('component', '=', Eval('component')),
            ('fraction.sample.state', '!=', 'annulled')],
            [('fraction.sample.state', '!=', 'annulled')])],
        depends=['free_precedents', 'component'])
    precedent5 = fields.Many2One('lims.notebook', 'Precedent 5',
        domain=[If(~Eval('free_precedents'),
            [('component', '=', Eval('component')),
            ('fraction.sample.state', '!=', 'annulled')],
            [('fraction.sample.state', '!=', 'annulled')])],
        depends=['free_precedents', 'component'])
    precedent6 = fields.Many2One('lims.notebook', 'Precedent 6',
        domain=[If(~Eval('free_precedents'),
            [('component', '=', Eval('component')),
            ('fraction.sample.state', '!=', 'annulled')],
            [('fraction.sample.state', '!=', 'annulled')])],
        depends=['free_precedents', 'component'])
    precedent7 = fields.Many2One('lims.notebook', 'Precedent 7',
        domain=[If(~Eval('free_precedents'),
            [('component', '=', Eval('component')),
            ('fraction.sample.state', '!=', 'annulled')],
            [('fraction.sample.state', '!=', 'annulled')])],
        depends=['free_precedents', 'component'])
    precedent8 = fields.Many2One('lims.notebook', 'Precedent 8',
        domain=[If(~Eval('free_precedents'),
            [('component', '=', Eval('component')),
            ('fraction.sample.state', '!=', 'annulled')],
            [('fraction.sample.state', '!=', 'annulled')])],
        depends=['free_precedents', 'component'])
    free_precedents = fields.Boolean('Free precedents')
    precedent1_diagnosis = fields.Function(fields.Text(
        'Diagnosis Precedent 1'), 'on_change_with_precedent1_diagnosis')
    precedent2_diagnosis = fields.Function(fields.Text(
        'Diagnosis Precedent 2'), 'on_change_with_precedent2_diagnosis')
    precedent3_diagnosis = fields.Function(fields.Text(
        'Diagnosis Precedent 3'), 'on_change_with_precedent3_diagnosis')
    precedent1_diagnosis_states = fields.Function(fields.Dict(
        'lims.diagnosis.state', 'Diagnosis States Precedent 1'),
        'get_precedent_diagnosis')
    precedent2_diagnosis_states = fields.Function(fields.Dict(
        'lims.diagnosis.state', 'Diagnosis States Precedent 2'),
        'get_precedent_diagnosis')
    precedent3_diagnosis_states = fields.Function(fields.Dict(
        'lims.diagnosis.state', 'Diagnosis States Precedent 3'),
        'get_precedent_diagnosis')

    @staticmethod
    def default_free_precedents():
        return False

    @classmethod
    def view_attributes(cls):
        missing_diagnosis = True if 'diagnosis' not in cls._fields else False
        return super().view_attributes() + [
            ('//group[@id="diagnosis"]', 'states', {
                    'invisible': missing_diagnosis,
                    }),
            ]

    @fields.depends('precedent1')
    def on_change_with_precedent1_diagnosis(self, name=None):
        if self.precedent1:
            result = self.get_precedent_diagnosis((self,),
                ('precedent1_diagnosis',))
            return result['precedent1_diagnosis'][self.id]
        return None

    @fields.depends('precedent2')
    def on_change_with_precedent2_diagnosis(self, name=None):
        if self.precedent2:
            result = self.get_precedent_diagnosis((self,),
                ('precedent2_diagnosis',))
            return result['precedent2_diagnosis'][self.id]
        return None

    @fields.depends('precedent3')
    def on_change_with_precedent3_diagnosis(self, name=None):
        if self.precedent3:
            result = self.get_precedent_diagnosis((self,),
                ('precedent3_diagnosis',))
            return result['precedent3_diagnosis'][self.id]
        return None

    @classmethod
    def get_precedent_diagnosis(cls, samples, names):
        result = {}
        missing_diagnosis = True if 'diagnosis' not in cls._fields else False
        if missing_diagnosis:
            for name in names:
                result[name] = {}
                for s in samples:
                    result[name][s.id] = None
        else:
            for name in names:
                result[name] = {}
                if 'precedent1' in name:
                    for s in samples:
                        result[name][s.id] = cls._get_precedent_diagnosis(
                            s.precedent1, name)
                elif 'precedent2' in name:
                    for s in samples:
                        result[name][s.id] = cls._get_precedent_diagnosis(
                            s.precedent2, name)
                else:  # name == 'precedent3_diagnosis':
                    for s in samples:
                        result[name][s.id] = cls._get_precedent_diagnosis(
                            s.precedent3, name)
        return result

    @classmethod
    def _get_precedent_diagnosis(cls, precedent, name):
        if not precedent:
            return None
        precedent_sample = cls.search([
            ('notebook', '=', precedent),
            ])
        if not precedent_sample:
            return None
        return (precedent_sample[0].diagnosis_states if 'states' in name
            else precedent_sample[0].diagnosis)

    @classmethod
    def _get_fields_from_sample(cls, sample, only_accepted=True):
        sample_default = super()._get_fields_from_sample(sample,
            only_accepted)
        sample_default['precedent1'] = (sample.precedent1 and
            sample.precedent1 or None)
        sample_default['precedent2'] = (sample.precedent2 and
            sample.precedent2 or None)
        sample_default['precedent3'] = (sample.precedent3 and
            sample.precedent3 or None)
        sample_default['precedent4'] = (sample.precedent4 and
            sample.precedent4 or None)
        sample_default['precedent5'] = (sample.precedent5 and
            sample.precedent5 or None)
        sample_default['precedent6'] = (sample.precedent6 and
            sample.precedent6 or None)
        sample_default['precedent7'] = (sample.precedent7 and
            sample.precedent7 or None)
        sample_default['precedent8'] = (sample.precedent8 and
            sample.precedent8 or None)
        return sample_default

    @classmethod
    def create(cls, vlist):
        samples = super().create(vlist)
        for sample in samples:
            if not sample.precedent1:
                precedents = cls.get_default_precedents(sample)
                if not precedents:
                    continue
                for i in range(0, min(3, len(precedents))):
                    setattr(sample, 'precedent%s' % str(i + 1), precedents[i])
                sample.save()
                cls.update_precedent_lines(sample)
        return samples

    @classmethod
    def write(cls, *args):
        super().write(*args)
        update_precedent_lines = False
        if not update_precedent_lines:
            return
        actions = iter(args)
        for samples, vals in zip(actions, actions):
            change_precedents = False
            for field in ['precedent1', 'precedent2', 'precedent3',
                    'precedent4', 'precedent5', 'precedent6', 'precedent7',
                    'precedent8']:
                if field in vals:
                    change_precedents = True
            if change_precedents:
                for sample in samples:
                    cls.update_precedent_lines(sample)

    @staticmethod
    def get_default_precedents(sample):
        pool = Pool()
        Notebook = pool.get('lims.notebook')
        if not sample.component:
            return []
        precedents = Notebook.search([
            ('id', '!=', sample.notebook.id),
            ('component', '=', sample.component),
            ('fraction.sample.state', '!=', 'annulled'),
            ('invoice_party', '=', sample.notebook.invoice_party),
            ], order=[
            ('fraction.sample.number', 'DESC'),
            ], limit=3)
        return precedents

    @classmethod
    def update_precedent_lines(cls, sample):
        pool = Pool()
        ResultsLine = pool.get('lims.results_report.version.detail.line')
        NotebookLine = pool.get('lims.notebook.line')

        precedent_lines = ResultsLine.search([
            ('detail_sample', '=', sample.id),
            ('notebook_line', '=', None),
            ])
        if precedent_lines:
            ResultsLine.delete(precedent_lines)

        result_lines = ResultsLine.search([
            ('detail_sample', '=', sample.id),
            ])
        analysis = [rl.notebook_line.analysis.id for rl in result_lines]

        lines_to_create = []
        for precedent in [sample.precedent1, sample.precedent2,
                sample.precedent3]:
            if not precedent:
                continue
            precedent_lines = NotebookLine.search([
                ('notebook', '=', precedent),
                ('analysis', 'not in', analysis),
                ('accepted', '=', True),
                ])
            for line in precedent_lines:
                lines_to_create.append({
                    'detail_sample': sample.id,
                    'precedent_analysis': line.analysis.id,
                    })
                analysis.append(line.analysis.id)

        if lines_to_create:
            ResultsLine.create(lines_to_create)


class ResultsReportVersionDetailLine(metaclass=PoolMeta):
    __name__ = 'lims.results_report.version.detail.line'

    precedent_analysis = fields.Many2One('lims.analysis', 'Analysis')
    precedent1_result = fields.Function(fields.Char('Precedent 1'),
        'get_precedent_result')
    precedent2_result = fields.Function(fields.Char('Precedent 2'),
        'get_precedent_result')
    precedent3_result = fields.Function(fields.Char('Precedent 3'),
        'get_precedent_result')
    precedent4_result = fields.Function(fields.Char('Precedent 4'),
        'get_precedent_result')
    precedent5_result = fields.Function(fields.Char('Precedent 5'),
        'get_precedent_result')
    precedent6_result = fields.Function(fields.Char('Precedent 6'),
        'get_precedent_result')
    precedent7_result = fields.Function(fields.Char('Precedent 7'),
        'get_precedent_result')
    precedent8_result = fields.Function(fields.Char('Precedent 8'),
        'get_precedent_result')

    @classmethod
    def __setup__(cls):
        super().__setup__()
        cls.analysis.getter = 'get_analysis'

    @classmethod
    def get_analysis(cls, details, name):
        result = {}
        for d in details:
            if d.precedent_analysis:
                result[d.id] = d.precedent_analysis.id
            elif d.notebook_line:
                field = getattr(d.notebook_line, name, None)
                result[d.id] = field.id if field else None
            else:
                result[d.id] = None
        return result

    @classmethod
    def get_precedent_result(cls, details, names):
        result = {}
        for name in names:
            result[name] = {}
            if name == 'precedent1_result':
                for d in details:
                    result[name][d.id] = cls._get_precedent_result(
                        d.detail_sample.precedent1, d)
            elif name == 'precedent2_result':
                for d in details:
                    result[name][d.id] = cls._get_precedent_result(
                        d.detail_sample.precedent2, d)
            elif name == 'precedent3_result':
                for d in details:
                    result[name][d.id] = cls._get_precedent_result(
                        d.detail_sample.precedent3, d)
            elif name == 'precedent4_result':
                for d in details:
                    result[name][d.id] = cls._get_precedent_result(
                        d.detail_sample.precedent4, d)
            elif name == 'precedent5_result':
                for d in details:
                    result[name][d.id] = cls._get_precedent_result(
                        d.detail_sample.precedent5, d)
            elif name == 'precedent6_result':
                for d in details:
                    result[name][d.id] = cls._get_precedent_result(
                        d.detail_sample.precedent6, d)
            elif name == 'precedent7_result':
                for d in details:
                    result[name][d.id] = cls._get_precedent_result(
                        d.detail_sample.precedent7, d)
            else:  # name == 'precedent8_result':
                for d in details:
                    result[name][d.id] = cls._get_precedent_result(
                        d.detail_sample.precedent8, d)
        return result

    @classmethod
    def _get_precedent_result(cls, precedent, line):
        pool = Pool()
        NotebookLine = pool.get('lims.notebook.line')
        if not precedent:
            return ''
        if not line.notebook_line:
            return ''
        precedent_line = NotebookLine.search([
            ('notebook', '=', precedent),
            ('analysis', '=', line.analysis),
            ['OR', ('method', '=', line.method), [
                ('method.equivalence_code', 'not in', [None, '']),
                ('method.equivalence_code', '=', line.method.equivalence_code),
                ]],
            ('accepted', '=', True),
            ])
        if not precedent_line:
            return ''
        return precedent_line[0].formated_result


class OpenResultsDetailPrecedent(Wizard):
    'Results Report Precedent'
    __name__ = 'lims.results_report.version.detail.open_precedent'

    start = StateAction('lims.act_lims_results_report_list')

    def do_start(self, action):
        pool = Pool()
        ResultsReport = pool.get('lims.results_report')
        ResultsDetail = pool.get('lims.results_report.version.detail')
        ResultsSample = pool.get('lims.results_report.version.detail.sample')
        Notebook = pool.get('lims.notebook')

        active_ids = Transaction().context['active_ids']
        details = ResultsDetail.browse(active_ids)

        component_ids = []
        samples = ResultsSample.search([
            ('version_detail', 'in', active_ids),
            ])
        for s in samples:
            if s.component:
                component_ids.append(s.component.id)

        notebooks = Notebook.search([
            ('component', 'in', component_ids),
            ])
        notebook_ids = [n.id for n in notebooks]

        reports = ResultsReport.search([
            ('versions.details.samples.notebook', 'in', notebook_ids),
            ('versions.details.id', 'not in', active_ids),
            ])
        results_report_ids = [r.id for r in reports]

        action['pyson_domain'] = PYSONEncoder().encode([
            ('id', 'in', results_report_ids),
            ])
        action['name'] = '%s (%s)' % (gettext('lims_industry.lbl_precedents'),
            ', '.join(d.rec_name for d in details))
        return action, {}


class SendResultsReport(metaclass=PoolMeta):
    __name__ = 'lims_email.send_results_report'

    def get_grouped_reports(self, report_ids):
        pool = Pool()
        Config = pool.get('lims.configuration')
        ResultsReport = pool.get('lims.results_report')
        ResultsSample = pool.get('lims.results_report.version.detail.sample')

        config = Config(1)

        if config.mail_ack_report_grouping == 'plant':
            res = {}
            results_reports = ResultsReport.browse(report_ids)
            for report in results_reports:
                plant_id = None
                samples = ResultsSample.search([
                    ('version_detail.report_version.results_report.id',
                        '=', report.id),
                    ])
                if samples:
                    sample = samples[0].notebook.fraction.sample
                    if sample.plant:
                        plant_id = sample.plant.id
                if not plant_id:
                    plant_id = report.id

                key = (plant_id, report.cie_fraction_type)
                if key not in res:
                    res[key] = {
                        'cie_fraction_type': report.cie_fraction_type,
                        'reports': [],
                        }
                res[key]['reports'].append(report)
            return res

        if config.mail_ack_report_grouping == 'equipment':
            res = {}
            results_reports = ResultsReport.browse(report_ids)
            for report in results_reports:
                equipment_id = None
                samples = ResultsSample.search([
                    ('version_detail.report_version.results_report.id',
                        '=', report.id),
                    ])
                if samples:
                    sample = samples[0].notebook.fraction.sample
                    if sample.equipment:
                        equipment_id = sample.equipment.id
                if not equipment_id:
                    equipment_id = report.id

                key = (equipment_id, report.cie_fraction_type)
                if key not in res:
                    res[key] = {
                        'cie_fraction_type': report.cie_fraction_type,
                        'reports': [],
                        }
                res[key]['reports'].append(report)
            return res

        return super().get_grouped_reports(report_ids)


class OpenResultsDetailAttachment(metaclass=PoolMeta):
    __name__ = 'lims.results_report.version.detail.open_attachment'

    def get_resource(self, details):
        res = super().get_resource(details)
        for detail in details:
            for s in detail.samples:
                if s.notebook.fraction.sample.equipment:
                    res.append(self._get_resource(
                        s.notebook.fraction.sample.equipment))
                if s.notebook.fraction.sample.component:
                    res.append(self._get_resource(
                        s.notebook.fraction.sample.component))
        return res


class ReportNameFormat(metaclass=PoolMeta):
    __name__ = 'lims.result_report.format'

    @classmethod
    def __setup__(cls):
        super().__setup__()
        cls.format_.help += (
            "\n- ${party_fantasy_name}"
            "\n- ${equipment_name}"
            "\n- ${equipment_serial_number}"
            "\n- ${equipment_type}"
            "\n- ${plant_name}"
            "\n- ${component_customer_description}"
            "\n- ${component_kind}"
            "\n- ${ind_equipment}")
