/*
 * 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.felix.dm.lambda.itest;

import static org.apache.felix.dm.lambda.DependencyManagerActivator.aspect;
import static org.apache.felix.dm.lambda.DependencyManagerActivator.component;

import java.util.ArrayList;
import java.util.List;

import org.apache.felix.dm.Component;
import org.apache.felix.dm.DependencyManager;
import org.junit.Assert;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;

/**
 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
 */
public class AspectBaseTest extends TestBase {    

	public void testSingleAspect() {
	    DependencyManager m = getDM();
        // helper class that ensures certain steps get executed in sequence
        Ensure e = new Ensure();
        
        // create a service provider and consumer
        ServiceProvider p = new ServiceProvider(e, "a");
        ServiceConsumer c = new ServiceConsumer(e);
        
        Component sp = component(m).impl(p).provides(ServiceInterface.class).properties(name -> "a").build();
        Component sc = component(m).impl(c).withSvc(ServiceInterface.class, srv -> srv.add("add").remove("remove").autoConfig("m_service")).build();
        Component sa = aspect(m, ServiceInterface.class).rank(20).impl(ServiceAspect.class).build();
            
        m.add(sc);
        m.add(sp);
        // after the provider was added, the consumer's add should have been invoked once
        e.waitForStep(1, 2000);
        Assert.assertEquals("a", c.invoke());
        m.add(sa);
        // after the aspect was added, the consumer should get and add for the aspect and a remove
        // for the original service
        e.waitForStep(3, 2000);
        Assert.assertEquals("aa", c.invoke());
        m.remove(sa);
        // removing the aspect again should give a remove and add
        e.waitForStep(5, 2000);
        Assert.assertEquals("a", c.invoke());
        m.remove(sp);
        // finally removing the original service should give a remove
        e.waitForStep(6, 2000);
        m.remove(sc);
        e.step(7);
        clearComponents();
    }
    
    public void testSingleAspectRef() {
        DependencyManager m = getDM();
        // helper class that ensures certain steps get executed in sequence
        Ensure e = new Ensure();
        
        // create a service provider and consumer
        ServiceProvider p = new ServiceProvider(e, "a");
        ServiceConsumer c = new ServiceConsumer(e);
        
        Component sp = component(m).impl(p).provides(ServiceInterface.class).properties(name -> "a").build();        
        Component sc = component(m)
            .impl(c).withSvc(ServiceInterface.class, srv -> srv.add(c::addRef).remove(c::removeRef).autoConfig("m_service")).build();
        Component sa = aspect(m, ServiceInterface.class).rank(20).impl(ServiceAspect.class).build();
        
        m.add(sc);
        m.add(sp);
        // after the provider was added, the consumer's add should have been invoked once
        e.waitForStep(1, 2000);
        Assert.assertEquals("a", c.invoke());
        m.add(sa);
        // after the aspect was added, the consumer should get and add for the aspect and a remove
        // for the original service
        e.waitForStep(3, 2000);
        Assert.assertEquals("aa", c.invoke());
        m.remove(sa);
        // removing the aspect again should give a remove and add
        e.waitForStep(5, 2000);
        Assert.assertEquals("a", c.invoke());
        m.remove(sp);
        // finally removing the original service should give a remove
        e.waitForStep(6, 2000);
        m.remove(sc);
        e.step(7);
        clearComponents();
    }
    
