package at.gv.egovernment.moa.id.auth.parser;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import org.w3c.dom.Element;

import at.gv.egovernment.moa.id.AuthenticationException;
import at.gv.egovernment.moa.id.ParseException;
import at.gv.egovernment.moa.id.auth.data.IdentityLink;
import at.gv.egovernment.moa.util.Constants;
import at.gv.egovernment.moa.util.DOMUtils;
import at.gv.egovernment.moa.util.XPathUtils;

/**
 * Parses an <code>&lt;InfoboxReadResponse&gt;</code>.
 * 
 * @author Stefan Knirsch
 * @version $Id$
 */

public class InfoboxReadResponseParser {
  //
  // XPath namespace prefix shortcuts
  //
  /** Xpath prefix for reaching SecurityLayer 1.0 Namespaces */
  private static final String SL10 = Constants.SL10_PREFIX + ":";
  /** Xpath prefix for reaching SAML Namespaces */
  private static final String SAML = Constants.SAML_PREFIX + ":";
  /** Xpath expression to the root element */  
  private static final String ROOT = "/" + SL10 + "InfoboxReadResponse/";
  /** Xpath expression to the SAML:Assertion element */  
  private static final String SAML_ASSERTION_XPATH = ROOT + SL10 + "BinaryFileData/" + SL10 + "XMLContent/" + SAML + "Assertion";

  /** This is the root element of the XML-Document provided by the Security Layer Card*/
  private Element infoBoxElem;

  /**
   * Constructor for InfoboxReadResponseParser.
   * A DOM-representation of the incoming String will be created
   * @param xmlResponse <code>&lt;InfoboxReadResponse&gt;</code> as String
   * @throws ParseException on any parsing error
   */
  public InfoboxReadResponseParser(String xmlResponse) throws ParseException, AuthenticationException {

    ErrorResponseParser erp = new ErrorResponseParser(xmlResponse);
    if (erp.getErrorCode() != null) {
      throw new AuthenticationException("auth.08", new Object[] { erp.getErrorCode(), erp.getErrorInfo()});
    }

    try {

      InputStream s = new ByteArrayInputStream(xmlResponse.getBytes("UTF-8"));
      infoBoxElem = DOMUtils.parseXmlValidating(s);
    }
    catch (Throwable t) {
    	throw new ParseException("parser.01", new Object[] { t.toString()}, t);
    }
  }

  /**
   * Constructor for InfoboxReadResponseParser.
   * A DOM-representation of the incoming Inputstream will be created
   * @param xmlResponse <code>&lt;InfoboxReadResponse&gt;</code> as InputStream
   * @throws ParseException on any parsing error
   */
  public InfoboxReadResponseParser(InputStream is) throws ParseException, AuthenticationException {

    ErrorResponseParser erp = new ErrorResponseParser(is);
    if (erp.getErrorCode() != null) {
      throw new AuthenticationException("auth.08", new Object[] { erp.getErrorCode(), erp.getErrorInfo()});
    }

    try {

      infoBoxElem = DOMUtils.parseXmlValidating(is);
    }
    catch (Throwable t) {
      throw new ParseException("parser.01", new Object[] { t.toString()}, t);
    }
  }

  /**
   * Parses the embedded <code>&lt;saml:Assertion&gt;</code> element from <code>&lt;InfoboxReadResponse&gt;</code>
   * @return <code>&lt;saml:Assertion&gt;</code> as String
   * @throws ParseException on any parsing error
   */
  public String parseSAMLAssertion() throws ParseException {
    try {
      Element samlAssertion = (Element) XPathUtils.selectSingleNode(infoBoxElem, SAML_ASSERTION_XPATH);
      return DOMUtils.serializeNode(samlAssertion);
    }
    catch (Throwable t) {
      throw new ParseException("parser.01", new Object[] { t.toString()}, t);
    }
  }

  /**
   * Parses the identity link from the <code>&lt;saml:Assertion&gt;</code>
   * @return Identity link
   * @throws ParseException on any parsing error
   */

  public IdentityLink parseIdentityLink() throws ParseException {
    String samlAssertionString = parseSAMLAssertion();
    IdentityLinkAssertionParser ilParser = new IdentityLinkAssertionParser(samlAssertionString);
    return ilParser.parseIdentityLink();
  }

}