/*
 * 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 test;

import org.apache.felix.dm.Component;
import org.apache.felix.dm.ComponentState;
import org.apache.felix.dm.ComponentStateListener;
import org.apache.felix.dm.impl.ComponentImpl;
import org.junit.Assert;
import org.junit.Test;

/**
 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
 */
@SuppressWarnings("unused")
public class ComponentTest {
	static class MyComponent {
		public MyComponent() {
		}
	}
	
	@Test
	public void createStartAndStopComponent() {
		ComponentImpl c = new ComponentImpl();
		c.setImplementation(MyComponent.class);
		Assert.assertEquals("should not be available until started", false, c.isAvailable());
		c.start();
		Assert.assertEquals("should be available", true, c.isAvailable());
		c.stop();
		Assert.assertEquals("should no longer be available when stopped", false, c.isAvailable());
	}
	
	@Test
	public void testInitCallbackOfComponent() {
		final Ensure e = new Ensure();
		ComponentImpl c = new ComponentImpl();
		c.setImplementation(new Object() {
			void init() {
				e.step(2);
			}
            void start() {
				e.step(3);
			}
			void stop() {
				e.step(5);
			}
			void destroy() {
				e.step(6);
			}
		});
		e.step(1);
		c.start();
		e.step(4);
		c.stop();
		e.step(7);
	}

	@Test
	public void testAddDependencyFromInitCallback() {
		final Ensure e = new Ensure();
		final SimpleServiceDependency d = new SimpleServiceDependency();
		d.setRequired(true);
		ComponentImpl c = new ComponentImpl();
		c.setImplementation(new Object() {
			void init(Component c) {
				e.step(2);
				c.add(d);
			}
			void start() {
				e.step(4);
			}
			void stop() {
				e.step(6);
			}
			void destroy() {
				e.step(7);
			}
		});
		e.step(1);
		c.start();
		e.step(3);
		d.add(new EventImpl()); // NPE?!
		e.step(5);
		d.remove(new EventImpl());
		c.stop();
		e.step(8);
	}
	
    @Test
    public void testAddAvailableDependencyFromInitCallback() {
        final Ensure e = new Ensure();
        final SimpleServiceDependency d = new SimpleServiceDependency();
        d.setRequired(true);
        final SimpleServiceDependency d2 = new SimpleServiceDependency();
        d2.setRequired(true);
        ComponentImpl c = new ComponentImpl();
        c.setImplementation(new Object() {
            void init(Component c) {
                System.out.println("init");
                e.step(2);
                c.add(d);
                d.add(new EventImpl());
                c.add(d2);
            }
            void start() {
                System.out.println("start");
                e.step();
            }
            void stop() {
                System.out.println("stop");
                e.step();
            }
            void destroy() {
                System.out.println("destroy");
                e.step(7);
            }
        });
        e.step(1);
        c.start();
        e.step(3);
        d2.add(new EventImpl());
        e.step(5);
        d.remove(new EventImpl());
        c.stop();
        e.step(8);
    }
    
	@Test
	public void testAtomicallyAddMultipleDependenciesFromInitCallback() {
		final Ensure e = new Ensure();
		final SimpleServiceDependency d = new SimpleServiceDependency();
		d.setRequired(true);

		final SimpleServiceDependency d2 = new SimpleServiceDependency();
		d2.setRequired(true);

		ComponentImpl c = new ComponentImpl();
		c.setImplementation(new Object() {
			void init(Component c) {
				System.out.println("init");
				e.step(2);
				c.add(d, d2); 
				d.add(new EventImpl()); // won't trigger start because d2 is not yet available
			}
			void start() {
				System.out.println("start");
				e.step(4);
			}
			void stop() {
				System.out.println("stop");
				e.step(6);
			}
			void destroy() {
				System.out.println("destroy");
				e.step(7);
			}
		});
		e.step(1);
		c.start();
		e.step(3);
		d2.add(new EventImpl());
		e.step(5);
		d.remove(new EventImpl());
		c.stop();
		e.step(8);
	}

	@Test
	public void createComponentAddDependencyAndStartComponent() {
		ComponentImpl c = new ComponentImpl();
		c.setImplementation(MyComponent.class);
		SimpleServiceDependency d = new SimpleServiceDependency();
		d.setRequired(true);
		c.add(d);
		c.start();
		Assert.assertEquals("should not be available when started because of missing dependency", false, c.isAvailable());
		c.stop();
		c.remove(d);
	}
	
