package eu.osci.messagetypes;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.logging.Logger;

import javax.xml.bind.JAXBException;
import javax.xml.transform.stream.StreamSource;

import org.w3._2005._08.addressing.EndpointReferenceType;

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

import eu.osci.ErrorTextTranslation;
import eu.osci.messageparts.JaxbContextHolder;
import eu.osci.messageparts.OSCIFragmentCreator;
import eu.osci.ws._2008._05.transport.MsgBoxGetNextRequestType;
import eu.osci.ws._2008._05.transport.ObjectFactory;


/**
 * The OSCIMsgBoxGetNextRequest will be used to get the next result set from a previous MsgBoxFetch or
 * MsgBoxStatusList request. With this class a next block/page of the previous request will be returned.<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 OSCIMsgBoxGetNextRequest extends OSCIRequestParent
{

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

  private MsgBoxGetNextRequestType msgBoxGetNextRequestType;

  /**
   * <b>For internal usage only!</b>
   */
  protected OSCIMsgBoxGetNextRequest()
  {}

  /**
   * This constructor is normally used by the client. The previous request will be given as parameter. If a
   * {@link OSCIMsgBoxFetchRequest}, {@link OSCIMsgBoxGetNextRequest} and than a
   * {@link OSCIMsgBoxCloseRequest} will be sent, than the previous OSCI message could be given to this
   * constructor because the configuration is the same.
   * 
   * @param parent The previous request object.
   */
  public OSCIMsgBoxGetNextRequest(OSCIRequestParent parent)
  {
    super(parent);
    LOG.fine("Entry constructor with OSCIRequestParent");
  }

  /**
   * Returns the created or set MsgBoxGetNextRequest for further processing.
   * 
   * @return The created or set MsgBoxGetNextRequest or a {@link IllegalStateException} if there is no object
   *         present.
   */
  public MsgBoxGetNextRequestType getMsgBoxGetNextRequestType()
  {
    if (msgBoxGetNextRequestType == null)
    {
      throw new IllegalStateException(
                                      OSCIMessage.text.getString(ErrorTextTranslation.OBJECT_NOT_INITIALIZED.getConstant()));
    }
    return msgBoxGetNextRequestType;
  }

  /**
   * Sets the MsgBoxGetNextRequest object. In most cases this method makes no sense. Use the constructor with
   * the OSCIRequestParent and the send* methods instead.
   * 
   * @param _msgBoxGetNextRequestType The MsgBoxGetNextRequest for selection. If there is an object already
   *          set a {@link IllegalStateException} will be thrown
   */
  public void setMsgBoxGetNextRequestType(MsgBoxGetNextRequestType _msgBoxGetNextRequestType)
  {
    if (msgBoxGetNextRequestType != null)
    {
      throw new IllegalStateException(
                                      OSCIMessage.text.getString(ErrorTextTranslation.OBJECT_ALREADY_SET.getConstant()));
    }
    msgBoxGetNextRequestType = _msgBoxGetNextRequestType;
  }

  /**
   * Sets the addressing 'ReplyTo' attribute on the OSCI message. Including the URL for reply messages.<br>
   * Be careful with this setter because if the framework will put a 'ReplyTo' header into the SOAP message
   * there will be two headers available.
   * 
   * @param _replyTo The 'ReplyTo' attribute.
   */
  public void setReplyTo(EndpointReferenceType _replyTo)
  {
    enableSetWSAReplyTo = true;
    replyTo = _replyTo;
  }

  /**
   * Internal method for preparing the send SOAP message. The header elements of the request will be set here.
   * 
   * @param bindingProvider The binding provider to set the header elements.
   * @throws JAXBException In the case of serialisation errors.
   */
  protected void prepareSendMessage(WSBindingProvider bindingProvider) throws JAXBException
  {
    ArrayList<Header> headerList = new ArrayList<Header>();
    super.prepareSendMessage(headerList);
    bindingProvider.setOutboundHeaders(headerList);
  }

  /**
   * Sends the request to present server. A SOAP message will be sent and the response message with the
   * fetched message will be created.
   * 
   * @return The created response message.
   * @throws JAXBException In the case of serialisation errors.
   */
  private Message sendRequest(String... commitIds) throws JAXBException
  {
    LOG.fine("Entry sendRequest");
    prepareSendMessage(bindingProvider);
    if (msgBoxGetNextRequestType == null)
    {
      msgBoxGetNextRequestType = new MsgBoxGetNextRequestType();
      msgBoxGetNextRequestType.setMsgBoxRequestID(getFetchIteratorID());
      int count = 0;
      while ((commitIds != null) && (count < commitIds.length))
      {
        msgBoxGetNextRequestType.getLastMsgReceived()
                                .add(OSCIFragmentCreator.createAttributedURI(commitIds[count]));
        LOG.info("Message with messageId: " + commitIds[count] + " will be marked as fetched.");
        count++;
      }
    }
    ByteArrayOutputStream body = new ByteArrayOutputStream();
    JaxbContextHolder.getOSCIJaxBContext()
                     .createMarshaller()
                     .marshal(new ObjectFactory().createMsgBoxGetNextRequest(msgBoxGetNextRequestType), body);
    Message sendMsg = Messages.createUsingPayload(new StreamSource(
                                                                   new ByteArrayInputStream(
                                                                                            body.toByteArray())),
                                                  SOAPVersion.SOAP_12);
    Message retMessage = jaxbDispatch.invoke(sendMsg);
    interpretWSAHeaders(sendMsg.getHeaders());
    return retMessage;

  }

  /**
   * Sends the request to present server. A SOAP message will be sent and the response message with the
   * fetched message will be created.
   * 
   * @param commitReceivedMessages Previous messages that will be marked as committed.
   * @return The created response message.
   * @throws JAXBException In the case of serialisation errors.
   */
  public OSCIMsgBoxFetchResponse sendFetchRequest(String... commitReceivedMessages) throws JAXBException
  {
    Message retMessage = sendRequest(commitReceivedMessages);
    return new OSCIMsgBoxFetchResponse(retMessage);
  }

  /**
   * Sends the request to present server. A SOAP message will be sent and the response message with the
   * fetched status list will be created.
   * 
   * @return The created response message
   * @throws JAXBException In the case of serialisation errors.
   */
  public OSCIMsgBoxStatusListResponse sendStatusListRequest() throws JAXBException
  {
    Message retMessage = sendRequest();
    return new OSCIMsgBoxStatusListResponse(retMessage);
  }
}
