/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.cxf.dosgi.dsw.handlers.ws;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.xml.namespace.QName;

import org.apache.aries.rsa.spi.Endpoint;
import org.apache.aries.rsa.util.EndpointHelper;
import org.apache.cxf.dosgi.common.endpoint.ServerEndpoint;
import org.apache.cxf.dosgi.common.httpservice.HttpServiceManager;
import org.apache.cxf.dosgi.common.intent.IntentManager;
import org.apache.cxf.dosgi.common.intent.impl.IntentManagerImpl;
import org.apache.cxf.dosgi.dsw.handlers.jaxws.MyJaxWsEchoService;
import org.apache.cxf.dosgi.dsw.handlers.simple.MySimpleEchoService;
import org.apache.cxf.dosgi.dsw.handlers.simple.MySimpleEchoServiceImpl;
import org.apache.cxf.endpoint.EndpointImpl;
import org.apache.cxf.endpoint.Server;
import org.apache.cxf.frontend.ClientFactoryBean;
import org.apache.cxf.frontend.ClientProxyFactoryBean;
import org.apache.cxf.frontend.ServerFactoryBean;
import org.apache.cxf.jaxws.support.JaxWsEndpointImpl;
import org.apache.cxf.transport.Destination;
import org.apache.cxf.ws.addressing.AttributedURIType;
import org.apache.cxf.ws.addressing.EndpointReferenceType;
import org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean;
import org.easymock.EasyMock;
import org.easymock.IAnswer;
import org.easymock.IMocksControl;
import org.junit.Assert;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.Version;
import org.osgi.service.remoteserviceadmin.EndpointDescription;
import org.osgi.service.remoteserviceadmin.RemoteConstants;

import junit.framework.TestCase;

public class PojoConfigurationTypeHandlerTest extends TestCase {

    public void testGetPojoAddressEndpointURI() {
        IntentManager intentManager = new IntentManagerImpl();
        WsProvider handler = new WsProvider();
        handler.setIntentManager(intentManager);
        handler.setHttpServiceManager(dummyHttpServiceManager());
        Map<String, Object> sd = new HashMap<String, Object>();
        String url = "http://somewhere:1234/blah";
        sd.put(RemoteConstants.ENDPOINT_ID, url);
        assertEquals(url, handler.getServerAddress(sd, String.class));
    }

    private HttpServiceManager dummyHttpServiceManager() {
        return new HttpServiceManager();
    }

    public void testGetPojoAddressEndpointCxf() {
        IntentManager intentManager = new IntentManagerImpl();
        WsProvider handler = new WsProvider();
        handler.setIntentManager(intentManager);
        handler.setHttpServiceManager(dummyHttpServiceManager());
        Map<String, Object> sd = new HashMap<String, Object>();
        String url = "http://somewhere:29/boo";
        sd.put("org.apache.cxf.ws.address", url);
        assertEquals(url, handler.getServerAddress(sd, String.class));
    }

    public void testGetDefaultPojoAddress() {
        IntentManager intentManager = new IntentManagerImpl();
        WsProvider handler = new WsProvider();
        handler.setIntentManager(intentManager);
        handler.setHttpServiceManager(dummyHttpServiceManager());
        Map<String, Object> sd = new HashMap<String, Object>();
        assertEquals("/java/lang/String", handler.getServerAddress(sd, String.class));
    }

