/* To change this template, choose Tools | Templates
 * and open the template in the editor. */
package lu.tudor.santec.gecamed.esante.gui.webservice;

import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;

import lu.tudor.santec.gecamed.core.utils.GECAMedUtils;
import lu.tudor.santec.gecamed.esante.ejb.entity.beans.ESanteProperty;
import lu.tudor.santec.gecamed.esante.utils.ESanteUtils;


/**
 * @author jens.ferring(at)tudor.lu
 * 
 * Based on infomed client sources.
 */
public class SAMLAssertion
{
	private String		envelopedAssertionContent;
	private String		plainAssertionContent;
	private Timestamp	start;
	private Timestamp	end;	
	private boolean isUserAssertion = false;
	private String		ipid;				//related to which patient
	private final static String ipidPath = "//*[local-name()='Attribute' and @Name='urn:oasis:names:tc:xacml:2.0:resource:resource-id']/*[local-name()='AttributeValue']";										
	
	public SAMLAssertion (String assertionResponse) throws Exception
	{
		// System.out.println("|"+assertionResponse+"|");
		// extract the dsp oid from the the response of the server
		this.ipid = ESanteUtils.parseXPath(ipidPath, assertionResponse, true).toString();
		// this is a saml assertion that is not specific to a certain dsp and therefore does not possess an ipid
		if(this.ipid.length()==0){
			this.ipid = ESanteProperty.USER_ASSERTION_NAME;
			this.isUserAssertion = true;
		}
		try {
			// afterwards the enveloped saml assertion (it is enveloped by the response tag)
			this.envelopedAssertionContent = SOAPUtilities.getXMLFragment("saml2p:Response", assertionResponse); 
			// and also the plain saml assertion, which is needed for document upload. (due to performance reasons this is not done on the fly)
			this.plainAssertionContent = SOAPUtilities.getXMLFragment("saml2:Assertion",envelopedAssertionContent);
		} catch (Exception e) {
			throw new Exception("Response does not contain a valid SAML assertion (SERVER OR CONNECTION ERROR)");
		}

		try {
			this.extractStartEndFromContent();
		} catch (Exception e) {
			throw new Exception("Unable to find validity period in SAML assertion.");
		}
	}
	
	
	public String getAssertionContent(boolean withResponseTag) {
		return withResponseTag ? envelopedAssertionContent : plainAssertionContent;
	}
	
	/**
	 * Indicates if this saml assertion is a user assertion
	 * 
	 * @return True, if it is a user assertion, false if it is a DSP specific assertion
	 */
	public boolean isUserAssertion() {
		return this.isUserAssertion;
	}
	
	public Timestamp getStart ()
	{
		return start;
	}
	
	
	public Timestamp getEnd ()
	{
		return end;
	}
	
	/**
	 * Provides the dsp id.
	 * 
	 * @return the ID of the patients dsp or {@link ESanteProperty#USER_ASSERTION_NAME} in case of a user saml assertion
	 */
	public String getIpid() {
		return ipid;
	}
	
	
	private void extractStartEndFromContent () throws ParseException
	{
		int startPos, endPos;
		String s;
		DateFormat formatUTC = GECAMedUtils.getDateFormatter("yyyy-MM-dd'T'HH:mm:ss.SS'Z'");
		
		startPos = envelopedAssertionContent.indexOf("NotBefore=");
		startPos = startPos + 11;
		endPos = envelopedAssertionContent.indexOf("\"", startPos);
		s = envelopedAssertionContent.substring(startPos, endPos);
		//start = Timestamp.valueOf(s);
		start = new Timestamp(formatUTC.parse(s).getTime());
		
		
		startPos = envelopedAssertionContent.indexOf("NotOnOrAfter=");
		startPos = startPos + 14;
		endPos = envelopedAssertionContent.indexOf("\"", startPos);
		s = envelopedAssertionContent.substring(startPos, endPos);
		//end = Timestamp.valueOf(s);
		end = new Timestamp(formatUTC.parse(s).getTime());
	}
	
	/**
	 * An assertion is valid if the point of time this function is called is within the period of time the assertion has been assigned for
	 * 
	 * @return True if the assertion is valid, false otherwise
	 */
	public Boolean isValid() {
		// get current time in utc
		Timestamp now = new Timestamp(System.currentTimeMillis());

		return (now.compareTo(start) >= 0) && !isExpired();
	}
	
	/**
	 * Indicates if the assertion has expired
	 * 
	 * @return True if the assertion has expired is still valid for a maximum of 5 minutes, false otherwise
	 */
	public Boolean isExpired() {
		// add 5 minutes to check if alive
		Timestamp now = new Timestamp(System.currentTimeMillis() + (5 * 60 * 1000));

		if (now.compareTo(end) >= 0) {
			return true;
		}

		return false;
	}
	
	
//	private long getUTCMillis ()
//	{
//		return System.currentTimeMillis() - TimeZone.getDefault().getRawOffset();
//	}
}
