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.fw.service.ServiceException;
import gov.va.med.fw.util.builder.BuilderException;

import gov.va.med.esr.common.model.ee.AgentOrangeExposure;
import gov.va.med.esr.common.model.ee.EligibilityVerification;
import gov.va.med.esr.common.model.ee.EnvironmentalContaminationExposure;
import gov.va.med.esr.common.model.ee.MilitaryService;
import gov.va.med.esr.common.model.ee.MilitarySexualTrauma;
import gov.va.med.esr.common.model.ee.MonetaryBenefit;
import gov.va.med.esr.common.model.ee.MonetaryBenefitAward;
import gov.va.med.esr.common.model.ee.RadiationExposure;
import gov.va.med.esr.common.model.ee.ReceivedEligibility;
import gov.va.med.esr.common.model.ee.SpecialFactor;
import gov.va.med.esr.common.model.lookup.MonetaryBenefitType;
import gov.va.med.esr.common.model.lookup.VAFacility;
import gov.va.med.esr.common.model.person.Person;
import gov.va.med.esr.messaging.builder.message.DateFormatter;
import gov.va.med.esr.service.PersonHelperService;

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

    public void validateZEL(Document document, Person person,
            PersonHelperService personHelperService) throws BuilderException,
            ServiceException
    {
        NodeList zelNodes = document.getElementsByTagName(ZEL);

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

            //SEQUENTIAL NUMBER (1 is always primary eligibility).Validate only
            // that for now..
            //Secondary Eligibilities, validate Seq 2(ELIGIBILITY) only
            String setId = getElement(element, ZEL_1);

            if ("1".equals(setId))
            {
                //ELIGIBILITY CODE
                validateEligibilityCode(person, element);

                //Validate disabilityRetirementStatus(Seq5),
                //dischargeDueToDisability(Seq 39)
                validateDisabilityRetirement(person, element);

                //CLAIM FOLDER NUMBER//Location
                validateClaimFolderLocationAndFolder(person, element);

                //VETERAN?
                validateIsVeteran(person, element);

                //ELIGIBLITY STATUS,Eligibility Status Date,ELIGIBILITY
                // VERIFICATION METHOD
                validateEligibilityStatus(person, element);

                //A&A BENEFITS,HOUSEBOUND BENEFITS,VA PENSION,VA DISABILITY
                validateMonetaryBenefits(person, element);

                //EXP TO AGENT ORANGE,RADIATION EXP INDICATED,ENV CONTAM
                // INANTS,
                //RADIATION EXPOSURE METHOD
                validateSpecialFactors(person, element);

                //MstStatus, MstStatusChangeDate, and MstStatusDeterminingSite
                validateMilitarySexualTrauma(person, element,
                        personHelperService);

            }
        }
    }

    /**
     * @param person
     * @param element
     */
    private void validateEligibilityCode(Person person, Element element)
    {
        String eligbltyCodeFromMsg = getElement(element, ZEL_2);
        ReceivedEligibility receivedEligibility = person
                .getReceivedPrimaryEligibility();

        validateNotNull(eligbltyCodeFromMsg, receivedEligibility,
                "ReceivedEligibility is null");

        if (receivedEligibility != null)
        {

            assertNotNull("ReceivedEligibility Type is null",
                    receivedEligibility.getType());
            assertEquals("Eligibility Code does not match",
                    eligbltyCodeFromMsg, receivedEligibility.getType()
                            .getCode());
        }
    }

    /**
     * Validate disabilityRetirementStatus(Seq5), dischargeDueToDisability(Seq
     * 39)
     * 
     * @param person
     * @param element
     */
    private void validateDisabilityRetirement(Person person, Element element)
    {
        // Disability Retirement
        String disabilityRetirementStatus = getElement(element, ZEL_5);
        String dischargeDueToDisability = getElement(element, ZEL_39);

        MilitaryService militaryService = person.getMilitaryService();
        validateNotNull(disabilityRetirementStatus, militaryService,
                "MilitaryService is null");
        if (disabilityRetirementStatus != null)
        {
            assertNotNull("MilitaryService is null", militaryService);
            assertEquals("DisabilityRetirementIndicator does not match",
                    buildBoolean(disabilityRetirementStatus), militaryService
                            .getDisabilityRetirementIndicator());
        }

        if (dischargeDueToDisability != null)
        {
            assertNotNull("MilitaryService is null", militaryService);
            assertEquals("DischargeDueToDisability does not match",
                    buildBoolean(disabilityRetirementStatus), militaryService
                            .getDischargeDueToDisability());
        }

    }

    /**
     * @param person
     * @param element
     */
    private void validateClaimFolderLocationAndFolder(Person person,
            Element element)
    {
        /*
         * TODO  ONce Beneficary BOM is working String claimFolderNumberFromMsg =
         * getElement(element, ZEL_6); assertEquals("ClaimFolderNumber does not
         * match ", claimFolderNumberFromMsg, person.getClaimFolderNumber());
         * 
         * String claimFolderLocationFromMsg = getElement(element, ZEL_7);
         * VAFacility claimFolderLocation = person.getClaimFolderLocation();
         * validateNotNull(claimFolderLocationFromMsg, claimFolderLocation,
         * "ClaimFolderLocation in Person is null"); if (claimFolderLocation !=
         * null) { assertEquals("ClaimFolderLocation code does not match",
         * claimFolderLocationFromMsg, claimFolderLocation .getStationNumber()); }
         */
    }

    /**
     * @param person
     * @param element
     * @throws BuilderException
     * @throws ServiceException
     */
    private void validateIsVeteran(Person person, Element element)
            throws BuilderException
    {
        String isVeteranFromMsg = getElement(element, ZEL_8);

        if (isVeteranFromMsg != null)
        {
            assertNotNull("Is Veteran is null in Person", person.isVeteran());
            assertEquals("Is Veteran does not match",
                    buildBoolean(isVeteranFromMsg), person.isVeteran());
        } else
        {
            assertNotNull("Is Veteran should be null in Person", person
                    .isVeteran());
        }
    }

    /**
     * @param person
     * @param element
     */
    private void validateEligibilityStatus(Person person, Element element)
    {
        String eligbltyStatusCodeFromMsg = getElement(element, ZEL_10);
        String eligbltyStatusDateFromMsg = getElement(element, ZEL_11);
        String eligbltyVerftnCodeFromMsg = getElement(element, ZEL_13);

        EligibilityVerification eligbltyVerifctn = person
                .getEligibilityVerification();
        validateNotNull(eligbltyStatusCodeFromMsg, eligbltyVerifctn,
                "EligibilityVerification is null");

        if (eligbltyVerifctn != null)
        {
            assertNotNull("EligibilityVerificationStatus is null",
                    eligbltyVerifctn.getEligibilityStatus());
            assertEquals("Eligibiliy Status Date does not match",
                    eligbltyStatusCodeFromMsg, eligbltyVerifctn
                            .getEligibilityStatus().getCode());

            assertEquals("EligibilityStatusDate does not match",
                    eligbltyStatusDateFromMsg, DateFormatter
                            .formatDate(eligbltyVerifctn
                                    .getEligibilityStatusDate()));

            assertEquals("VerificationMethod Code does not match",
                    eligbltyVerftnCodeFromMsg, eligbltyVerifctn
                            .getVerificationMethod());

        }
    }

    private void validateMonetaryBenefits(Person person, Element element)
    {
        String receivingAABenefitsFromMsg = getElement(element, ZEL_14);
        String receivingHouseholdBenefitsFromMsg = getElement(element, ZEL_15);
        String receivingVaPensionFromMsg = getElement(element, ZEL_16);
        String receivingVaDisabilityFromMsg = getElement(element, ZEL_17);

        MonetaryBenefitAward mbAward = person.getMonetaryBenefitAward();
        //If any one of the benefits above is not null, then
        // MonetaryBenefitAward should not be null
        if (receivingAABenefitsFromMsg != null
                || receivingHouseholdBenefitsFromMsg != null
                || receivingVaPensionFromMsg != null
                || receivingVaDisabilityFromMsg != null)
        {
            assertNotNull("MonetaryBenefitAward is null", mbAward);
        }

        String receivingAABenefits = null;
        String receivingHouseboundBenefits = null;
        String receivingVaPension = null;
        String receivingVaDisability = null;

        if (mbAward != null)
        {

            Set monetaryBenefits = mbAward.getMonetaryBenefits();
            assertNotNull("MonetaryBenefits is null", monetaryBenefits);

            Iterator iterMonetaryBenefits = monetaryBenefits.iterator();
            while (iterMonetaryBenefits.hasNext())
            {
                MonetaryBenefit theMB = (MonetaryBenefit) iterMonetaryBenefits
                        .next();

                if ((theMB != null) && (theMB.getType() != null))
                {
                    if (MonetaryBenefitType.CODE_AID_AND_ATTENDANCE.getName()
                            .equals(theMB.getType().getCode()))
                    {
                        receivingAABenefits = "1";
                    } else if (MonetaryBenefitType.CODE_HOUSEBOUND.getName()
                            .equals(theMB.getType().getCode()))
                    {
                        receivingHouseboundBenefits = "1";
                    } else if (MonetaryBenefitType.CODE_VA_PENSION.getName()
                            .equals(theMB.getType().getCode()))
                    {
                        receivingVaPension = "1";
                    } else if (MonetaryBenefitType.CODE_DISABILITY_COMPENSATION
                            .getName().equals(theMB.getType().getCode()))
                    {
                        receivingVaDisability = "1";
                    }
                }
            }
            assertMonetaryBenefit("receivingAABenefits does not match",
                    receivingAABenefitsFromMsg, receivingAABenefits);
            assertMonetaryBenefit("receivingHouseboundBenefits does not match",
                    receivingHouseholdBenefitsFromMsg,
                    receivingHouseboundBenefits);
            assertMonetaryBenefit("receivingVaPension does not match",
                    receivingVaPensionFromMsg, receivingVaPension);

        }

    }

    /**
     * A MonetaryBenefit is present in the MonetaryBenefitAward only if the
     * indicator in the message is true i.e "1". If it is "0", the
     * MonetaryBenefit does not get added
     * 
     * @param string
     * @param receivingAABenefitsFromMsg
     * @param receivingAABenefits
     */
    private void assertMonetaryBenefit(String failureMessage,
            String receivingBenefitFromMsg, String receivingBenefit)
    {
        if ("0".equals(receivingBenefitFromMsg))
        {
            assertNull(failureMessage, null);

        } else if ("1".equals(receivingBenefitFromMsg))
        {
            assertEquals(failureMessage, receivingBenefitFromMsg,
                    receivingBenefit);
        }

    }

    private void validateSpecialFactors(Person person, Element element)
    {
        String agentOrangeIndFromMsg = getElement(element, ZEL_18);
        String radiationExpIndFromMsg = getElement(element, ZEL_19);
        String envContaminantsIndFromMsg = getElement(element, ZEL_19);
        String radiationExpMethodFromMsg = getElement(element, ZEL_22);

        Set specialFactors = person.getSpecialFactors();
        //If any one of the factors above is not null, then
        // specialFactors should not be null
        if (agentOrangeIndFromMsg != null || radiationExpIndFromMsg != null
                || envContaminantsIndFromMsg != null)
        {
            assertNotNull("specialFactors is null", specialFactors);
        }

        String agentOrangeInd = null;
        String radiationExpInd = null;
        String envContaminantsInd = null;
        String radiationExpMethod = null;

        if (specialFactors != null)
        {
            AgentOrangeExposure agentOrange = null;
            RadiationExposure radiation = null;
            EnvironmentalContaminationExposure envCont = null;

            Iterator iterSpecialFactors = specialFactors.iterator();
            while (iterSpecialFactors.hasNext())
            {
                SpecialFactor theSpecialFactor = (SpecialFactor) iterSpecialFactors
                        .next();

                if (theSpecialFactor != null)
                {
                    if (theSpecialFactor instanceof AgentOrangeExposure)
                    {
                        agentOrange = (AgentOrangeExposure) theSpecialFactor;
                    } else if (theSpecialFactor instanceof RadiationExposure)
                    {
                        radiation = (RadiationExposure) theSpecialFactor;
                    } else if (theSpecialFactor instanceof EnvironmentalContaminationExposure)
                    {
                        envCont = (EnvironmentalContaminationExposure) theSpecialFactor;
                    }
                }
            }

            if (agentOrange != null)
            {
                agentOrangeInd = "1";
            }

            if (radiation != null)
            {
                radiationExpInd = "1";
                radiationExpMethod = radiation.getExposureMethod().getCode();
            }

            if (envCont != null)
            {
                envContaminantsInd = "1";
            }
            /*
            assertEquals("agentOrangeInd does not match",
                    agentOrangeIndFromMsg, agentOrangeInd);
            assertEquals("radiationExpInd does not match",
                    radiationExpIndFromMsg, radiationExpInd);
            assertEquals("envContaminantsInd does not match",
                    envContaminantsIndFromMsg, envContaminantsInd);
            assertEquals("radiationExpMethod does not match",
                    radiationExpMethodFromMsg, radiationExpMethod);*/
        }
    }

    private void validateMilitarySexualTrauma(Person person, Element element,
            PersonHelperService personHelperService)
    {
        String mstStatusFromMsg = getElement(element, ZEL_23);
        String mstStatusChangeDateFromMsg = getSubElementData(element, ZEL_24,
                TS_1);
        String mstStatusSiteFromMsg = getElement(element, ZEL_25);

        String mstStatus = null;
        String mstStatusChangeDate = null;
        String mstStatusSite = null;

        //Get MilitarySexualTrauma object
        MilitarySexualTrauma mst = (MilitarySexualTrauma) personHelperService
                .getClinicalDetermination(MilitarySexualTrauma.class, person);

        validateNotNull(mstStatusFromMsg, mst, "MilitarySexualTrauma is null");
        validateNotNull(mstStatusChangeDateFromMsg, mst,
                "MilitarySexualTrauma is null");
        validateNotNull(mstStatusSiteFromMsg, mst,
                "MilitarySexualTrauma is null");

        if (mst != null)
        {
            mstStatus = (mst.getStatus() != null) ? mst.getStatus().getCode()
                    : null;
            mstStatusChangeDate = DateFormatter.formatDate(mst
                    .getStatusChangeDate());
            mstStatusSite = (mst.getDeterminationFacility() != null) ? mst
                    .getDeterminationFacility().getStationNumber() : null;
        }

        assertEquals("mstStatus does not match", mstStatusFromMsg, mstStatus);
        assertEquals("mstStatusChangeDate does not match",
                mstStatusChangeDateFromMsg.substring(0, 8), mstStatusChangeDate);
        assertEquals("mstStatusSite does not match", mstStatusSiteFromMsg,
                mstStatusSite);
    }

}