package eu.osci.messagetypes;

import java.io.OutputStream;
import java.util.logging.Logger;

import javax.xml.bind.JAXBException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;

import com.sun.xml.ws.api.SOAPVersion;
import com.sun.xml.ws.api.message.Header;
import com.sun.xml.ws.api.message.HeaderList;
import com.sun.xml.ws.api.message.Message;
import com.sun.xml.ws.api.message.Messages;

import eu.osci.ErrorTextTranslation;
import eu.osci.messageparts.OSCIFragmentParser;
import eu.osci.ws._2008._05.transport.MsgBoxResponseType;


/**
 * This class will be returned if the client sends a MsgBoxFetchRequest. It includes the fetched message with
 * the payload and all important header elements.<br>
 * Copyright © 2010 Freie Hansestadt Bremen. <br>
 * Created by bremen online services Entwicklungs- und Betriebsgesellschaft mbH & Co. KG. <br>
 * This library (Starter Kit) can be used by anybody according to the Bremer Lizenz für freie
 * Softwarebibliotheken. The license terms can be viewed at www.osci.de or can be ordered at the
 * OSCI-Leitstelle (Die Senatorin für Finanzen, Freie Hansestadt Bremen, Postfach 10 15 40, 28015 Bremen).
 * 
 * @author R. Lindemann
 */
public class OSCIMsgBoxFetchResponse extends OSCIMessage
{

  /** Logger to log the messages. */
  private static Logger LOG = Logger.getLogger(OSCIMsgBoxFetchResponse.class.getName());

  protected MsgBoxResponseType msgBoxResponseType;

  protected Message soapMessage;

  protected Message fetchedMessage;

  protected OSCIRequest osciFetchedMsg;

  /**
   * This constructor will be used to parse the incoming SOAP header elements. It will be called by the send
   * method of the associate request message.
   * 
   * @param _soapMessage The incoming SOAP message with the given header and body elements.
   * @throws JAXBException In case that the header elements could not be parsed.
   */
  public OSCIMsgBoxFetchResponse(Message _soapMessage) throws JAXBException
  {
    LOG.fine("Entry constructor with SOAP message");
    soapMessage = _soapMessage;
    interpretHeaders(soapMessage.getHeaders());
    if ((msgBoxResponseType != null) && (msgBoxResponseType.getNoMessageAvailable() == null))
    {
      LOG.info("Found a fetch message");
      fetchedMessage = Messages.create(soapMessage.readPayloadAsSource(), SOAPVersion.SOAP_12);
      osciFetchedMsg = new OSCIRequest(fetchedMessage);
    }
    else
      LOG.info("No fetch message found.");
  }

  /**
   * Interprets the incoming header elements and sets the WS-Addressing and OSCI element on this method.
   * 
   * @param headerList The header list that will be parsed.
   * @throws JAXBException In the case of parsing errors.
   */
  protected void interpretHeaders(HeaderList headerList) throws JAXBException
  {
    LOG.fine("Entry interpretHeaders()");
    for ( Header header : headerList )
    {
      LOG.fine("Found header: " + header.getLocalPart());
    }
    interpretWSAHeaders(headerList);
    // ##### OSCI header ##########
    msgBoxResponseType = OSCIFragmentParser.getMsgBoxResponseType(headerList);
    setAdditionalHeaderList(headerList);

  }

  /**
   * Returns the metadata for the selection. In most cases the methods {@link #getItemsPending},
   * {@link #getFetchIteratorID} and {@link #noMessageFoundForSelection} can be used.
   */
  public MsgBoxResponseType getMsgBoxResponse()
  {
    return msgBoxResponseType;
  }

  /**
   * Returns the count of the next available messages.
   * 
   * @return The count of pending messages.
   */
  public long getItemsPending()
  {
    if ((soapMessage == null) || (msgBoxResponseType == null))
    {
      throw new IllegalStateException(
                                      OSCIMessage.text.getString(ErrorTextTranslation.OBJECT_NOT_INITIALIZED.getConstant()));
    }
    return msgBoxResponseType.getItemsPending().longValue();
  }

  /**
   * Returns true if there are no messages found for the selection.
   * 
   * @return False if messages are found otherwise true.
   */
  public boolean noMessageFoundForSelection()
  {
    if ((soapMessage == null) || (msgBoxResponseType == null))
    {
      throw new IllegalStateException(
                                      OSCIMessage.text.getString(ErrorTextTranslation.OBJECT_NOT_INITIALIZED.getConstant()));
    }
    if (msgBoxResponseType.getNoMessageAvailable() != null)
    {
      return true;
    }
    return false;
  }

  /**
   * Returns the id that was generated by the server for the search parameter of the request message. The
   * fetchIteratorId could be used for getNext requests.
   * 
   * @return The generated id for next requests.
   */
  public String getFetchIteratorID()
  {
    if ((soapMessage == null) || (msgBoxResponseType == null))
    {
      throw new IllegalStateException(
                                      OSCIMessage.text.getString(ErrorTextTranslation.OBJECT_NOT_INITIALIZED.getConstant()));
    }
    return msgBoxResponseType.getMsgBoxRequestID();
  }

  /**
   * Returns the whole OSCI message of associated request message. The whole OSCI message will be returned
   * with all header information and the payload in the body.
   * 
   * @param out An OutputStream where the data could be written to.
   * @throws TransformerException If there are errors getting the stream.
   */
  public void getReceiveMessageStream(OutputStream out) throws TransformerException
  {
    TransformerFactory factory = TransformerFactory.newInstance();
    Transformer transformer = factory.newTransformer();
    StreamResult streamResult = new StreamResult();
    streamResult.setOutputStream(out);
    transformer.transform(fetchedMessage.readPayloadAsSource(), streamResult);
  }

  /**
   * Returns the whole OSCI message of associated request message. The whole OSCI message will be returned
   * with all header information and the payload in the body.
   * 
   * @return The SOAP message.
   */
  public Message getReceiveMessageAsSoapMessage()
  {
    return fetchedMessage;
  }

  /**
   * Returns the created fetched OSCI message.
   * 
   * @return The parsed OSCIRequest message out of the OSCIMsgBoxFetchResponse.
   */
  public OSCIRequest getReceiveMessage()
  {
    return osciFetchedMsg;
  }
}