	@Test
	public void createComponentStartItAndAddDependency() {
		ComponentImpl c = new ComponentImpl();
		c.setImplementation(MyComponent.class);
		SimpleServiceDependency d = new SimpleServiceDependency();
		d.setRequired(true);
		c.start();
		Assert.assertEquals("should be available when started", true, c.isAvailable());
		c.add(d);
		Assert.assertEquals("dependency should not be available", false, d.isAvailable());
		Assert.assertEquals("Component should not be available", false, c.isAvailable());
		c.remove(d);
		c.stop();
	}
	
	@Test
	public void createComponentStartItAddDependencyAndMakeDependencyAvailable() {
		ComponentImpl c = new ComponentImpl();
		c.setImplementation(MyComponent.class);
		SimpleServiceDependency d = new SimpleServiceDependency();
		d.setRequired(true);
		c.start();
		c.add(d);
		Assert.assertEquals("Component should not be available: it is started but the dependency is not available", false, c.isAvailable());
		d.add(new EventImpl());
		Assert.assertEquals("dependency is available, component should be too", true, c.isAvailable());
		d.remove(new EventImpl());
		Assert.assertEquals("dependency is no longer available, component should not be either", false, c.isAvailable());
		c.remove(d);
		Assert.assertEquals("dependency is removed, component should be available again", true, c.isAvailable());
		c.stop();
		Assert.assertEquals("Component is stopped, should be unavailable now", false, c.isAvailable());
	}
	
	@Test
	public void createComponentStartItAddDependencyAndListenerMakeDependencyAvailableAndUnavailableImmediately() {
		ComponentImpl c = new ComponentImpl();
		c.setImplementation(MyComponent.class);
		final SimpleServiceDependency d = new SimpleServiceDependency();
		d.setRequired(true);
		ComponentStateListener l = new ComponentStateListener() {
			@Override
			public void changed(Component c, ComponentState state) {
				// make the dependency unavailable
				d.remove(new EventImpl());
			}
		};
		c.start();
		c.add(d);
		// we add a listener here which immediately triggers an 'external event' that
		// makes the dependency unavailable again as soon as it's invoked
		c.add(l);
		Assert.assertEquals("Component unavailable, dependency unavailable", false, c.isAvailable());
		// so even though we make the dependency available here, before our call returns it
		// is made unavailable again
		d.add(new EventImpl());
		Assert.assertEquals("Component *still* unavailable, because the listener immediately makes the dependency unavailable", false, c.isAvailable());
		c.remove(l);
		Assert.assertEquals("listener removed, component still unavailable", false, c.isAvailable());
		c.remove(d);
		Assert.assertEquals("dependency removed, component available", true, c.isAvailable());
		c.stop();
		Assert.assertEquals("Component stopped, should be unavailable", false, c.isAvailable());
	}
	
	@Test
	public void createComponentAddTwoDependenciesMakeBothAvailableAndUnavailable() {
		ComponentImpl c = new ComponentImpl();
		c.setImplementation(MyComponent.class);
		SimpleServiceDependency d1 = new SimpleServiceDependency();
		d1.setRequired(true);
		SimpleServiceDependency d2 = new SimpleServiceDependency();
		d2.setRequired(true);
		c.start();
		c.add(d1);
		c.add(d2);
		Assert.assertEquals("Component should be unavailable, both dependencies are too", false, c.isAvailable());
		d1.add(new EventImpl());
		Assert.assertEquals("one dependency available, component should still be unavailable", false, c.isAvailable());
		d2.add(new EventImpl());
		Assert.assertEquals("both dependencies available, component should be available", true, c.isAvailable());
		d1.remove(new EventImpl());
		Assert.assertEquals("one dependency unavailable again, component should be unavailable too", false, c.isAvailable());
		d2.remove(new EventImpl());
		Assert.assertEquals("both dependencies unavailable, component should be too", false, c.isAvailable());
		c.remove(d2);
		Assert.assertEquals("removed one dependency, still unavailable", false, c.isAvailable());
		c.remove(d1);
		Assert.assertEquals("removed the other dependency, component should be available now", true, c.isAvailable());
		c.stop();
		Assert.assertEquals("Component stopped, should be unavailable again", false, c.isAvailable());
	}