    // todo: add test for data bindings
    public void testCreateProxy() {
        IMocksControl c = EasyMock.createNiceControl();
        BundleContext bc1 = c.createMock(BundleContext.class);

        BundleContext requestingContext = c.createMock(BundleContext.class);

        final ClientProxyFactoryBean cpfb = c.createMock(ClientProxyFactoryBean.class);
        ReflectionServiceFactoryBean sf = c.createMock(ReflectionServiceFactoryBean.class);
        EasyMock.expect(cpfb.getServiceFactory()).andReturn(sf).anyTimes();
        ClientFactoryBean cf = c.createMock(ClientFactoryBean.class);
        EasyMock.expect(cpfb.getClientFactoryBean()).andReturn(cf).anyTimes();
        IntentManager intentManager = new IntentManagerImpl();
        WsProvider p = new WsProvider() {
            @Override
            protected ClientProxyFactoryBean createClientProxyFactoryBean(Map<String, Object> sd,
                                                                          Class<?> iClass) {
                return cpfb;
            }
        };
        p.setIntentManager(intentManager);
        p.setHttpServiceManager(dummyHttpServiceManager());
        p.activate(bc1);

        Class<?>[] exportedInterfaces = new Class[] {Runnable.class};

        Map<String, Object> props = new HashMap<String, Object>();
        props.put(RemoteConstants.ENDPOINT_ID, "http://google.de/");
        EndpointHelper.addObjectClass(props, exportedInterfaces);
        props.put(RemoteConstants.SERVICE_IMPORTED_CONFIGS, new String[] {"my.config"});
        EndpointDescription endpoint = new EndpointDescription(props);

        cpfb.setAddress((String)EasyMock.eq(props.get(RemoteConstants.ENDPOINT_ID)));
        EasyMock.expectLastCall().atLeastOnce();

        cpfb.setServiceClass(EasyMock.eq(Runnable.class));
        EasyMock.expectLastCall().atLeastOnce();

        c.replay();
        ClassLoader cl = null;
        Object proxy = p.importEndpoint(cl, requestingContext, exportedInterfaces, endpoint);
        assertNotNull(proxy);
        assertTrue("Proxy is not of the requested type! ", proxy instanceof Runnable);
        c.verify();
    }

    public void testCreateServerWithAddressProperty() {
        BundleContext dswContext = EasyMock.createNiceMock(BundleContext.class);
        EasyMock.replay(dswContext);

        String myService = "Hi";
        final ServerFactoryBean sfb = createMockServerFactoryBean();

        IntentManager intentManager = new IntentManagerImpl();
        WsProvider p = new WsProvider() {
            @Override
            protected ServerFactoryBean createServerFactoryBean(Map<String, Object> sd, Class<?> iClass) {
                return sfb;
            }
        };
        p.activate(dswContext);
        p.setIntentManager(intentManager);
        p.setHttpServiceManager(dummyHttpServiceManager());
        BundleContext bundleContext = EasyMock.createNiceMock(BundleContext.class);
        EasyMock.replay(bundleContext);

        Class<?>[] exportedInterface = new Class[] {String.class
        };
        Map<String, Object> props = new HashMap<String, Object>();
        EndpointHelper.addObjectClass(props, exportedInterface);
        props.put(WsConstants.WS_ADDRESS_PROPERTY, "http://alternate_host:80/myString");

        Endpoint exportResult = p.exportService(myService, bundleContext, props, exportedInterface);
        Map<String, Object> edProps = exportResult.description().getProperties();

        assertNotNull(edProps.get(RemoteConstants.SERVICE_IMPORTED_CONFIGS));
        assertEquals(1, ((String[])edProps.get(RemoteConstants.SERVICE_IMPORTED_CONFIGS)).length);
        assertEquals(WsConstants.WS_CONFIG_TYPE,
                     ((String[])edProps.get(RemoteConstants.SERVICE_IMPORTED_CONFIGS))[0]);
        assertEquals("http://alternate_host:80/myString", edProps.get(RemoteConstants.ENDPOINT_ID));
    }

    public void testAddressing() {
        runAddressingTest(new HashMap<String, Object>(), "http://localhost:9000/java/lang/Runnable");

        Map<String, Object> p1 = new HashMap<String, Object>();
        p1.put("org.apache.cxf.ws.address", "http://somewhere");
        runAddressingTest(p1, "http://somewhere");

        Map<String, Object> p3 = new HashMap<String, Object>();
        p3.put("org.apache.cxf.ws.port", 65535);
        runAddressingTest(p3, "http://localhost:65535/java/lang/Runnable");

        Map<String, Object> p4 = new HashMap<String, Object>();
        p4.put("org.apache.cxf.ws.port", "8181");
        runAddressingTest(p4, "http://localhost:8181/java/lang/Runnable");
    }

