<?php

namespace RxConnexionBundle\Service;

use Doctrine\ORM\EntityManager;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;

Class HL7ForAllService {

    private $em;
    private $container;
    public $segments;
    public $messageTypes;

    public function __construct(EntityManager $em, ContainerInterface $container) {
        $this->em = $em;
        $this->container = $container;
        $this->segments = array(
            'DG1', // Diagnosis
            'EVN', // Event Type
            'GT1', // Guarantor
            'IN1', // Insurance
            'MSH', // Message Header
            'MSA', // Message Acknowledgment
            'NK1', // Next of kin/associated parties
            'NTE', // Notes and comments
            'OBR', // Observation request
            'OBX', // Observation result
            'ORC', // Common order
            'PID', // Patient identification
            'FT1', // (for DFT messages) – Financial transaction
        );
        $this->messageTypes = array(
            array('code' => 'ADT-A01', 'type_code' => 'A01',  'label' => 'Patient Admit', 'settings' => array(
                'requiredSegments' => array('MSH', 'EVN', 'PID', 'PV1', 'DG1', 'IN1'), // SEQUENCE MUST BE CORRECT ALSO
                'displayGlobal' => true,
            )),
            array('code' => 'ADT-A02', 'type_code' => 'A02', 'label' => 'Patient Transfer', 'settings' => array(
                'requiredSegments' => array('MSH', 'EVN', 'PID', 'PV1'), // SEQUENCE MUST BE CORRECT ALSO
                'displayGlobal' => true,
            )),
            array('code' => 'ADT-A04', 'type_code' => 'A04', 'label' => 'Patient Registration', 'settings' => array(
                'requiredSegments' => array('MSH', 'EVN', 'PID', 'PV1', 'DG1', 'IN1'), // SEQUENCE MUST BE CORRECT ALSO
                'displayGlobal' => true,
            )),
            array('code' => 'ADT-A05', 'type_code' => 'A05', 'label' => 'Patient Pre-admission', 'settings' => array(
                'requiredSegments' => array('MSH', 'EVN', 'PID', 'PV1', 'DG1', 'IN1'), // SEQUENCE MUST BE CORRECT ALSO
                'displayGlobal' => true,
            )),
            array('code' => 'ADT-A08', 'type_code' => 'A01', 'label' => 'Patient Information Update', 'settings' => array(
                'requiredSegments' => array('MSH', 'EVN', 'PID', 'PV1', 'DG1', 'IN1'), // SEQUENCE MUST BE CORRECT ALSO
                'displayGlobal' => true,
            )),
            array('code' => 'ADT-A11', 'type_code' => 'A11', 'label' => 'Cancel Patient Admit', 'settings' => array(
                'requiredSegments' => array('MSH', 'EVN', 'PID', 'PV1'), // SEQUENCE MUST BE CORRECT ALSO
                'displayGlobal' => true,
            )),
            array('code' => 'ADT-A12', 'type_code' => 'A12', 'label' => 'Cancel Patient Transfer', 'settings' => array(
                'requiredSegments' => array('MSH', 'EVN', 'PID', 'PV1'), // SEQUENCE MUST BE CORRECT ALSO
                'displayGlobal' => true,
            )),
            array('code' => 'ADT-A13', 'type_code' => 'A13', 'label' => 'Cancel Patient Discharge', 'settings' => array(
                'requiredSegments' => array('MSH', 'EVN', 'PID', 'PV1', 'DG1', 'IN1'), // SEQUENCE MUST BE CORRECT ALSO
                'displayGlobal' => true,
            )),
            /*array('code' => 'BAR-P01', 'type_code' => 'P01', 'label' => 'Add Billing Account', 'settings' => array(
                'requiredSegments' => array('MSH', 'EVN', 'PID', 'PV1'), // SEQUENCE MUST BE CORRECT ALSO
                'displayGlobal' => true,
            )),*/
            /*array('code' => 'BAR-P02', 'type_code' => 'P02', 'label' => 'Purge Billing Account', 'settings' => array(
                'requiredSegments' => array('MSH', 'EVN', 'PID', 'PV1'), // SEQUENCE MUST BE CORRECT ALSO
                'displayGlobal' => true,
            )),
            array('code' => 'BAR-P05', 'type_code' => 'P05', 'label' => 'Update Billing Account', 'settings' => array(
                'requiredSegments' => array('MSH', 'EVN', 'PID', 'PV1'), // SEQUENCE MUST BE CORRECT ALSO
                'displayGlobal' => true,
            )),
            array('code' => 'DFT-P03', 'type_code' => 'P03', 'label' => 'Detail Financial Transaction', 'settings' => array(
                'requiredSegments' => array('MSH', 'EVN', 'PID', 'PV1', 'FT1'), // SEQUENCE MUST BE CORRECT ALSO
                'displayGlobal' => false,
            )),
            array('code' => 'MDM-T01', 'type_code' => 'T01', 'label' => 'Medical document management', 'settings' => array(
                'requiredSegments' => array('MSH', 'EVN', 'PID', 'PV1', 'TXA'), // SEQUENCE MUST BE CORRECT ALSO
                'displayGlobal' => false,
            )),*/
            /*array('code' => 'ORM-O01', 'type_code' => 'O01', 'label' => 'Order (Pharmacy/treatment)', 'settings' => array(
                'requiredSegments' => array('MSH', 'PID', 'ORC'), // SEQUENCE MUST BE CORRECT ALSO
            )),
            array('code' => 'ACK', 'label' => 'General Acknowledgement'),*/
            /*'BAR', // Add/change billing account
            'DFT', // Detailed financial transaction
            'MDM', // Medical document management
            'MFN', // Master files notification
            'ORM', // Order (Pharmacy/treatment)
            'ORU', // Observation result (unsolicited)
            'QRY', // Query, original mode
            'RAS', // Pharmacy/treatment administration
            'RDE', // Pharmacy/treatment encoded order
            'RGV', // Pharmacy/treatment give
            'SIU', // Scheduling information unsolicited*/
        );
    }

    public function generate($typeCode, $patient, $params){
        $messageType = $this->message_type_by_type_code($typeCode);
        $segments = $this->generate_patient_segment($messageType, $patient, $params);
        return array('success' => true, 'data' => implode("\r\n", $segments));
    }

    private function message_type_by_type_code($typeCode) {
        foreach ($this->messageTypes as $messageType) {
            if ($messageType['code'] == $typeCode) {
                return $messageType;
            }
        }
        return null;
    }

    private function generate_patient_segment($messageType, $patient, $params){
        $requiredSegments = $messageType['settings']['requiredSegments'];

        $segmetDetails = array();
        foreach($requiredSegments as $segment){
            $functionName = preg_replace("/[\- _]/", '_', $segment);
            $segmetDetails[] = $this->$functionName($messageType, $patient, $params);
        }

        return $segmetDetails;
    }




    /*--------------------------------------------------------------------------------------------------------*/
    /*				           	SEGMENT GENERATOR   						    						       */
    /*--------------------------------------------------------------------------------------------------------*/

    private function MSH($messageType,$patient, $params){
        $msh_sendingApplication = array(
            'RXCON', // namespace identification ex. company name
            '', // universal identification
            '', // universal identification type
        );
        $msh_sendingFacility = array(
            '', // namespace identification
            '', // universal identification
            '', // universal identification type
        );
        $msh_receivingApplication = array(
            '', // namespace identification
            '', // universal identification
            '', // universal identification type
        );
        $msh_receivingFacility = array(
            '', // namespace identification
            '', // universal identification
            '', // universal identification type
        );
        $msh_dateTime = date('YmdHis');
        $security = '';
        $msh_messageType = array(
            preg_replace("/[\- _]/", '^', $messageType['code']), // message code ex. ACK for acknowledgment
            '', // trigger event
            '', // message structure
        );
        $msh_messageControlId = 'RXCON'.time();
        $msh_processingId = array(
            'P', // processing id ex. D-debuggin, P-production, T-training
            '', // processing mode ex. A-Archive, I-initial load, Not present-current processing, R-Restore from archive, T-scheduled/currenty processing
        );
        $msh_versionId = '2.7.1'; // 2.7.1 is the latest in hl7 version 2.x
        $msh = implode('|', array(
            'MSH',
            '^~\&',
            implode('^', array_filter($msh_sendingApplication)),
            implode('^', array_filter($msh_sendingFacility)),
            implode('^', array_filter($msh_receivingApplication)),
            implode('^', array_filter($msh_receivingFacility)),
            $msh_dateTime,
            $security,
            implode('^', array_filter($msh_messageType)),
            $msh_messageControlId,
            implode('^', array_filter($msh_processingId)),
            $msh_versionId,
        )); // produces something like this "MSH|^~\&|rxconnexion||||20190606131820||ACK|47L9Mc9K7wbRAUs19qf9GTeM|P|2.7.1";
        return $msh;
    }

    private function EVN($messageType, $patient, $params){
        return implode('|', array(
            'EVN',
            $messageType['type_code'],
            date('YmdHis')
        ));
    }

    private function MSA($messageType, $patient, $params){
        $msa_acknowledgementCode = 'AA'; // ex. AA-Application Accept, AE-Application Error, AR-Application Reject, CA-Commit Accept, CE-Commit Error, CR-Commit Reject
        $msa_messageControlId = 'RXCON'.time();
        $msa_textMessage = 'Sample Acknowledgment'; //  your message (optional)
        $msa = implode('|', array(
            'MSA',
            $msa_acknowledgementCode,
            $msa_messageControlId,
            $msa_textMessage,
        ));
        return $msa;
    }

    private function PID($messageType, $patient, $params){
        return implode('|', array(
            'PID',
            '', // SET ID
            $patient['id'], // Patient ID
            implode('^', array(
                $patient['albertaHealthCardNo'] == '' ? 'null' : $patient['albertaHealthCardNo'], // health card number
                '', // identifier check digit
                '', // check digit scheme
                '', // assigning auth
                'HC', // identifier code (type) HC = Health Card
            )), // Patient identifier
            '', // Alternate Patient Id
            implode('^', array(
                $patient['lastName'], // last name
                $patient['firstName'], // first name
                $patient['middleName'], // middle name
            )), // Patient Name
            '', // mothers maiden name
            $patient['birthDate'], // date of birth
            $patient['gender'] == 'Male' ? 'M' : 'F', // gender
            '', // patient alias
            '', // race
            implode('^', array(
                implode('&', array(
                    $patient['street'], // street
                )), // street address
                '', // other designation
                $patient['city'], // city
                '', // province
                $patient['postalCode'], // zip code
            )), // patient address
        ));
    }

    private function PV1($messageType, $patient, $params){
        $referringProviders = array();
        $patientReferringProviders = explode('~', $patient['patientReferringProviderDetails']);
        $i = 0;
        foreach($patientReferringProviders as $patientReferringProvider){
            $referringProviderDetails = explode('|', $patientReferringProvider);
            $i++;
            $referringProviders[] = implode('^', array(
                $referringProviderDetails[0], // set id
                isset($referringProviderDetails[1]) ? $referringProviderDetails[1] : '', // Last name
                isset($referringProviderDetails[2]) ? $referringProviderDetails[2] : '', // First name
                isset($referringProviderDetails[3]) ? $referringProviderDetails[3] : '', // Middle name
            ));
        }
        return implode('|', array(
            'PV1',
            '', // set id
            'I', // patient identifier I=in patient,
            '', // assigned patient location (floor/room in hospital)
            '', // Admission type A=accident, C=elective, E=emergency etc.
            '', // Pre admit number
            '', // Prior patient location
            '', // attending doctor
            implode('~', $referringProviders), // referring doctor
            '', // consulting doctor
            'MED', // Hospital service CAR=cardiac service, MED=medical service, PUL=pulmonary, SUR=surgical, URO=urology service
        ));
    }

    private function DG1($messageType, $patient, $params){
        $dg1 = array();
        $patientDiagnosiss = explode('~', $patient['diagnosesDetails']);
        $i = 0;
        foreach($patientDiagnosiss as $patientDiagnosis){
            $i++;
            $dg1[] = implode('|', array(
                'DG1',
                $i, // set id
                '', // Diagnosis coding method
                'null', // Diagnosis code
                isset($patientDiagnosis[0]) ? $patientDiagnosis[0] : '', // diagnosis desc
                '', // Diagnosis date time
                'F', // Diagnosis type A=admitting, F=final, W=working
            ));
        }
        return join("\r\n", $dg1);
    }

    private function IN1($messageType, $patient, $params){
        $in1 = array();
        $patientInsurances = explode('~', $patient['insurancesDetails']);
        $i = 0;
        foreach($patientInsurances as $patientInsurance){
            $insuranceDetails = explode('|', $patientInsurance);
            $i++;
            $in1[] = implode('|', array(
                'IN1',
                $i, // set id
                'null', // Insurance plan id
                implode('^', array(
                    isset($insuranceDetails[0]) ? $insuranceDetails[0] : '', // ID
                    '', // Check Digit
                    '', // Code identifying
                    '', // Assigning auth
                    'U', // identifier type U=unspecified identifer
                    '', // Assigning facility
                    isset($insuranceDetails[1]) ? $insuranceDetails[1] : '', // Effective date
                    isset($insuranceDetails[2]) ? $insuranceDetails[2] : '', // Expiration date
                )), // Insurance company id
                isset($insuranceDetails[3]) ? $insuranceDetails[3] :'', // Insurance company name
            ));
        }
        return join("\r\n", $in1);
    }

}