	@Test
	public void createComponentAddDependencyMakeAvailableAndUnavailableWithCallbacks() {
		final Ensure e = new Ensure();
		ComponentImpl c = new ComponentImpl();
		c.setImplementation(new Object() {
            public void add() {
				e.step(1);
			}
            public void remove() {
				e.step(3);
			}
		});
		SimpleServiceDependency d1 = new SimpleServiceDependency();
		d1.setCallbacks("add", "remove");
		d1.setRequired(true);
		// add the dependency to the component
		c.add(d1);
		// start the component
		c.start();
		// make the dependency available, we expect the add callback
		// to be invoked here
		d1.add(new EventImpl());
		e.step(2);
		// remove the dependency, should trigger the remove callback
		d1.remove(new EventImpl());
		e.step(4);
		c.stop();
		c.remove(d1);
		Assert.assertEquals("Component stopped, should be unavailable again", false, c.isAvailable());
	}
	
	@Test
	public void createAndStartComponentAddDependencyMakeAvailableAndUnavailableWithCallbacks() {
		final Ensure e = new Ensure();
		ComponentImpl c = new ComponentImpl();
		c.setImplementation(new Object() {
			public void add() {
				e.step(1);
			}
			public void remove() {
				e.step(3);
			}
		});
		SimpleServiceDependency d1 = new SimpleServiceDependency();
		d1.setCallbacks("add", "remove");
		d1.setRequired(true);
		// start the ComponentImpl (it should become available)
		c.start();
		// add the dependency (it should become unavailable)
		c.add(d1);
		// make the dependency available, which should invoke the
		// add callback
		d1.add(new EventImpl());
		e.step(2);
		// make the dependency unavailable, should trigger the
		// remove callback
		d1.remove(new EventImpl());
		e.step(4);
		c.remove(d1);
		c.stop();
		Assert.assertEquals("Component stopped, should be unavailable again", false, c.isAvailable());
	}

	@Test
	public void createComponentAddTwoDependenciesMakeBothAvailableAndUnavailableWithCallbacks() {
		final Ensure e = new Ensure();
		ComponentImpl c = new ComponentImpl();
		c.setImplementation(new Object() {
			public void add() {
				e.step();
			}
			public void remove() {
				e.step();
			}
		});
		SimpleServiceDependency d1 = new SimpleServiceDependency();
		d1.setCallbacks("add", "remove");
		d1.setRequired(true);
		SimpleServiceDependency d2 = new SimpleServiceDependency();
		d2.setCallbacks("add", "remove");
		d2.setRequired(true);
		// start the component, which should become active because there are no
		// dependencies yet
		c.start();
		// now add the dependencies, making the ComponentImpl unavailable
		c.add(d1);
		c.add(d2);
		// make the first dependency available, should have no effect on the
		// component
		d1.add(new EventImpl());
		e.step(1);
		// second dependency available, now all the add callbacks should be
		// invoked
		d2.add(new EventImpl());
		e.step(4);
		// remove the first dependency, triggering the remove callbacks
		d1.remove(new EventImpl());
		e.step(7);
		// remove the second dependency, should not trigger more callbacks
		d2.remove(new EventImpl());
		e.step(8);
		c.remove(d2);
		c.remove(d1);
		c.stop();
		// still, no more callbacks should have been invoked
		e.step(9);
		Assert.assertEquals("Component stopped, should be unavailable again", false, c.isAvailable());
	}
	
	@Test
	public void createAndStartComponentAddTwoDependenciesMakeBothAvailableAndUnavailableWithCallbacks() {
		final Ensure e = new Ensure();
		ComponentImpl c = new ComponentImpl();
		c.setImplementation(new Object() {
			public void add() {
				e.step();
			}
			public void remove() {
				e.step();
			}
		});
		// start the component, it should become available
		c.start();
		SimpleServiceDependency d1 = new SimpleServiceDependency();
		d1.setCallbacks("add", "remove");
		d1.setRequired(true);
		SimpleServiceDependency d2 = new SimpleServiceDependency();
		d2.setCallbacks("add", "remove");
		d2.setRequired(true);
		// add the first dependency, ComponentImpl should be unavailable
		c.add(d1);
		c.add(d2);
		// make first dependency available, ComponentImpl should still be unavailable
		d1.add(new EventImpl());
		e.step(1);
		// make second dependency available, ComponentImpl available, callbacks should
		// be invoked
		d2.add(new EventImpl());
		e.step(4);
		// remove the first dependency, callbacks should be invoked
		d1.remove(new EventImpl());
		e.step(7);
		// remove second dependency, no callbacks should be invoked
		d2.remove(new EventImpl());
		e.step(8);
		c.remove(d2);
		c.remove(d1);
		c.stop();
		e.step(9);
		Assert.assertEquals("Component stopped, should be unavailable again", false, c.isAvailable());
	}

