/******************************************************************************
 * Copyright (c) 2006, 2010 VMware Inc.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and Apache License v2.0 which accompanies this distribution. 
 * The Eclipse Public License is available at 
 * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
 * is available at http://www.opensource.org/licenses/apache2.0.php.
 * You may elect to redistribute this code under either of these licenses. 
 * 
 * Contributors:
 *   VMware Inc.
 *****************************************************************************/

package org.eclipse.gemini.blueprint.blueprint.container;

import java.awt.Point;
import java.util.LinkedList;
import java.util.List;
import java.util.TreeMap;

import org.osgi.service.blueprint.container.Converter;
import org.osgi.service.blueprint.container.ReifiedType;

/**
 * @author Costin Leau
 */
public class GenericConverter implements Converter {

	public Object convert(Object s, ReifiedType type) throws Exception {
		switch (type.size()) {
		// we should only be getting called for things we've already vetted,
		// so we can take some short cuts.
		case 1: {
			Class<?> targetType = type.getRawClass();
			// we only handle LinkedList<Point>, and only from an array of ints.
			if (targetType == LinkedList.class) {
				LinkedList result = new LinkedList();
				int[] source = (int[]) s;

				int counter = 0;
				while (counter < source.length) {
					Point p = new Point(source[counter], source[counter + 1]);
					result.add(p);
					counter += 2;
				}

				return result;
			} else if (targetType == GenericHolder.class) {
				Class<?> listType = type.getActualTypeArgument(0).getRawClass();
				GenericHolder source = (GenericHolder) s;
				// this just validates the type
				if (listType.isInstance(source.getTarget())) {
					return source;
				}
			}
		}
		case 2: {
			TreeMap result = new TreeMap();
			List source = (List) s;

			int counter = 0;
			while (counter < source.size()) {
				String index = (String) source.get(counter);
				int x = Integer.parseInt((String) source.get(counter + 1));
				int y = Integer.parseInt((String) source.get(counter + 2));

				Point p = new Point(x, y);
				result.put(index, p);
				counter += 3;
			}

			return result;
		}
		}
		// we're supposed to throw an exception if we can't convert
		throw new Exception("Unconvertable object type");
	}

	public boolean canConvert(Object source, ReifiedType type) {
		switch (type.size()) {
		case 0:
			return false;
			// probably a collection type with a target. We only handle some
			// very specific conversions here.
		case 1: {
			Class<?> targetType = type.getRawClass();
			// we only handle LinkedList<Point>, and only from an array of ints.
			if (targetType == LinkedList.class) {
				Class<?> listType = type.getActualTypeArgument(0).getRawClass();
				if (!(listType == Point.class)) {
					return false;
				}

				// the only source we handle is an array of ints with even size
				if (source instanceof int[] && (((int[]) source).length % 2) == 0) {
					return true;
				}
				return false;
			}
			// this is our generic type class. Check for convertability also
			else if (targetType == GenericHolder.class) {
				// all we do is handle the held value
				return source instanceof GenericHolder;
			}

			return false;
		}
		case 2: {
			Class<?> targetType = type.getRawClass();
			// we only handle TreeMap<String, Point>, and only from a List of triplet values
			if (targetType != TreeMap.class) {
				return false;
			}
			Class<?> indexType = type.getActualTypeArgument(0).getRawClass();
			if (indexType != String.class) {
				return false;
			}

			Class<?> itemType = type.getActualTypeArgument(1).getRawClass();
			if (itemType != Point.class) {
				return false;
			}

			// the only source we handle is a list of values with a size that's
			// a multiple of 3.
			if (source instanceof List && (((List) source).size() % 3) == 0) {
				return true;
			}

			return false;
		}
		default:
			// don't understand this
			return false;
		}
	}
}