package gov.va.med.esr.webservices.jaxws.spring.interceptor;

import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;

import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;

import org.springframework.util.CollectionUtils;
import org.springframework.ws.soap.SoapFault;
import org.springframework.ws.soap.SoapFaultDetail;
import org.springframework.ws.soap.SoapFaultDetailElement;
import org.springframework.ws.soap.server.endpoint.AbstractSoapFaultDefinitionExceptionResolver;
import org.springframework.ws.soap.server.endpoint.SoapFaultDefinition;
import org.springframework.ws.soap.server.endpoint.SoapFaultDefinitionEditor;
import org.springframework.xml.transform.StringSource;

public class ExceptionResolver extends
		AbstractSoapFaultDefinitionExceptionResolver {


	

    public ExceptionResolver()
    {
        exceptionMappings = new LinkedHashMap();
    }

    public void setExceptionMappings(Properties mappings)
    {
        Iterator i$ = mappings.entrySet().iterator();
        do
        {
            if(!i$.hasNext())
                break;
            java.util.Map.Entry entry = (java.util.Map.Entry)i$.next();
            if((entry.getKey() instanceof String) && (entry.getValue() instanceof String))
                exceptionMappings.put((String)entry.getKey(), (String)entry.getValue());
        } while(true);
    }

    protected SoapFaultDefinition getFaultDefinition(Object endpoint, Exception ex)
    {
        if(!CollectionUtils.isEmpty(exceptionMappings))
        {
            String definitionText = null;
            int deepest = 2147483647;
            Iterator i$ = exceptionMappings.keySet().iterator();
            do
            {
                if(!i$.hasNext())
                    break;
                String exceptionMapping = (String)i$.next();
                int depth = getDepth(exceptionMapping, ex);
                
                /*if this exception is not mapped in class heirachy then check the caused path.*/
                if ( depth < 0 ) {
                	depth = getRootCauseDepth(exceptionMapping, ex);
                }
                
                if(depth >= 0 && depth < deepest)
                {
                    deepest = depth;
                    definitionText = (String)exceptionMappings.get(exceptionMapping);
                }
            } while(true);
            if(definitionText != null)
            {
                SoapFaultDefinitionEditor editor = new SoapFaultDefinitionEditor();
                SoapFaultDefinition faultDef = (SoapFaultDefinition)editor.getValue();
                
                if (faultDef == null ) {
                	faultDef = new SoapFaultDefinition();
                	editor.setValue(faultDef);
                }
                
                String exMessage = ex.getMessage();
                if (exMessage != null && (exMessage.indexOf("gov.va.med.person.exceptions.NoRecordFoundException") >= 0  ||
                		exMessage.indexOf("No Record Found")>=0 ||
                		exMessage.indexOf("VPID Exception")>=0 ||
                		exMessage.indexOf("gov.va.med.person.idmgmt.exceptions.VPIDException") >= 0)){
                	//This must be person not found exception.
                	faultDef.setFaultCode(SoapFaultDefinition.CLIENT);
                	faultDef.setFaultStringOrReason("PERSON_NOT_FOUND");
                } else if (exMessage != null && 
                	(exMessage.indexOf("Authorization exception") >= 0)) {
                	faultDef.setFaultCode(SoapFaultDefinition.CLIENT);
                	faultDef.setFaultStringOrReason("AUTHORIZATION_FAILED");
                }else {
                	faultDef.setFaultCode(SoapFaultDefinition.SERVER);
                	faultDef.setFaultStringOrReason("UNKNOWN_ERROR");
                }
                
                return (SoapFaultDefinition)editor.getValue();
            }
        }
        return null;
    }

    
    protected void customizeFault(Object obj, Exception exception, SoapFault soapfault)
    {
    	
    
		//Transformer trn;
		//try {
			//trn = TransformerFactory.newInstance().newTransformer();
			SoapFaultDetail faultDetail = soapfault.addFaultDetail();
			String  exmessage = exception.getMessage();
			SoapFaultDetailElement detailEle = faultDetail.addFaultDetailElement(faultDetail.getName());
			detailEle.addText(exmessage);
		//} catch (TransformerException e) {
		//	logger.error("problem with XML transform: ", e);
		//}

    }
    
    
    protected int getDepth(String exceptionMapping, Exception ex)
    {
        return getDepth(exceptionMapping, ex.getClass(), 0);
    }

    private int getDepth(String exceptionMapping, Class exceptionClass, int depth)
    {
        if(exceptionClass.getName().indexOf(exceptionMapping) != -1)
            return depth;
        if(exceptionClass.equals(java.lang.Throwable.class))
            return -1;
        else
            return getDepth(exceptionMapping, exceptionClass.getSuperclass(), depth + 1);
    }

    
    protected int getRootCauseDepth(String exceptionMapping, Throwable ex)
    {
        return getRootCauseDepth(exceptionMapping, 0, ex);
    }

    private int getRootCauseDepth(String exceptionMapping,  int depth, Throwable ex)
    {
    	if ( ex == null )
    		return -1;
        if(ex.getClass().getName().indexOf(exceptionMapping) != -1)
            return depth;
        if(ex.getClass().getName().equals(java.lang.Throwable.class))
            return -1;
        else {
        	Throwable exception = ex.getCause();
            return getRootCauseDepth(exceptionMapping,  depth + 1, exception);
        }
    }
    
    
    private Map exceptionMappings;

}
