/*******************************************************************************
 * Copyright © 2006 VHA. All rights reserved
 ******************************************************************************/
package gov.va.med.esr.ui.taglib;

// Java classes
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.security.ESRUserPrincipalImpl;
import gov.va.med.esr.service.UnknownLookupTypeException;
import gov.va.med.esr.ui.common.beans.VISNSite;
import gov.va.med.esr.ui.common.service.LookupCacheService;
import gov.va.med.fw.model.lookup.Lookup;
import gov.va.med.fw.security.SecurityContextHelper;
import gov.va.med.fw.ui.DelegatingActionUtils;
import gov.va.med.fw.util.StringUtils;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyTagSupport;

import org.apache.struts.taglib.TagUtils;
import org.springframework.web.context.WebApplicationContext;

/**
 * Tag handler for the ESR Code options tag.
 * 
 */
public class SetLookupP8Tag extends BodyTagSupport {

	private static final long serialVersionUID = 2787899133475609011L;

	public final static String PAGE_SCOPE = "page";

	public final static String REQUEST_SCOPE = "request";

	public final static String SESSION_SCOPE = "session";

	public final static String APPLICATION_SCOPE = "application";
	
	public final static String VISN_CLASS="gov.va.med.esr.common.model.lookup.VISN";
	public final static String VISN_SITE_CLASS="gov.va.med.esr.ui.common.beans.VISNSite";
	public final static String SITE_CLASS="gov.va.med.esr.ui.common.beans.PreferredFacility";
	public final static String VAFACILITY_CLASS="gov.va.med.esr.common.model.lookup.VAFacility";
	public final static String HEC_USER_CLASS="hec.user";
	
	private String className;

	private String var;

	private String scope;
	private String reportId;
	
	private String removeCollection = null;

	private String removeCollectionScope = null;

	public String getClassName() {
		return className;
	}

	public void setClassName(String className) {
		this.className = className;
	}

	public String getVar() {
		return var;
	}

	public void setVar(String var) {
		this.var = var;
	}

	public String getScope() {
		return this.scope;
	}

	public void setScope(String scope) {
		this.scope = scope;
	}

	public String getRemoveCollection() {
		return removeCollection;
	}

	public void setRemoveCollection(String removeCollection) {
		this.removeCollection = removeCollection;
	}

	public String getRemoveCollectionScope() {
		return removeCollectionScope;
	}

	public void setRemoveCollectionScope(String removeCollectionScope) {
		this.removeCollectionScope = removeCollectionScope;
	}

	public int doStartTag() throws JspException {
        this.setLookup(getLookup(className));
		return (EVAL_PAGE);
	}

	public void release() {
		super.release();
		this.className = null;
		this.var = null;
		this.scope = null;
		this.removeCollection = null;
		this.removeCollectionScope = null;
	}

	/**
	 * Gets the lookup either from the cache or from the database.
	 * 
	 * @exception JspException
	 *               if an error occurs
	 */
	protected Collection getLookup(String className) throws JspException {
		Collection list = null;
		try {
			WebApplicationContext ac = DelegatingActionUtils.findRequiredWebApplicationContext( pageContext.getServletContext() );
			if(className.indexOf(HEC_USER_CLASS)<0){
				LookupCacheService lookupCacheService = 
					(LookupCacheService) ac.getBean(LookupCacheService.LOOKUP_CACHE_SERVICE);
				list = this.filterCollection(lookupCacheService.getFromCache(className));
			}
			ESRUserPrincipalImpl user = (ESRUserPrincipalImpl)SecurityContextHelper.getCurrentUser();
			VAFacility userFacility=user.getFacility();
			if(userFacility==null)
				return new ArrayList();
			if(!isHECUser())
				list=userProfileSecuredList(list,className,userFacility);
		}
		catch (Exception ex) {
			throw new JspException("Error while getting lookup data.", ex);
		}
		return list;
	}
	
	private boolean isHECUser(){
		boolean hecUser=false;
		ESRUserPrincipalImpl user = (ESRUserPrincipalImpl)SecurityContextHelper.getCurrentUser();
		VAFacility userFacility=user.getFacility();
		if(userFacility!=null){
			String stationNumber=userFacility.getStationNumber();
			String str=(VAFacility.CODE_HEC).getName();
			if(stationNumber.equalsIgnoreCase(str)){
				hecUser=true;
			}else if(userFacility.getCode().equals(VAFacility.CODE_HEC))
			hecUser=true;
		}
		return hecUser;
	}
	private Collection userProfileSecuredList(Collection list, String className, VAFacility userFacility){
		if(list==null || userFacility==null)
			return list;
		if(className.indexOf(VISN_CLASS)>-1){
			list=filterVISNList(list, userFacility);
		}else if(className.indexOf(SITE_CLASS)>-1){
			list=filterSiteList(list, userFacility);
		}else if(className.indexOf(VAFACILITY_CLASS)>-1){
			list=filterSiteList(list, userFacility);
		}else if(className.indexOf(VISN_SITE_CLASS)>-1){
			list=filterVisnSiteList(list, userFacility);
		}
		return list;
	}
	