    @SuppressWarnings("serial")
    public void testSingleAspectThatAlreadyExisted() {
        DependencyManager m = new DependencyManager(context);
        // helper class that ensures certain steps get executed in sequence
        Ensure e = new Ensure();
        
        // create a service provider and consumer
        ServiceProvider p = new ServiceProvider(e, "a");
        ServiceConsumer c = new ServiceConsumer(e);
        Component sp = component(m).impl(p).provides(ServiceInterface.class).properties(name -> "a").build();            
        Component sc = component(m).impl(c).withSvc(ServiceInterface.class, srv -> srv.add("add").remove("remove").autoConfig("m_service")).build();
        Component sa = aspect(m, ServiceInterface.class).rank(20).impl(ServiceAspect.class).build();

        // we first add the aspect
        m.add(sa);
        // then the service provider
        m.add(sp);
        // finally the consumer
        m.add(sc);

        Assert.assertEquals("aa", c.invoke());
        
        // now the consumer's added should be invoked once, as the aspect is already available and should
        // directly hide the original service
        e.waitForStep(1, 2000);
        e.step(2);

        m.remove(sa);
        // after removing the aspect, the consumer should get the original service back, so
        // remove and add will be invoked
        e.waitForStep(4, 2000);
        
        Assert.assertEquals("a", c.invoke());
        
        m.remove(sp);
        // after removing the original service, the consumer's remove should be called once
        e.waitForStep(5, 2000);
        
        m.remove(sc);
        e.step(6);
    }

    public void testSingleAspectThatAlreadyExistedRef() {
        DependencyManager m = new DependencyManager(context);
        // helper class that ensures certain steps get executed in sequence
        Ensure e = new Ensure();
        
        // create a service provider and consumer
        ServiceProvider p = new ServiceProvider(e, "a");
        ServiceConsumer c = new ServiceConsumer(e);
        
        Component sp = component(m).impl(p).provides(ServiceInterface.class).properties(name -> "a").build();
        Component sc = component(m).impl(c).withSvc(ServiceInterface.class, srv -> srv.add(c::addRef).remove(c::removeRef).autoConfig("m_service")).build();
        Component sa = aspect(m, ServiceInterface.class).rank(20).impl(ServiceAspect.class).build();

        // we first add the aspect
        m.add(sa);
        // then the service provider
        m.add(sp);
        // finally the consumer
        m.add(sc);

        Assert.assertEquals("aa", c.invoke());
        
        // now the consumer's added should be invoked once, as the aspect is already available and should
        // directly hide the original service
        e.waitForStep(1, 2000);
        e.step(2);

        m.remove(sa);
        // after removing the aspect, the consumer should get the original service back, so
        // remove and add will be invoked
        e.waitForStep(4, 2000);
        
        Assert.assertEquals("a", c.invoke());
        
        m.remove(sp);
        // after removing the original service, the consumer's remove should be called once
        e.waitForStep(5, 2000);
        
        m.remove(sc);
        e.step(6);
    }

    public void testMultipleAspects() {
        DependencyManager m = new DependencyManager(context);
        // helper class that ensures certain steps get executed in sequence
        Ensure e = new Ensure();
        
        // create service providers and consumers
        ServiceConsumer c = new ServiceConsumer(e);
        Component sp = component(m).impl(new ServiceProvider(e, "a")).provides(ServiceInterface.class).properties(name -> "a").build();
        Component sp2 = component(m).impl(new ServiceProvider(e, "b")).provides(ServiceInterface.class).properties(name -> "b").build();
        Component sc = component(m).impl(c).withSvc(ServiceInterface.class, srv -> srv.add("add").remove("remove")).build();

        Component sa = aspect(m, ServiceInterface.class).rank(20).impl(ServiceAspect.class).build();
        Component sa2 = aspect(m, ServiceInterface.class).rank(10).impl(ServiceAspect.class).build();

        m.add(sp);
        m.add(sp2);
        m.add(sa);
        m.add(sa2);
        m.add(sc);
        // the consumer will monitor progress, it should get it's add invoked twice, once for every
        // (highest) aspect
        e.waitForStep(2, 2000);
        e.step(3);
        
        // now invoke all services the consumer collected
        List<String> list = c.invokeAll();
        // and make sure both of them are correctly invoked
        Assert.assertTrue(list.size() == 2);
        Assert.assertTrue(list.contains("aaa"));
        Assert.assertTrue(list.contains("bbb"));
        
        m.remove(sc);
        // removing the consumer now should get its removed method invoked twice
        e.waitForStep(5, 2000);
        e.step(6);
        m.remove(sa2);
        m.remove(sa);
        m.remove(sp2);
        m.remove(sp);
        e.step(7);
    }
    
