/*
 * 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.tracker;

import static org.junit.Assert.assertArrayEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

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

import org.apache.felix.dm.DependencyManager;
import org.apache.felix.dm.tracker.ServiceTracker.Tracked;
import org.junit.Test;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceReference;

/**
 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
 */
@SuppressWarnings("rawtypes")
public class TrackedTest {

	@Test
	public void testSetInitialHideAspects() {
		System.out.println("testSetInitialHideAspects");
		TestCustomizer customizer = new TestCustomizer();
		
		ServiceTracker tracker = new TestTracker(customizer);
		tracker.open();
		Tracked tracked = tracker.getTracked();

		Object[] initialReferences = new Object[] {
				createServiceReference(1L),
				createServiceReference(2L, 1L, 10),
				createServiceReference(3L),
				createServiceReference(4L, 1L, 5),
				createServiceReference(5L, 3L, 5),
		};
		tracked.setInitial(initialReferences);
		tracked.trackInitial();
		tracked.getExecutor().execute();
		assertArrayEquals(new Long[] { 2L, 5L }, customizer.getServiceReferenceIds());
	}
	
	@Test
	public void testUnHideAspect() {
		System.out.println("testUnhideAspect");
		TestCustomizer customizer = new TestCustomizer();
		
		ServiceTracker tracker = new TestTracker(customizer);
		tracker.open();
		Tracked tracked = tracker.getTracked();
		
		ServiceReference<?>[] initialReferences = new ServiceReference[] {
				createServiceReference(1L),
				createServiceReference(2L, 1L, 10),
				createServiceReference(3L),
				createServiceReference(4L, 1L, 5),
				createServiceReference(5L, 3L, 5),
		};
		tracked.setInitial(initialReferences);
		tracked.trackInitial();
		tracked.getExecutor().execute();
		assertArrayEquals(new Long[] { 2L, 5L }, customizer.getServiceReferenceIds());
		
		// create a service event that unregisters service with id 2, we would expect it to be swapped with 4.
		ServiceEvent event = new ServiceEvent(ServiceEvent.UNREGISTERING, initialReferences[1]);
		tracked.serviceChanged(event);
		assertArrayEquals(new Long[] { 5L, 4L }, customizer.getServiceReferenceIds());
		// create a service event that unregisters service with id 4, we would expect it to be swapped with 1.
		event = new ServiceEvent(ServiceEvent.UNREGISTERING, initialReferences[3]);
		tracked.serviceChanged(event);
		assertArrayEquals(new Long[] { 5L, 1L }, customizer.getServiceReferenceIds());
	}	
	
	@Test
	public void testHideAspect() {
		System.out.println("testHideAspect");
		TestCustomizer customizer = new TestCustomizer();
		
		ServiceTracker tracker = new TestTracker(customizer);
		tracker.open();
		Tracked tracked = tracker.getTracked();
		
		ServiceReference<?>[] initialReferences = new ServiceReference[] {
				createServiceReference(1L),
				createServiceReference(2L, 1L, 10),
				createServiceReference(3L),
				createServiceReference(4L, 1L, 5),
				createServiceReference(5L, 3L, 5),
		};
		tracked.setInitial(initialReferences);
		tracked.trackInitial();
		tracked.getExecutor().execute();
		assertArrayEquals(new Long[] { 2L, 5L }, customizer.getServiceReferenceIds());
		
		// create a service event that registers another but lower ranked aspect for service with id 1. 
		ServiceReference<?> newReference = createServiceReference(6L, 1L, 8);
		ServiceEvent event = new ServiceEvent(ServiceEvent.REGISTERED, newReference);
		tracked.serviceChanged(event);
		assertArrayEquals(new Long[] { 2L, 5L }, customizer.getServiceReferenceIds());
		
		// create a service event that unregisters service with id 2, we would expect it to be swapped with 6.
		event = new ServiceEvent(ServiceEvent.UNREGISTERING, initialReferences[1]);
		tracked.serviceChanged(event);
		assertArrayEquals(new Long[] { 5L, 6L }, customizer.getServiceReferenceIds());
		
		// create a service event that unregisters service with id 6, we would expect it to be swapped with 4.
		event = new ServiceEvent(ServiceEvent.UNREGISTERING, newReference);
		tracked.serviceChanged(event);
		assertArrayEquals(new Long[] { 5L, 4L }, customizer.getServiceReferenceIds());	
		
		// create a service event that registers a higher ranked aspect for service with id 1.
		ServiceReference<?> higherRankedReference = createServiceReference(7L, 1L, 15);
		ServiceEvent addHigherRankedEvent = new ServiceEvent(ServiceEvent.REGISTERED, higherRankedReference);
		tracked.serviceChanged(addHigherRankedEvent);
		assertArrayEquals(new Long[] { 5L, 7L }, customizer.getServiceReferenceIds());	
	}		
	
