/*****************************************************************************************
 * Copyright © 2004 VHA. All rights reserved
 ****************************************************************************************/
// Package
package gov.va.med.esr.common.report.data.impl;

//Java classes
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

// Library classes
import org.hibernate.Query;
import org.hibernate.Session;

// framework classes
import gov.va.med.fw.report.ReportConfiguration;
import gov.va.med.fw.report.data.QueryCriteria;
import gov.va.med.fw.report.data.ReportDataException;
import gov.va.med.fw.util.StringUtils;

// ESR classes
import gov.va.med.esr.common.model.lookup.ReportFacilityDisplayBy;
import gov.va.med.esr.common.model.lookup.VAFacility;
import gov.va.med.esr.common.model.lookup.VISN;
import gov.va.med.esr.common.model.report.ReportFacility;
import gov.va.med.esr.common.model.report.ReportParameterSet;
import gov.va.med.esr.common.model.report.ReportSetup;
import gov.va.med.esr.common.report.data.CommonCriteria;
import gov.va.med.esr.common.report.data.StandardReportCriteria;
import gov.va.med.esr.service.UnknownLookupTypeException;

/**
 * Provides methods to build a HQL statemenets for retrieving report data. This
 * interface is intented to retrieve report data for all ESR standard reports
 * related to Finacials Signed Application Report.
 */
