package eu.osci.messagetypes;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.xml.ws.WebServiceFeature;

import org.junit.Test;

import com.sun.xml.ws.api.security.CallbackHandlerFeature;
import com.sun.xml.wss.XWSSecurityException;
import com.sun.xml.wss.impl.misc.DefaultCallbackHandler;

import eu.osci.ErrorTextTranslation;
import eu.osci.OSCIException;
import eu.osci.OSCIFault;
import eu.osci.helper.EndpointLocator;
import eu.osci.messageparts.OSCIFragmentCreator;


/**
 * Tests the error codes of the specification. In the most test methods an OSCIException will be thrown.<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 TestErrorMessages extends MessageParent
{

  private static final Logger LOG = Logger.getLogger(TestErrorMessages.class.getName());

  /**
   * Sends an OSCIRequest with a wrong SAML assertion will be used. In the STS configuration a user with the
   * name 'Wrong_claim' must be configured and the SAML assertion should not match the expected one.<br>
   * Expected behaviour: An Exception
   */
  @Test
  public void testWrongClaims() throws Exception
  {
    EndpointLocator endpointLocator = new EndpointLocator(new URL(URL_WSDL_USER));
    endpointLocator.usePort("LetterStyle");
    Properties props = new Properties();
    props.put("my.username", "Wrong_claim");
    props.put("my.password", "Wrong_claim");
    CallbackHandlerFeature callbackFeature = new CallbackHandlerFeature(new MyCallbackHandler("osci", props));
    MyRequest req = new MyRequest(endpointLocator, callbackFeature);
    req.sendMessage(new ByteArrayInputStream(MessageParent.XML_ENC_DATA.getBytes()));
  }

  private static class MyRequest extends OSCIRequest
  {

    public MyRequest(EndpointLocator endpointLocator, WebServiceFeature feature)
    {
      super(endpointLocator, feature);
      bindingProvider.getRequestContext().put(com.sun.xml.wss.XWSSConstants.USERNAME_PROPERTY, "Wrong_claim");
      bindingProvider.getRequestContext().put(com.sun.xml.wss.XWSSConstants.PASSWORD_PROPERTY, "Wrong_claim");
    }
  }

  private static class MyCallbackHandler extends DefaultCallbackHandler
  {

    public MyCallbackHandler(String clientOrServer, Properties assertions) throws XWSSecurityException
    {
      super(clientOrServer, assertions);
    }

    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException
    {
      for ( Callback tmpCallback : callbacks )
      {
        LOG.fine("################################################ \n handle() callback=" + tmpCallback);
      }
      super.handle(callbacks);
    }
  }

  public void testSendFile() throws Exception
  {
    InputStream in = this.getClass().getResourceAsStream("/data/soapMessage.xml");
    sendMessage(in, URL_WSDL_USER);
  }

  private void sendMessage(InputStream in, String url) throws Exception
  {
    URLConnection con = new URL(url).openConnection();
    con.setDoOutput(true);
    OutputStream out = con.getOutputStream();
    int count = 0;
    byte[] bytes = new byte[102400];
    while ((count = in.read(bytes)) > -1)
    {
      out.write(bytes, 0, count);
      System.out.println(new String(bytes));
    }
    out.close();
    InputStream resp = con.getInputStream();
    ByteArrayOutputStream rspOut = new ByteArrayOutputStream();
    while ((count = resp.read(bytes)) > -1)
    {
      rspOut.write(bytes, 0, count);
    }
    LOG.fine("The Response: " + rspOut.toString());
  }

  /**
   * A wrong endpoint address will be requested. Requested physical URL does not match the requested
   * OSCIMsgBoxFetchRequest URL of the request.<br>
   * Expected behaviour: An OSCIException will be thrown.
   */
  @Test
  public void testWrongMsgBoxSelected()
  {
    try
    {
      EndpointLocator wsdlHelper = new EndpointLocator(new URL(URL_WSDL_USER));
      LOG.fine("Service: " + wsdlHelper.getServiceList().length);
      wsdlHelper.usePort("LetterStyle");
      OSCIRequest req = new OSCIRequest(wsdlHelper);
      ByteArrayInputStream encData = new ByteArrayInputStream(XML_ENC_DATA.getBytes());
      OSCIResponse rsp = req.sendMessage(encData);
      assertNull("Delivery receipt is not null", rsp.getDeliveryReceipt());
      assertNotNull("RelatesTo is null", rsp.getRelatesTo());
      assertEquals("Not the correct RelatesTo in response", req.getMessageId().getValue(), rsp.getRelatesTo()
                                                                                              .getValue());
      OSCIMsgBoxFetchRequest reqFetch = new OSCIMsgBoxFetchRequest(new URL(URL_WSDL_USER), SERVICE,
                                                                   FETCH_PORT);
      reqFetch.setSelectionByMessageId(new String[]{req.getMessageId().getValue()},
                                       OSCIFragmentCreator.createEndpointRef(WSA_REPLY_TO));
      OSCIMsgBoxFetchResponse rspFetch = reqFetch.sendRequest();
      assertFalse("No message found for selection", rspFetch.noMessageFoundForSelection());
      assertTrue("Wrong count of pending items found: "
                 + rspFetch.getMsgBoxResponse().getItemsPending().intValue(), rspFetch.getMsgBoxResponse()
                                                                                      .getItemsPending()
                                                                                      .intValue() >= 2);
      assertNotNull("No request iterator.", rspFetch.getMsgBoxResponse().getMsgBoxRequestID());
      assertTrue("No request iterator.", rspFetch.getMsgBoxResponse().getMsgBoxRequestID().length() > 0);
      // checkBody(rspFetch);
    }
    catch (OSCIException ex)
    {
      assertEquals("Wrong subcode",
                   OSCIFault.PROCESSING_EXCEPTION.getSubcode().getLocalPart(),
                   ex.getSubcode());
      LOG.fine("getReason: " + ex.getReason());
      assertEquals("Wrong reason", "The fetched endpoint is not allowed from this address!", ex.getReason());
      String expectedCode = OSCIFault.PROCESSING_EXCEPTION.getCode().toString().trim();
      assertTrue("Wrong fault code ", (expectedCode.indexOf("Receiver") > -1));
      assertEquals("Wrong exception code", "S:Receiver", ex.getCode());
      assertEquals("Wrong localized message",
                   OSCIFault.PROCESSING_EXCEPTION.getReason(),
                   ex.getLocalizedMessage());
      // Expected exception
    }
    catch (Exception ex)
    {
      LOG.log(Level.SEVERE, "Could not run test", ex);
      fail("Sending simple OSCI request failed. Error: " + ex.getMessage());
    }
  }

  /**
   * Forces an IllegalStateException because the FetchRequest object is empty.
   */
  @Test
  public void testErrorSendRequest() throws Exception
  {
    try
    {
      OSCIMsgBoxFetchRequest rspRequest = new OSCIMsgBoxFetchRequest();
      rspRequest.sendRequest();
    }
    catch (IllegalStateException ex)
    {
      String expectedConstant = ErrorTextTranslation.NO_SELECTION_PARAMETER.getConstant();
      assertEquals("Wrong value. ", "noSelectionPara", expectedConstant);
      assertNotNull("Translation message was null. ", ex.getLocalizedMessage());
      // Expected exception
    }
  }
}
