package gov.va.med.esr.messaging.parser;

import java.util.Iterator;
import java.util.Set;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import gov.va.med.esr.common.model.lookup.NameType;
import gov.va.med.esr.common.model.lookup.PhoneType;
import gov.va.med.esr.common.model.lookup.SSNType;
import gov.va.med.esr.common.model.party.Address;
import gov.va.med.esr.common.model.party.Phone;
import gov.va.med.esr.common.model.person.BirthRecord;
import gov.va.med.esr.common.model.person.Name;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.common.model.person.SSN;

/**
 * 
 * @author Rajiv Patnaik Created on Aug 4, 2005
 * @version 1.0
 * 
 * Copyright © 2005 VHA. All rights reserved
 */
public class PIDTestDataValidator extends BaseSegmentsTestDataValidator
        implements XMLSegmentTagNameConstants
{

    /**
     * @param pidNode
     * @param person
     */
    public void validatePID(Document document, Person person)
    {
        NodeList pidNodes = document.getElementsByTagName(PID);

        for (int i = 0; i < pidNodes.getLength(); i++)
        {
            Element element = (Element) pidNodes.item(i);

            String patientId = getElement(element,
                    XMLSegmentTagNameConstants.PID_1);

            //Patient ICN
            String icn = getSubElementData(element, PID_2, CX_1);

            //Patient Name
            validateLegalName(person, element);

            validateDateOfBirth(person, element);
            //Sex
            String gender = getElement(element, PID_8);
            assertEquals("Sex is not equal", gender, person.getGender()
                    .getCode());

            //Patient Address
            validateAddress(person, element);

            validatePhone(person, element);

            validateSSN(person, element);
        }

    }

    /**
     * @param person
     * @param element
     */
    private void validateSSN(Person person, Element element)
    {
        //Legal or PseudoSSN
        String ssnFromMsg = getElement(element, PID_19);
        Set ssns = person.getSsns();
        
        if(ssnFromMsg != null)
        {
            assertNotNull("SSNs from person is null", ssns);
            SSN ssn = null;
            SSN ssnToTest = null;

            for (Iterator iter = ssns.iterator(); iter.hasNext();)
            {
                //Testing legal  only(not the alias ssns).
                ssn = (SSN) iter.next();
                if ((ssn.getType().getCode().equals(SSNType.CODE_ACTIVE.getName()))) 
                {
                    ssnToTest = ssn;
                }
            }
            assertNotNull("SSN is null", ssnToTest);
            assertEquals("SSN text does not match", ssnFromMsg, ssnToTest
                    .getSsnText());

            if (ssnFromMsg.substring(0, 1).equalsIgnoreCase("P"))
            {
                assertEquals("SSN type does not match", SSNType.CODE_PSEUDO
                        .getName(), ssnToTest.getType().getCode());
            } else
            {
                assertEquals("SSN type does not match", SSNType.CODE_ACTIVE
                        .getName(), ssnToTest.getType().getCode());
            }
        }

    }

    /**
     * @param person
     * @param element
     */
    private void validatePhone(Person person, Element element)
    {
        Set phones = person.getPhones();
        Phone homePhone = null;
        Phone businessPhone = null;
        for (Iterator iter = phones.iterator(); iter.hasNext();)
        {
            Phone phone = (Phone) iter.next();

            if (PhoneType.CODE_HOME.getName().equals(phone.getType().getCode()))
            {
                homePhone = phone;
            } else if (PhoneType.CODE_BUSINESS.getName().equals(
                    phone.getType().getCode()))
            {
                businessPhone = phone;
            }
        }

        String homePhoneExpected = getSubElementData(element, PID_13, XTN_1);
        validateNotNull(homePhoneExpected, homePhone, "Home Phone is null");
        if (homePhone != null)
        {
            assertEquals("Home Phone is not equal ", homePhoneExpected,
                    homePhone.getPhoneNumber());
        }

        String businessPhoneExpected = getSubElementData(element, PID_14, XTN_1);
        validateNotNull(businessPhoneExpected, businessPhone,
                "Business Phone is null");
        if (businessPhone != null)
        {
            assertEquals("Business Phone is not equal ", businessPhoneExpected,
                    businessPhone.getPhoneNumber());
        }

    }

    /**
     * @param person
     * @param element
     */
    private void validateAddress(Person person, Element element)
    {
        Address primaryAddress = person.getPermanentAddress();

        String streetNo = getSubElementData(element, PID_11, XAD_1);
        String state = getSubElementData(element, PID_11, XAD_4);
        String zipCode = getSubElementData(element, PID_11, XAD_5);
        String country = getSubElementData(element, PID_11, XAD_6);

        //If any of the above fields is not empty/null, then a Address object
        //should have been built
        validateNotNull(streetNo, primaryAddress, "Primary Address is null");

        //If primaryAddress not built, no assertions
        if (primaryAddress != null)
        {
            assertEquals("StreetR name is not equal ", streetNo, primaryAddress
                    .getLine1());

            assertEquals("State is not equal ", state, primaryAddress
                    .getState());
            if(zipCode != null)
            {
                assertNotNull(primaryAddress.getZipCode());
                assertEquals("Zip Code is not equal ", zipCode.substring(0,5), primaryAddress
                    .getZipCode());
            }

            assertEquals("Country is not equal ", country, primaryAddress
                    .getCountry());
        }
    }

    /**
     * @param person
     * @param element
     */
    private void validateLegalName(Person person, Element element)
    {
        Set names = person.getNames();
        Name legalName = null;
        for (Iterator iter = names.iterator(); iter.hasNext();)
        {
            Name name = (Name) iter.next();
            if (NameType.LEGAL_NAME.getName().equals(name.getType().getCode())) 
            {
                legalName = name;
                break;
            }
        }

        String lastName = getSubElementData(element, PID_5, "xpn.1");
        String firstName = getSubElementData(element, PID_5, XPN_2);
        String middleName = getSubElementData(element, PID_5, XPN_3);
        String suffix = getSubElementData(element, PID_5, XPN_4);
        String prefix = getSubElementData(element, PID_5, XPN_5);

        validateNotNull(lastName, legalName, "Legal Name is null");

        if (legalName != null)
        {
            assertEquals("Last name is not equal ", lastName, legalName
                    .getFamilyName());

            assertEquals("First name is not equal ", firstName, legalName
                    .getGivenName());

            assertEquals("Middle name is not equal ", middleName, legalName
                    .getMiddleName());

            assertEquals("Suffix name is not equal ", suffix, legalName
                    .getSuffix());

            assertEquals("Prefix for name is not equal ", prefix, legalName
                    .getPrefix());
        }
    }

    private void validateDateOfBirth(Person person, Element element)
    {
        String birthDateExpected = getSubElementData(element, PID_7, TS_1);
        BirthRecord birthRecord = person.getBirthRecord();
        validateNotNull(birthDateExpected, birthRecord, "Birth Record is null");
        if (birthRecord != null)
        {
            validateImpreciseDate(birthRecord.getBirthDate(),
                    birthDateExpected, "BirthDate is null ",
                    "BirthDate does not match");
        }
    }

}