    public void testMultipleAspectsRef() {
        DependencyManager m = new DependencyManager(context);
        // helper class that ensures certain steps get executed in sequence
        Ensure e = new Ensure();
        
        // create service providers and consumers
        ServiceConsumer c = new ServiceConsumer(e);
        Component sp = component(m).impl(new ServiceProvider(e, "a")).provides(ServiceInterface.class).properties(name -> "a").build();
        Component sp2 = component(m).impl(new ServiceProvider(e, "b")).provides(ServiceInterface.class).properties(name -> "b").build();
        Component sc = component(m).impl(c).withSvc(ServiceInterface.class, srv -> srv.add(c::addRef).remove(c::removeRef)).build();

        Component sa = aspect(m, ServiceInterface.class).rank(20).impl(ServiceAspect.class).build();
        Component sa2 = aspect(m, ServiceInterface.class).rank(10).impl(ServiceAspect.class).build();

        m.add(sp);
        m.add(sp2);
        m.add(sa);
        m.add(sa2);
        m.add(sc);
        // the consumer will monitor progress, it should get it's add invoked twice, once for every
        // (highest) aspect
        e.waitForStep(2, 2000);
        e.step(3);
        
        // now invoke all services the consumer collected
        List<String> list = c.invokeAll();
        // and make sure both of them are correctly invoked
        Assert.assertTrue(list.size() == 2);
        Assert.assertTrue(list.contains("aaa"));
        Assert.assertTrue(list.contains("bbb"));
        
        m.remove(sc);
        // removing the consumer now should get its removed method invoked twice
        e.waitForStep(5, 2000);
        e.step(6);
        m.remove(sa2);
        m.remove(sa);
        m.remove(sp2);
        m.remove(sp);
        e.step(7);
    }
    
    public static interface ServiceInterface {
        public String invoke(String input);
    }
    
    public static class ServiceProvider implements ServiceInterface {
        private final Ensure m_ensure;
        private final String m_name;
        public ServiceProvider(Ensure e, String name) {
            m_ensure = e;
            m_name = name;
        }
        public String invoke(String input) {
            return input + m_name;
        }
    }
    
    public static class ServiceAspect implements ServiceInterface {
        private volatile ServiceInterface m_originalService;
        private volatile ServiceRegistration m_registration;
        
        public String invoke(String input) {
            String result = m_originalService.invoke(input);
            String property = (String) m_registration.getReference().getProperty("name");
            return result + property;
        }
    }
    
    public static class ServiceConsumer {
        private final Ensure m_ensure;
        private volatile ServiceInterface m_service;
        private List<ServiceInterface> m_services = new ArrayList<ServiceInterface>();

        public ServiceConsumer(Ensure e) {
            m_ensure = e;
        }
        
        public void addRef(ServiceInterface si, ServiceReference<ServiceInterface> ref) { // method ref callback
            add(ref, si);
        }
        
        public void add(ServiceReference<ServiceInterface> ref, ServiceInterface si) { // reflection callback
            System.out.println("add: " + ServiceUtil.toString(ref));
            m_services.add(si);
            m_ensure.step();
        }
        
        public void removeRef(ServiceInterface si, ServiceReference<ServiceInterface> ref) { // method ref callback
            remove(ref, si);
        }
        
        public void remove(ServiceReference<ServiceInterface> ref, ServiceInterface si) { // reflection callback
            System.out.println("rem: " + ServiceUtil.toString(ref));
            m_services.remove(si);
            m_ensure.step();
        }
        
        public String invoke() {
            return m_service.invoke("");
        }
        
        public List<String> invokeAll() {
            List<String> results = new ArrayList<String>();
            for (ServiceInterface si : m_services) {
                results.add(si.invoke(""));
            }
            return results;
        }
    }
}