public class SignedApplicationReportDataDAOImpl extends
		AbstractStandardReportDataDAOImpl {
	/**
	 * An instance of serialVersionUID
	 */
	private static final long serialVersionUID = 3913277504975056202L;

	private static final String PARAM_VALUE_ALL = "all";

	private static final String PARAM_VALUE_VISN = "visn";

	private static final String PARAM_VALUE_SITE = "site";

	private static final String PARAM_VALUE_NONE = "none";

	/**
	 * A default constructor
	 */
	public SignedApplicationReportDataDAOImpl() {
		super();
	}

	/**
	 * @see gov.va.med.esr.common.report.data.impl.AbstractStandardReportDataDAOImpl#preDataRetrieval(gov.va.med.fw.report.ReportConfiguration)
	 */
public void preDataRetrieval(ReportConfiguration config)
			throws ReportDataException {
		super.preDataRetrieval(config);
		QueryCriteria reportCriteria = config.getQueryCriteria();

		try {
			if (reportCriteria instanceof StandardReportCriteria) {
				StandardReportCriteria criteria = (StandardReportCriteria) reportCriteria;
				ReportSetup setup = criteria.getReportSetup();
				ReportParameterSet parameters = setup != null ? setup
						.getParameterSet() : null;
				if (parameters == null) {
					throw new ReportDataException(
							"Missing report parameters in report "
									+ config.getReportID());
				}

				criteria.setStartDate(this.getDate(config, true));
				criteria.setEndDate(this.getDate(config, false));
				criteria.setIncomeYear(criteria.getReportSetup()
						.getParameterSet().getBeginIncomeYear());
				criteria.setEndIncomeYear(criteria.getReportSetup().getParameterSet().getEndIncomeYear());

				String visnNames = "";
				String facilityNames = "";

				ReportFacilityDisplayBy facilityDisplayBy = parameters
						.getFacilityDisplayBy();
				if (facilityDisplayBy == null
						|| StringUtils.isEmpty(facilityDisplayBy.getCode())) {
					visnNames = "ALL";
					facilityNames = "ALL";
				} 
				else {
					// When 1 or more VISNs selected
					if (StringUtils.equals(facilityDisplayBy.getCode(),
							ReportFacilityDisplayBy.CODE_VISN.getCode())) {
						Set visns = parameters.getFacilities();
						if (visns != null && !visns.isEmpty()) {
							Collection allVisns = this.lookupService
									.findAll(VISN.class);
							if (allVisns.size() == visns.size()) {
								visnNames = "ALL";
								facilityNames = "ALL";
							} else {
								ArrayList visnVistaNameList = this.getVistaNameList(parameters.getFacilities());
								String visnVistaNames = this.getItemsAsString(visnVistaNameList);
								visnNames = visnVistaNames;
								facilityNames = "ALL";
							}
						}
					} else { // When 0, more or all facilities selected
						Set reportFacilities = parameters.getFacilities();
						if (reportFacilities == null
								|| reportFacilities.isEmpty()) {
							visnNames = "ALL";
							facilityNames = "ALL";
						} else {
							StringBuffer visnVistaNamesSB = new StringBuffer();
							StringBuffer facilityStationNamesSB = new StringBuffer();
							this.getVisnAndFacilityNames(reportFacilities, visnVistaNamesSB, facilityStationNamesSB);
							visnNames = visnVistaNamesSB.toString();
							facilityNames = facilityStationNamesSB.toString();
						}
					}
				}
				criteria.addCriterion(CommonCriteria.VISNS, visnNames);
				criteria.addCriterion(CommonCriteria.FACILITIES, facilityNames);

			}
		} 
		catch (UnknownLookupTypeException e) {
			throw new ReportDataException(e);
		}
		catch (ClassNotFoundException e) {
			throw new ReportDataException(e);
		}

	}
	/**
	 * @see gov.va.med.esr.common.report.data.impl.AbstractStandardReportDataDAOImpl#buildQuery(gov.va.med.fw.report.ReportConfiguration)
	 */
	protected Query buildQuery(ReportConfiguration config, Session session)
			throws ReportDataException {
		QueryCriteria reportCriteria = config.getQueryCriteria();
		Query query = null;

		if (reportCriteria instanceof StandardReportCriteria) {

			// Get a named query
			query = this.getNamedQuery(session);

			// Get a criteria
			StandardReportCriteria criteria = (StandardReportCriteria) reportCriteria;
			ReportSetup setup = criteria.getReportSetup();
			ReportParameterSet parameters = setup != null ? setup
					.getParameterSet() : null;
			if (parameters == null) {
				throw new ReportDataException(
						"Missing report parameters in report "
								+ config.getReportID());
			}

			Integer incomeYear = parameters.getBeginIncomeYear();
			if (incomeYear == null) {
				throw new ReportDataException("Missing Income year in report "
						+ config.getReportID());
			}

			query.setInteger(CommonCriteria.INCOME_YEAR, parameters
					.getBeginIncomeYear().intValue());
			
			if(parameters.getEndIncomeYear()!=null)
			{
				query.setInteger(CommonCriteria.END_INCOME_YEAR, parameters
						.getEndIncomeYear().intValue());	
			}else{
				query.setInteger(CommonCriteria.END_INCOME_YEAR, 0);
			}			
			query.setDate(CommonCriteria.START_DATE, parameters.getFromDate());
			query.setDate(CommonCriteria.END_DATE, parameters.getToDate());
			// set default parameters values
			query.setString(CommonCriteria.QUERY_TYPE, null);
			query.setString(CommonCriteria.IS_ALL, null);
			query.setParameterList(CommonCriteria.FACILITIES, getDefaultList());
			query.setParameterList(CommonCriteria.VISNS, getDefaultList());

            //Queries always contain the NOVISN parameter. set it in all the cases
			ReportFacilityDisplayBy facilityDisplayBy = parameters
					.getFacilityDisplayBy();
			if (facilityDisplayBy == null
					|| StringUtils.isEmpty(facilityDisplayBy.getCode())) {
				// No additional parameters are required to be passed
				query.setString(CommonCriteria.QUERY_TYPE, PARAM_VALUE_NONE);
                query.setString(CommonCriteria.IS_NO_VISN,CommonCriteria.IS_NO_VISN);
			} else {
				// When 1 or more VISNs selected
				if (StringUtils.equals(facilityDisplayBy.getCode(),
						ReportFacilityDisplayBy.CODE_VISN.getCode())) {
					query.setString(CommonCriteria.QUERY_TYPE,PARAM_VALUE_VISN);
					List visns = this.getFacilitityIds(parameters
							.getFacilities());
					if (visns != null && !visns.isEmpty()) {
						query.setParameterList(CommonCriteria.VISNS, visns.toArray());
					}
                    //case where novisn is selected (could be no visn)
                    else {
                        List facilities = new ArrayList();
                        facilities.add(new Integer(0));
                        query.setParameterList( CommonCriteria.VISNS, facilities);
                    }
                    //NOVISN is selected
                    if (parameters.isNoVISNPresent()){
                        query.setString(CommonCriteria.IS_NO_VISN,CommonCriteria.IS_NO_VISN);
                    }
                    else {
                        query.setString(CommonCriteria.IS_NO_VISN,"VISN");
                    }                    
					// When 0, more or all facilities selected
				} else {
					query.setString(CommonCriteria.QUERY_TYPE,PARAM_VALUE_SITE);
                    query.setString(CommonCriteria.IS_NO_VISN,CommonCriteria.IS_NO_VISN);
					Set reportFacilities = parameters.getFacilities();
					if (reportFacilities == null || reportFacilities.isEmpty()) {
						query.setString(CommonCriteria.IS_ALL, PARAM_VALUE_ALL);
					} else {
						query.setParameterList(CommonCriteria.FACILITIES, this
								.getFacilitityIds(reportFacilities));
					}
				}
			}
		}
		return query;
	}

	private List getDefaultList() {
		List facilities = new ArrayList();
		facilities.add(new Integer(0));
		return facilities;
	}

	private List getFacilitityIds(Set facilities) {
		Iterator i = facilities != null ? facilities.iterator() : null;
		ArrayList list = new ArrayList();
		while (i != null && i.hasNext()) {
			ReportFacility rFacility = (ReportFacility) i.next();
			if (rFacility != null && rFacility.getLookup() != null) {
				list.add(rFacility.getFacility().getIdentifier());
			}
		}
		return list;
	}

	private void getVisnAndFacilityNames(Set facilities,
			StringBuffer visnVistaNamesSB, StringBuffer facilityStationNamesSB)
			throws UnknownLookupTypeException, ClassNotFoundException {
		Iterator i = facilities != null ? facilities.iterator() : null;
		HashMap selectedVisnFacilityMap = new HashMap();
		while (i != null && i.hasNext()) {
			ReportFacility rFacility = (ReportFacility) i.next();
			if (rFacility != null && rFacility.getLookup() != null) {
				VAFacility vaFacility = rFacility.getFacility();
				BigDecimal visnId = vaFacility.getVisnId();
				if (visnId != null) {
					ArrayList visnfacilityList = (ArrayList) selectedVisnFacilityMap
							.get(visnId);
					if (visnfacilityList == null) {
						visnfacilityList = new ArrayList();
						selectedVisnFacilityMap
								.put(visnId, visnfacilityList);
					}
					visnfacilityList.add(vaFacility);
				}

			}
		}

		ArrayList selectedVisnVistaNames = new ArrayList();
		ArrayList selectedfacilityStationnames = new ArrayList();
		boolean allStations = true;
		Map visnFacilityMap = this.lookupService.getVISNSiteMap();
		Iterator visnMapIterator = visnFacilityMap.entrySet().iterator();
		while (visnMapIterator.hasNext()) {
			Map.Entry mapEntry = (Map.Entry) visnMapIterator.next();
			VISN visn = (VISN) mapEntry.getKey();
			Collection visnFacilities = (Collection) mapEntry.getValue();

			Collection selectedVisnFacilities = (Collection) selectedVisnFacilityMap
					.get(visn.getIdentifier());
			if (selectedVisnFacilities != null) {
				int selectedVisnFacilitiesSize = (selectedVisnFacilities != null) ? selectedVisnFacilities
						.size()
						: 0;
				int visnFacililitiesSize = (visnFacilities != null) ? visnFacilities
						.size()
						: 0;

				selectedVisnVistaNames.add(visn.getDescription());
				if (selectedVisnFacilitiesSize != visnFacililitiesSize) {
					allStations = false;
				}
			}
		}

		if (allStations == false) {
			selectedfacilityStationnames = getStationNameList(facilities);
			facilityStationNamesSB.append(this
					.getItemsAsString(selectedfacilityStationnames));
		} else {
			facilityStationNamesSB.append("ALL");
		}

		visnVistaNamesSB.append(getItemsAsString(selectedVisnVistaNames));

	}

	private ArrayList getVistaNameList(Set facilities) {
		Iterator i = facilities != null ? facilities.iterator() : null;
		ArrayList vistaNameList = new ArrayList();
		while (i != null && i.hasNext()) {
			ReportFacility rFacility = (ReportFacility) i.next();
			if (rFacility != null && rFacility.getLookup() != null) {
				vistaNameList.add(rFacility.getFacility().getDescription());
			}
		}
		return vistaNameList;
	}

	private ArrayList getStationNameList(Set facilities) {
		Iterator i = facilities != null ? facilities.iterator() : null;
		ArrayList vistaNameList = new ArrayList();
		while (i != null && i.hasNext()) {
			ReportFacility rFacility = (ReportFacility) i.next();
			if (rFacility != null && rFacility.getLookup() != null) {
				vistaNameList.add(rFacility.getFacility().getStationNumber());
			}
		}
		return vistaNameList;
	}

	private String getItemsAsString(ArrayList facilities) {
		Iterator i = facilities != null ? facilities.iterator() : null;
		StringBuffer sBuf = new StringBuffer();
		if (i != null && i.hasNext()) {
			String rFacility = (String) i.next();
			sBuf.append(rFacility);
		}
		
		if (i != null) {
			while (i.hasNext()) {
				sBuf.append(", ");
				String rFacility = (String) i.next();
				sBuf.append(rFacility);
			}
		}
		return sBuf.toString();
	}

}