	private Collection filterVISNList(Collection list, VAFacility userFacility){
		ArrayList securedList=new ArrayList();
		Iterator listIter=list.iterator();

		while(listIter.hasNext()){
			Object obj=listIter.next();
			VISN visn=(VISN)obj;
			BigDecimal visnId=visn.getIdentifier();
			BigDecimal userFacilityVisnId=userFacility.getVisnId();
			if(visnId!=null && userFacilityVisnId!=null && (visnId.compareTo(userFacilityVisnId)==0)){
				securedList.add(obj);
				break;
			}
		}
		return securedList;
	}
	
	private Collection filterSiteList(Collection list, VAFacility userFacility){
		ArrayList securedList=new ArrayList();
		Iterator listIter=list.iterator();

		while(listIter.hasNext()){
			Object obj=listIter.next();
			VAFacility facility=(VAFacility)obj;
			BigDecimal visnId=facility.getVisnId();
			BigDecimal userFacilityVisnId=userFacility.getVisnId();
			
			if(visnId!=null && userFacilityVisnId!=null && 
					(visnId.compareTo(userFacilityVisnId)==0)){
				securedList.add(obj);
			}
		}
		return securedList;
	}
	
	private Collection filterVisnSiteList(Collection list, VAFacility userFacility){
		ArrayList securedList=new ArrayList();
		Iterator listIter=list.iterator();

		while(listIter.hasNext()){
			Object obj=listIter.next();
			if(obj instanceof VISN){
				VISN facility=(VISN)obj;
				BigDecimal visnId=facility.getIdentifier();
				BigDecimal userFacilityVisnId=userFacility.getVisnId();
				if(visnId!=null && userFacilityVisnId!=null
						&&(visnId.compareTo(userFacilityVisnId)==0)){
					securedList.add(obj);
					while(listIter.hasNext()){
						Object facilityObj=listIter.next();
						if(facilityObj instanceof VISNSite){
							securedList.add(facilityObj);
						}else{
							break;
						}
					}
					break;
				}
			}
		}
		return securedList;
	}
	/**
	 * Sets the lookup in the scope.
	 * 
	 * @param lookup
	 * @throws JspException
	 */
	protected void setLookup(Collection lookup) throws JspException {
		String localVar = StringUtils.isNotEmpty(var) ? var : this.className;
		if((className.indexOf(HEC_USER_CLASS)>=0)){ 
			if(isHECUser()){
				setHECUserLookup();
			}
			return;
		}
		if (StringUtils.isEmpty(scope) || StringUtils.equals(scope, PAGE_SCOPE)) {
			pageContext.setAttribute(localVar, lookup);
			if(className.indexOf(HEC_USER_CLASS)>=0){
				pageContext.setAttribute(localVar, "false");
			}
		}
		else {
			HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
			if (StringUtils.equals(scope, REQUEST_SCOPE)) {
				request.setAttribute(localVar, lookup);
			}
			else if (StringUtils.equals(scope, SESSION_SCOPE)) {
				request.getSession().setAttribute(localVar, lookup);
			}
			else if (StringUtils.equals(scope, APPLICATION_SCOPE)) {
				request.getSession().getServletContext().setAttribute(localVar,lookup);
			}
		}
	}

	protected void setHECUserLookup() throws JspException {
		String localVar="hecUserflag";
		String lookup="true";
		if (StringUtils.isEmpty(scope) || StringUtils.equals(scope, PAGE_SCOPE)) {
			pageContext.setAttribute(localVar, lookup);
		}
		else {
			HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
			if (StringUtils.equals(scope, REQUEST_SCOPE)) {
				request.setAttribute(localVar, lookup);
			}
			else if (StringUtils.equals(scope, SESSION_SCOPE)) {
				request.getSession().setAttribute(localVar, lookup);
			}
			else if (StringUtils.equals(scope, APPLICATION_SCOPE)) {
				request.getSession().getServletContext().setAttribute(localVar,lookup);
			}
		}
	}
	
	protected Collection filterCollection(Collection list) throws JspException {
		if (list == null || list.isEmpty()) {
			return list;
		}
		// Get removable elements as a map
		Map removables = getRemovables();
		if (removables == null || removables.isEmpty()) {
			return list;
		}

		// Filter out the removable elements
		Collection result = new ArrayList();
		for (Iterator listIter = list.iterator(); listIter.hasNext();) {
			Lookup lookup = (Lookup) listIter.next();
			if (removables.get(lookup.getCode()) == null) {
				result.add(lookup);
			}
		}
		return result;
	}

	protected Map getRemovables() throws JspException {
		if (StringUtils.isEmpty(this.getRemoveCollection())) {
			return null;
		}

		Map removeble = new HashMap();
		TagUtils util = TagUtils.getInstance();
		Object col = util.lookup(pageContext, this.getRemoveCollection(), this
				.getRemoveCollectionScope());
		if (col != null) {
			if (col.getClass().isArray()) {
				Object[] array = (Object[]) col;
				for (int i = 0; i < array.length; i++) {
					removeble.put((array[i] instanceof Lookup) ? ((Lookup) array[i]).getCode() : array[i], "");
				}
			}
			else if (col instanceof Collection) {
				for (Iterator iter = ((Collection) col).iterator(); iter.hasNext();) {
					Object obj = iter.next();
					removeble.put((obj instanceof Lookup) ? ((Lookup) obj).getCode() : obj, "");
				}
			}
		}
		return removeble;
	}

	public String getReportId() {
		return reportId;
	}

	public void setReportId(String reportId) {
		this.reportId = reportId;
	}
}