    private void runAddressingTest(Map<String, Object> properties, String expectedAddress) {
        Class<?>[] exportedInterface = new Class[] {Runnable.class};
        EndpointHelper.addObjectClass(properties, exportedInterface);
        BundleContext dswContext = EasyMock.createNiceMock(BundleContext.class);
        String expectedUUID = UUID.randomUUID().toString();
        EasyMock.expect(dswContext.getProperty(org.osgi.framework.Constants.FRAMEWORK_UUID))
            .andReturn(expectedUUID);
        EasyMock.replay(dswContext);

        IntentManager intentManager = new IntentManagerImpl();

        WsProvider handler = new WsProvider() {
            @Override
            protected Endpoint createServerFromFactory(ServerFactoryBean factory, EndpointDescription epd) {
                return new ServerEndpoint(epd, null);
            }
        };
        handler.setIntentManager(intentManager);
        handler.setHttpServiceManager(dummyHttpServiceManager());
        handler.activate(dswContext);
        Runnable myService = new Runnable() {
            @Override
            public void run() {
            }
        };

        BundleContext bundleContext = EasyMock.createNiceMock(BundleContext.class);
        EasyMock.replay(bundleContext);

        Endpoint result = handler.exportService(myService, bundleContext, properties, exportedInterface);
        Map<String, Object> props = result.description().getProperties();
        assertEquals(expectedAddress, props.get("org.apache.cxf.ws.address"));
        Assert.assertArrayEquals(new String[] {"org.apache.cxf.ws"}, 
                                 (String[])props.get(RemoteConstants.SERVICE_IMPORTED_CONFIGS));
        Assert.assertArrayEquals(new String[] {"java.lang.Runnable"}, 
                                 (String[])props.get(org.osgi.framework.Constants.OBJECTCLASS));
    }

    public void testCreateServerException() {
        BundleContext dswContext = EasyMock.createNiceMock(BundleContext.class);
        EasyMock.replay(dswContext);

        IntentManager intentManager = new IntentManagerImpl();

        WsProvider handler = new WsProvider() {
            @Override
            protected Endpoint createServerFromFactory(ServerFactoryBean factory, EndpointDescription epd) {
                throw new TestException();
            }
        };
        handler.setIntentManager(intentManager);
        handler.setHttpServiceManager(dummyHttpServiceManager());
        handler.activate(dswContext);

        Class[] exportedInterfaces = {Runnable.class};
        Map<String, Object> props = new HashMap<String, Object>();
        EndpointHelper.addObjectClass(props, exportedInterfaces);

        Runnable myService = EasyMock.createMock(Runnable.class);
        EasyMock.replay(myService);
        try {
            handler.exportService(myService, null, props, exportedInterfaces);
            fail("Expected TestException");
        } catch (TestException e) {
            // Expected
        } catch (RuntimeException re) {
            if (!(re.getCause() instanceof TestException)) {
                fail("Expected TestException");
            }
        }
    }