	@Test
	public void createAndStartComponentAddTwoDependenciesWithMultipleServicesWithCallbacks() {
		final Ensure e = new Ensure();
		ComponentImpl c = new ComponentImpl();
		c.setImplementation(new Object() {
			public void add() {
				e.step();
			}
			public void remove() {
				e.step();
			}
		});
		// start component
		c.start();
		SimpleServiceDependency d1 = new SimpleServiceDependency();
		d1.setCallbacks("add", "remove");
		d1.setRequired(true);
		SimpleServiceDependency d2 = new SimpleServiceDependency();
		d2.setCallbacks("add", "remove");
		d2.setRequired(true);
		c.add(d1);
		c.add(d2);
		// add three instances to first dependency, no callbacks should
		// be triggered
		d1.add(new EventImpl(1));
		d1.add(new EventImpl(2));
		d1.add(new EventImpl(3));
		e.step(1);
		// add two instances to the second dependency, callbacks should
		// be invoked (4x)
		d2.add(new EventImpl(1));
		e.step(6);
		// add another dependency, triggering another callback
		d2.add(new EventImpl(2));
		e.step(8);
		// remove first dependency (all three of them) which makes the 
		// ComponentImpl unavailable so it should trigger calling remove for
		// all of them (so 5x)
		d1.remove(new EventImpl(1));
		d1.remove(new EventImpl(2));
		d1.remove(new EventImpl(3));
		e.step(14);
		// remove second dependency, should not trigger further callbacks
		d2.remove(new EventImpl(1));
		d2.remove(new EventImpl(2));
		e.step(15);
		c.remove(d2);
		c.remove(d1);
		c.stop();
		e.step(16);
		Assert.assertEquals("Component stopped, should be unavailable again", false, c.isAvailable());
	}
	
	@Test
	public void createComponentAddDependencyMakeAvailableChangeAndUnavailableWithCallbacks() {
		final Ensure e = new Ensure();
		ComponentImpl c = new ComponentImpl();
		c.setImplementation(new Object() {
			public void add() {
				e.step(1);
			}
			public void change() {
				e.step(3);
			}
			public void remove() {
				e.step(5);
			}
		});
		SimpleServiceDependency d1 = new SimpleServiceDependency();
		d1.setCallbacks("add", "change", "remove");
		d1.setRequired(true);
		// add the dependency to the component
		c.add(d1);
		// start the component
		c.start();
		// make the dependency available, we expect the add callback
		// to be invoked here
		d1.add(new EventImpl());
		e.step(2);
		// change the dependency
		d1.change(new EventImpl());
		e.step(4);
		// remove the dependency, should trigger the remove callback
		d1.remove(new EventImpl());
		e.step(6);
		c.stop();
		c.remove(d1);
		Assert.assertEquals("Component stopped, should be unavailable again", false, c.isAvailable());
	}

	@Test
	public void createComponentWithOptionalDependency() {
		final Ensure e = new Ensure();
		ComponentImpl c = new ComponentImpl();
		c.setImplementation(new Object() {
			public void add() {
				e.step(1);
			}
			public void change() {
				e.step(3);
			}
			public void remove() {
				e.step(5);
			}
		});
		SimpleServiceDependency d1 = new SimpleServiceDependency();
		d1.setCallbacks("add", "change", "remove");
		d1.setRequired(false);
		// add the dependency to the component
		c.add(d1);
		// start the component
		c.start();
		Assert.assertEquals("Component started with an optional dependency, should be available", true, c.isAvailable());
		// make the dependency available, we expect the add callback
		// to be invoked here
		d1.add(new EventImpl());
		e.step(2);
		Assert.assertEquals("Component started with an optional dependency, should be available", true, c.isAvailable());
		// change the dependency
		d1.change(new EventImpl());
		e.step(4);
		Assert.assertEquals("Component started with an optional dependency, should be available", true, c.isAvailable());
		// remove the dependency, should trigger the remove callback
		d1.remove(new EventImpl());
		Assert.assertEquals("Component started with an optional dependency, should be available", true, c.isAvailable());
		e.step(6);
		c.stop();
		c.remove(d1);
		Assert.assertEquals("Component stopped, should be unavailable again", false, c.isAvailable());
	}