	@Test
	public void testSetInitialTrackAspects() {
		System.out.println("testSetInitialTrackAspects");
		TestCustomizer customizer = new TestCustomizer();
		
		ServiceTracker tracker = new TestTracker(customizer);
		tracker.open(false, true);
		Tracked tracked = tracker.getTracked();
		
		Object[] initialReferences = new Object[] {
				createServiceReference(1L),
				createServiceReference(2L, 1L, 10),
				createServiceReference(3L, 1L, 5)
		};
		tracked.setInitial(initialReferences);
		tracked.trackInitial();
		tracked.getExecutor().execute();
		assertArrayEquals(new Long[] { 1L, 2L, 3L }, customizer.getServiceReferenceIds());
	}	
	
	private static BundleContext createBundleContext() {
		BundleContext context = mock(BundleContext.class);
		when(context.getProperty(Constants.FRAMEWORK_VERSION)).thenReturn(null);
		return context;
	}
	
	private ServiceReference<?> createServiceReference(Long serviceId) {
		return createServiceReference(serviceId, null, null);
	}

	private ServiceReference<?> createServiceReference(Long serviceId, Long aspectId, Integer ranking) {
		return new TestServiceReference(serviceId, aspectId, ranking);
	}

	class TestTracker extends ServiceTracker {

		public TestTracker(ServiceTrackerCustomizer customizer) {
			super(createBundleContext(), "(objectClass=*)", customizer);
		}
		
	}
	
	class TestCustomizer implements ServiceTrackerCustomizer {
		
		List<ServiceReference<?>> serviceReferences = new ArrayList<>();

		@Override
		public Object addingService(ServiceReference reference) {
			System.out.println("adding service: " + reference);
			return new Object();
		}

		@Override
		public void addedService(ServiceReference reference, Object service) {
			System.out.println("added service: " + reference);
			serviceReferences.add(reference);
		}

		@Override
		public void modifiedService(ServiceReference reference, Object service) {
			System.out.println("modified service: " + reference);
		}

		@Override
		public void swappedService(ServiceReference reference, Object service,
				ServiceReference newReference, Object newService) {
			System.out.println("swapped service: " + reference);
			serviceReferences.remove(reference);
			serviceReferences.add(newReference);
		}

		@Override
		public void removedService(ServiceReference reference, Object service) {
			System.out.println("removed service: " + reference);
			serviceReferences.remove(reference);
		}
		
		public Long[] getServiceReferenceIds() {
			Long[] ids = new Long[serviceReferences.size()];
			for (int i = 0; i < serviceReferences.size(); i++) {
				ids[i] = (Long) serviceReferences.get(i).getProperty(Constants.SERVICE_ID);
			}
			return ids;
		}
		
	}
	
	class TestServiceReference implements ServiceReference {
		
		Properties props = new Properties();

		public TestServiceReference(Long serviceId, Long aspectId,
				Integer ranking) {
			props.put(Constants.SERVICE_ID, serviceId);
			if (aspectId != null) {
				props.put(DependencyManager.ASPECT, aspectId);
			}
			if (ranking != null) {
				props.put(Constants.SERVICE_RANKING, ranking);
			}
		}

		@Override
		public Object getProperty(String key) {
			return props.get(key);
		}

		@Override
		public String[] getPropertyKeys() {
			return props.keySet().toArray(new String[]{});
		}

		@Override
		public Bundle getBundle() {
			return null;
		}

		@Override
		public Bundle[] getUsingBundles() {
			return null;
		}

		@Override
		public boolean isAssignableTo(Bundle bundle, String className) {
			return false;
		}

		@Override
		public int compareTo(Object reference) // Kindly borrowed from the Apache Felix ServiceRegistrationImpl.ServiceReferenceImpl
        {
            ServiceReference other = (ServiceReference) reference;

            Long id = (Long) getProperty(Constants.SERVICE_ID);
            Long otherId = (Long) other.getProperty(Constants.SERVICE_ID);

            if (id.equals(otherId))
            {
                return 0; // same service
            }

            Object rankObj = getProperty(Constants.SERVICE_RANKING);
            Object otherRankObj = other.getProperty(Constants.SERVICE_RANKING);

            // If no rank, then spec says it defaults to zero.
            rankObj = (rankObj == null) ? new Integer(0) : rankObj;
            otherRankObj = (otherRankObj == null) ? new Integer(0) : otherRankObj;

            // If rank is not Integer, then spec says it defaults to zero.
            Integer rank = (rankObj instanceof Integer)
                ? (Integer) rankObj : new Integer(0);
            Integer otherRank = (otherRankObj instanceof Integer)
                ? (Integer) otherRankObj : new Integer(0);

            // Sort by rank in ascending order.
            if (rank.compareTo(otherRank) < 0)
            {
                return -1; // lower rank
            }
            else if (rank.compareTo(otherRank) > 0)
            {
                return 1; // higher rank
            }

            // If ranks are equal, then sort by service id in descending order.
            return (id.compareTo(otherId) < 0) ? 1 : -1;
        }

		@Override
		public String toString() {
			return "TestServiceReference [props=" + props + "]";
		}

	}
	
}