    private ServerFactoryBean createMockServerFactoryBean() {
        ReflectionServiceFactoryBean sf = EasyMock.createNiceMock(ReflectionServiceFactoryBean.class);
        EasyMock.replay(sf);

        final StringBuilder serverURI = new StringBuilder();

        ServerFactoryBean sfb = EasyMock.createNiceMock(ServerFactoryBean.class);
        Server server = createMockServer(sfb);

        EasyMock.expect(sfb.getServiceFactory()).andReturn(sf).anyTimes();
        EasyMock.expect(sfb.create()).andReturn(server);
        sfb.setAddress((String)EasyMock.anyObject());
        EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
            @Override
            public Object answer() {
                serverURI.setLength(0);
                serverURI.append(EasyMock.getCurrentArguments()[0]);
                return null;
            }
        });
        EasyMock.expect(sfb.getAddress()).andAnswer(new IAnswer<String>() {
            @Override
            public String answer() {
                return serverURI.toString();
            }
        });
        EasyMock.replay(sfb);
        return sfb;
    }

    private Server createMockServer(final ServerFactoryBean sfb) {
        AttributedURIType addr = EasyMock.createMock(AttributedURIType.class);
        EasyMock.expect(addr.getValue()).andAnswer(new IAnswer<String>() {
            @Override
            public String answer() {
                return sfb.getAddress();
            }
        });
        EasyMock.replay(addr);

        EndpointReferenceType er = EasyMock.createMock(EndpointReferenceType.class);
        EasyMock.expect(er.getAddress()).andReturn(addr);
        EasyMock.replay(er);

        Destination destination = EasyMock.createMock(Destination.class);
        EasyMock.expect(destination.getAddress()).andReturn(er);
        EasyMock.replay(destination);

        Server server = EasyMock.createNiceMock(Server.class);
        EasyMock.expect(server.getDestination()).andReturn(destination);
        EasyMock.replay(server);
        return server;
    }

    public void testCreateEndpointProps() {
        BundleContext bc = EasyMock.createNiceMock(BundleContext.class);
        EasyMock.expect(bc.getProperty("org.osgi.framework.uuid")).andReturn("some_uuid1");
        EasyMock.replay(bc);

        IntentManager intentManager = new IntentManagerImpl();
        WsProvider pch = new WsProvider();
        pch.setIntentManager(intentManager);
        pch.setHttpServiceManager(dummyHttpServiceManager());
        pch.activate(bc);
        Class<?>[] exportedInterfaces = new Class[] {String.class};
        Map<String, Object> sd = new HashMap<String, Object>();
        sd.put(org.osgi.framework.Constants.SERVICE_ID, 42);
        EndpointHelper.addObjectClass(sd, exportedInterfaces);
        List<String> intents = Arrays.asList("my_intent", "your_intent");
        EndpointDescription epd = pch.createEndpointDesc(sd, 
                                                         new String[] {"org.apache.cxf.ws"}, 
                                                         "http://localhost:12345", 
                                                         intents);

        assertEquals("http://localhost:12345", epd.getId());
        assertEquals(Arrays.asList("java.lang.String"), epd.getInterfaces());
        assertEquals(Arrays.asList("org.apache.cxf.ws"), epd.getConfigurationTypes());
        assertEquals(Arrays.asList("my_intent", "your_intent"), epd.getIntents());
        assertEquals(new Version("0.0.0"), epd.getPackageVersion("java.lang"));
    }

    public void testCreateJaxWsEndpointWithoutIntents() {
        IMocksControl c = EasyMock.createNiceControl();
        BundleContext dswBC = c.createMock(BundleContext.class);

        IntentManager intentManager = new IntentManagerImpl();
        WsProvider handler = new WsProvider();
        handler.setIntentManager(intentManager);
        handler.setHttpServiceManager(dummyHttpServiceManager());
        handler.activate(dswBC);

        Class<?>[] exportedInterfaces = new Class[] {MyJaxWsEchoService.class};
        Map<String, Object> sd = new HashMap<String, Object>();
        sd.put(WsConstants.WS_ADDRESS_PROPERTY, "/somewhere");
        EndpointHelper.addObjectClass(sd, exportedInterfaces);
        BundleContext serviceBC = c.createMock(BundleContext.class);
        Object myService = c.createMock(MyJaxWsEchoService.class);
        c.replay();

        ServerEndpoint serverWrapper = (ServerEndpoint)handler.exportService(myService, serviceBC, sd,
                exportedInterfaces);
        c.verify();

        org.apache.cxf.endpoint.Endpoint ep = serverWrapper.getServer().getEndpoint();
        QName bindingName = ep.getEndpointInfo().getBinding().getName();
        Assert.assertEquals(JaxWsEndpointImpl.class, ep.getClass());
        Assert.assertEquals(new QName("http://jaxws.handlers.dsw.dosgi.cxf.apache.org/",
                                      "MyJaxWsEchoServiceServiceSoapBinding"),
                            bindingName);
    }

    public void testCreateSimpleEndpointWithoutIntents() {
        IMocksControl c = EasyMock.createNiceControl();
        BundleContext dswBC = c.createMock(BundleContext.class);

        IntentManager intentManager = new IntentManagerImpl();
        WsProvider handler = new WsProvider();
        handler.setIntentManager(intentManager);
        handler.setHttpServiceManager(dummyHttpServiceManager());
        handler.activate(dswBC);
        Map<String, Object> sd = new HashMap<String, Object>();
        sd.put(Constants.OBJECTCLASS, new String[]{MySimpleEchoService.class.getName()});
        sd.put(WsConstants.WS_ADDRESS_PROPERTY, "/somewhere_else");
        BundleContext serviceBC = c.createMock(BundleContext.class);
        c.replay();
        Class<?>[] ifaces = new Class[] {MySimpleEchoService.class};
        MySimpleEchoServiceImpl service = new MySimpleEchoServiceImpl();
        ServerEndpoint serverWrapper = (ServerEndpoint)handler.exportService(service, serviceBC, sd, ifaces);
        c.verify();

        org.apache.cxf.endpoint.Endpoint ep = serverWrapper.getServer().getEndpoint();
        QName bindingName = ep.getEndpointInfo().getBinding().getName();
        Assert.assertEquals(EndpointImpl.class, ep.getClass());
        Assert.assertEquals(new QName("http://simple.handlers.dsw.dosgi.cxf.apache.org/",
                                      "MySimpleEchoServiceSoapBinding"),
                            bindingName);
    }

    @SuppressWarnings("serial")
    public static class TestException extends RuntimeException {
    }
}