	@Test
	public void createComponentWithOptionalAndRequiredDependency() {
		final Ensure e = new Ensure();
		ComponentImpl c = new ComponentImpl();
		c.setImplementation(new Object() {
			public void add() {
				e.step();
			}
			public void remove() {
				e.step();
			}
		});
		SimpleServiceDependency d1 = new SimpleServiceDependency();
		d1.setCallbacks("add", "remove");
		d1.setRequired(false);
		SimpleServiceDependency d2 = new SimpleServiceDependency();
		d2.setCallbacks("add", "remove");
		d2.setRequired(true);
		// add the dependencies to the component
		c.add(d1);
		c.add(d2);
		// start the component
		c.start();
		Assert.assertEquals("Component started with a required and optional dependency, should not be available", false, c.isAvailable());
		// make the optional dependency available
		d1.add(new EventImpl());
		e.step(1);
		Assert.assertEquals("Component should not be available", false, c.isAvailable());
		// make the required dependency available
		d2.add(new EventImpl());
		e.step(4);
		Assert.assertEquals("Component should be available", true, c.isAvailable());
		// remove the optional dependency
		d1.remove(new EventImpl());
		e.step(6);
		Assert.assertEquals("Component should be available", true, c.isAvailable());
		// remove the required dependency
		d1.remove(new EventImpl());
		e.step(8);
		Assert.assertEquals("Component should be available", true, c.isAvailable());
		c.stop();
		c.remove(d1);
		Assert.assertEquals("Component stopped, should be unavailable again", false, c.isAvailable());
	}
	
	@Test
	public void createComponentAddAvailableDependencyRemoveDependencyCheckStopCalledBeforeUnbind() {
		final Ensure e = new Ensure();
		ComponentImpl c = new ComponentImpl();
		c.setImplementation(new Object() {
			void add() {
				e.step(1);
			}
			void start() {
				e.step(2);
			}
			void stop() {
				e.step(4);
			}
			void remove() {
				e.step(5);
			}
		});
		SimpleServiceDependency d = new SimpleServiceDependency();
		d.setCallbacks("add", "remove");
		d.setRequired(true);
		// add the dependency to the component
		c.add(d);
		// start the component
		c.start();
		// make the dependency available, we expect the add callback
		// to be invoked here, then start is called.
		d.add(new EventImpl());
		e.step(3);
		// remove the dependency, should trigger the stop, then remove callback
		d.remove(new EventImpl());
		e.step(6);
		c.stop();
		c.remove(d);
		Assert.assertEquals("Component stopped, should be unavailable", false, c.isAvailable());
	}
	
	@Test
	public void createDependenciesWithCallbackInstance() {
		final Ensure e = new Ensure();
		ComponentImpl c = new ComponentImpl();
		c.setImplementation(new Object() {
			void start() {
				e.step(2);
			}
			
			void stop() {
				e.step(4);
			}
		});
		
		Object callbackInstance = new Object() {
			void add() {
				e.step(1);
			}
			
			void remove() {
				e.step(5);
			}
		};		
		
		SimpleServiceDependency d = new SimpleServiceDependency();
		d.setCallbacks(callbackInstance, "add", "remove");
		d.setRequired(true);
		// add the dependency to the component
		c.add(d);
		// start the component
		c.start();
		// make the dependency available, we expect the add callback
		// to be invoked here, then start is called.
		d.add(new EventImpl());
		e.step(3);
		// remove the dependency, should trigger the stop, then remove callback
		d.remove(new EventImpl());
		e.step(6);
		c.stop();
		c.remove(d);
		Assert.assertEquals("Component stopped, should be unavailable", false, c.isAvailable());
	}
}
