# -*- coding: utf-8 -*-
##############################################################################
#
#    GNU Health: The Free Health and Hospital Information System
#    Copyright (C) 2008-2012  Luis Falcon <lfalcon@gnusolidario.org>
#
#    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 3 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, see <http://www.gnu.org/licenses/>.
#
##############################################################################


from trytond.model import ModelView, ModelSingleton, ModelSQL, fields
from trytond.transaction import Transaction
from trytond.pool import Pool
from trytond.pyson import Eval, Not, Bool, And, Equal
from datetime import datetime


class InpatientSequences(ModelSingleton, ModelSQL, ModelView):
    "Inpatient Registration Sequences for GNU Health"

    _name = "gnuhealth.sequences"

    inpatient_registration_sequence = fields.Property(fields.Many2One('ir.sequence',
        'Inpatient Sequence', domain=[('code', '=', 'gnuhealth.inpatient.registration')],
        required=True))

InpatientSequences()


class InpatientRegistration(ModelSQL, ModelView):
    'Patient admission History'
    _name = 'gnuhealth.inpatient.registration'
    _description = __doc__

    name = fields.Char('Registration Code', readonly=True, select=True)
    patient = fields.Many2One('gnuhealth.patient', 'Patient',
     required=True, select=True)
    admission_type = fields.Selection([
        ('routine', 'Routine'),
        ('maternity', 'Maternity'),
        ('elective', 'Elective'),
        ('urgent', 'Urgent'),
        ('emergency', 'Emergency'),
        ], 'Admission type', required=True, select=True)
    hospitalization_date = fields.DateTime('Hospitalization date',
        required=True, select=True)
    discharge_date = fields.DateTime('Discharge date', required=True,
     select=True)
    attending_physician = fields.Many2One('gnuhealth.physician',
        'Attending Physician',select=True)
    operating_physician = fields.Many2One('gnuhealth.physician',
        'Operating Physician')
    admission_reason = fields.Many2One('gnuhealth.pathology',
        'Reason for Admission', help="Reason for Admission", select=True)
    bed = fields.Many2One('gnuhealth.hospital.bed', 'Hospital Bed',
     required=True, select=True)
    nursing_plan = fields.Text('Nursing Plan')
    discharge_plan = fields.Text('Discharge Plan')

    info = fields.Text('Extra Info')
    state = fields.Selection((
        ('free', 'free'),
        ('cancelled', 'cancelled'),
        ('confirmed', 'confirmed'),
        ('hospitalized', 'hospitalized'),
        ), 'Status', select=True)

# Method to check for availability and make the hospital bed reservation

    def button_registration_confirm(self, ids):
		registration_id = self.browse(ids)[0]
		bed_obj = Pool().get('gnuhealth.hospital.bed')
		cursor = Transaction().cursor
		bed_id = registration_id.bed.id
		cursor.execute("SELECT COUNT(*) \
			FROM gnuhealth_inpatient_registration \
			WHERE (hospitalization_date::timestamp,discharge_date::timestamp) \
				OVERLAPS (timestamp %s, timestamp %s) \
			  AND (state = %s or state = %s) \
			  AND bed = CAST(%s AS INTEGER) ",
			(registration_id.hospitalization_date, registration_id.discharge_date,
			'confirmed','hospitalized', str(bed_id)))

		res = cursor.fetchone()
		
		if res[0] > 0:
			self.raise_user_error('bed_is_not_available')
		else:
			self.write(ids, {'state': 'confirmed'})
			bed_obj.write(registration_id.bed.id, {'state': 'reserved'})

		return True

    def button_patient_discharge(self, ids):
        registration_id = self.browse(ids)[0]
        bed_obj = Pool().get('gnuhealth.hospital.bed')

        self.write(ids, {'state': 'free'})
        bed_obj.write(registration_id.bed.id, {'state': 'free'})
        return True

    def button_registration_cancel(self, ids):
        registration_id = self.browse(ids)[0]
        bed_obj = Pool().get('gnuhealth.hospital.bed')

        self.write(ids, {'state': 'cancelled'})
        bed_obj.write(registration_id.bed.id, {'state': 'free'})
        return True

    def button_registration_admission(self, ids):
        registration_id = self.browse(ids)[0]
        bed_obj = Pool().get('gnuhealth.hospital.bed')
        
        if ( registration_id.hospitalization_date.date() <> datetime.today().date()):
            self.raise_user_error ("The Admission date must be today")
        else:
            self.write(ids, {'state': 'hospitalized'})

            bed_obj.write(registration_id.bed.id, {'state': 'occupied'})
            
        return True

    def create(self, values):
        sequence_obj = Pool().get('ir.sequence')
        config_obj = Pool().get('gnuhealth.sequences')

        values = values.copy()
        if not values.get('name'):
            config = config_obj.browse(1)
            values['name'] = sequence_obj.get_id(
            config.inpatient_registration_sequence.id)

        return super(InpatientRegistration, self).create(values)

    def default_state(self):
        return 'free'


    def __init__(self):
        super(InpatientRegistration, self).__init__()

        self._rpc.update({
            'button_registration_confirm': True,
            'button_patient_discharge': True,
            'button_registration_cancel': True,
            'button_registration_admission': True,
        })

        self._sql_constraints = [
            ('name_uniq', 'unique(name)',
             'The Registration code already exists')
        ]

        self._error_messages.update({
                'bed_is_not_available': 'Bed is not available'})


        self._buttons.update({
                'button_registration_confirm': {
                    'invisible': And(Not(Equal(Eval('state'), 'free')), Not(Equal(Eval('state'), 'cancelled'))),
                    },
                'button_registration_cancel': {
                    'invisible': Not(Equal(Eval('state'), 'confirmed')),
                    },
                'button_patient_discharge': {
                    'invisible': Not(Equal(Eval('state'), 'hospitalized')),
                    },

                'button_registration_admission': {
                    'invisible': Not(Equal(Eval('state'), 'confirmed')),
                    },
                    
                })


InpatientRegistration()


class Appointment(ModelSQL, ModelView):
    'Add Inpatient Registration field to the Appointment model.'
    _name = 'gnuhealth.appointment'
    _description = __doc__

    inpatient_registration_code = fields.Many2One(
        'gnuhealth.inpatient.registration', 'Inpatient Registration',
        help="Enter the patient hospitalization code")

Appointment()


class PatientData(ModelSQL, ModelView):
    'Inherit patient model and add the patient status to the patient.'
    _name = 'gnuhealth.patient'
    _description = __doc__

    def get_patient_status(self, ids, name):
        cursor = Transaction().cursor

        def get_hospitalization_status(patient_dbid):
            cursor.execute('SELECT state ' \
                'FROM gnuhealth_inpatient_registration ' \
                'WHERE patient = %s ' \
                  'AND state = \'hospitalized\' ', (str(patient_dbid),))

            try:
                patient_status = str(cursor.fetchone()[0])
            except:
                patient_status = 'outpatient'

            return patient_status

        result = {}

# Get the patient (DB) id to be used in the search on the medical inpatient
# registration table lookup

        for patient_data in self.browse(ids):
            patient_dbid = patient_data.id

            if patient_dbid:
                result[patient_data.id] = \
                        get_hospitalization_status(patient_dbid)

        return result

    patient_status = fields.Function(fields.Char('Hospitalization Status'),
        'get_patient_status')

PatientData()
