/*******************************************************************************
 * Copyright (c) 2004, 2010 Tasktop Technologies and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Tasktop Technologies - initial API and implementation
 *******************************************************************************/

package org.eclipse.mylyn.tasks.tests;

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

import junit.framework.TestCase;

import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.tasks.core.data.TaskAttachmentMapper;
import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
import org.eclipse.mylyn.tasks.core.data.TaskAttributeMapper;
import org.eclipse.mylyn.tasks.core.data.TaskCommentMapper;
import org.eclipse.mylyn.tasks.core.data.TaskData;
import org.eclipse.mylyn.tasks.core.data.TaskMapper;
import org.eclipse.mylyn.tasks.tests.connector.MockRepositoryConnector;

/**
 * @author Steffen Pingel
 */
public class TaskMapperTest extends TestCase {

	private StubTaskAttributeMapper mapper;

	private TaskMapper source;

	private TaskMapper target;

	private TaskRepository taskRepository;

	@Override
	protected void setUp() throws Exception {
		taskRepository = new TaskRepository(MockRepositoryConnector.CONNECTOR_KIND,
				MockRepositoryConnector.REPOSITORY_URL);
		mapper = new StubTaskAttributeMapper(taskRepository);
		source = new TaskMapper(new TaskData(mapper, "kind", "http://url", "1"), true);
		target = new TaskMapper(new TaskData(mapper, "kind", "http://url", "2"), true);
	}

	public void testTaskSchema() {
		source.setReporter("reporter");

		TaskAttribute attribute = source.getTaskData().getRoot().getAttribute(TaskAttribute.USER_REPORTER);
		assertNotNull(attribute);
		assertEquals("reporter", attribute.getValue());
		assertEquals("Reporter", attribute.getMetaData().getLabel());
		assertEquals(TaskAttribute.TYPE_PERSON, attribute.getMetaData().getType());
	}

	public void testTaskAttachmentMapperSchema() {
		TaskAttribute attachmentAttribute = mapper.createTaskAttachment(source.getTaskData());
		TaskAttachmentMapper mapper = new TaskAttachmentMapper();
		mapper.setAuthor(taskRepository.createPerson("reporter"));
		mapper.applyTo(attachmentAttribute);

		TaskAttribute attribute = attachmentAttribute.getAttribute(TaskAttribute.ATTACHMENT_AUTHOR);
		assertNotNull(attribute);
		assertEquals("reporter", attribute.getValue());
		assertEquals("Author", attribute.getMetaData().getLabel());
		assertEquals(TaskAttribute.TYPE_PERSON, attribute.getMetaData().getType());
	}

	public void testTaskCommentMapperSchema() {
		TaskAttribute attachmentAttribute = mapper.createTaskAttachment(source.getTaskData());
		TaskCommentMapper mapper = new TaskCommentMapper();
		mapper.setAuthor(taskRepository.createPerson("reporter"));
		mapper.applyTo(attachmentAttribute);

		TaskAttribute attribute = attachmentAttribute.getAttribute(TaskAttribute.COMMENT_AUTHOR);
		assertNotNull(attribute);
		assertEquals("reporter", attribute.getValue());
		assertEquals("Author", attribute.getMetaData().getLabel());
		assertEquals(TaskAttribute.TYPE_PERSON, attribute.getMetaData().getType());
	}

	public void testCloneTaskCloneCommonAttributes() {
		source.setDescription("sourceDescription");
		target.setDescription("");
		target.merge(source);
		assertEquals("sourceDescription", target.getDescription());
		assertEquals(null, target.getSummary());

		source.setSummary("sourceSummary");
		target.setSummary("");
		target.merge(source);
		assertEquals("sourceSummary", target.getSummary());
	}

	public void testCloneTaskDataAttributeWithValues() {
		source.getTaskData().getRoot().createAttribute("key1").addValue("value1");
		target.merge(source);
		assertEquals(null, target.getTaskData().getRoot().getAttribute("key1"));

		target.getTaskData().getRoot().createAttribute("key1").addValue("value2");
		target.merge(source);
		assertEquals("value1", target.getTaskData().getRoot().getAttribute("key1").getValue());

		TaskAttribute attribute = source.getTaskData().getRoot().createAttribute("multi");
		attribute.addValue("v1");
		attribute.addValue("v2");
		target.getTaskData().getRoot().createAttribute("multi");
		target.merge(source);
		assertEquals("value1", target.getTaskData().getRoot().getAttribute("key1").getValue());
		List<String> values = target.getTaskData().getRoot().getAttribute("multi").getValues();
		assertEquals(2, values.size());
		assertEquals("v1", values.get(0));
		assertEquals("v2", values.get(1));
	}

	public void testCloneTaskDataAttributeWithOptions() {
		TaskAttribute sourceAttribute = source.getTaskData().getRoot().createAttribute("key");
		sourceAttribute.setValue("o2");
		sourceAttribute.putOption("o1", "");
		sourceAttribute.putOption("o2", "");
		target.getTaskData().getRoot().createAttribute("key");
		target.merge(source);
		assertEquals("o2", target.getTaskData().getRoot().getAttribute("key").getValue());

		// test target with options that don't contain value
		TaskAttribute targetAttribute = target.getTaskData().getRoot().getAttribute("key");
		targetAttribute.putOption("o3", "");
		target.merge(source);
		assertEquals("", target.getTaskData().getRoot().getAttribute("key").getValue());

		// test target with options that contain value
		targetAttribute.putOption("o2", "");
		target.merge(source);
		assertEquals("o2", target.getTaskData().getRoot().getAttribute("key").getValue());

		// test multiple values
		sourceAttribute.addValue("o3");
		target.merge(source);
		List<String> values = targetAttribute.getValues();
		assertEquals(2, values.size());
		assertEquals("o2", values.get(0));
		assertEquals("o3", values.get(1));
	}

	public void testCloneTaskDifferentRepositoryTypesCloneCommonAttributes() {
		target = new TaskMapper(new TaskData(mapper, "otherkind", "http://url", "2"), true);

		source.setDescription("sourceDescription");
		target.setDescription("");
		target.merge(source);
		assertEquals("sourceDescription", target.getDescription());
		assertEquals(null, target.getSummary());

		source.setSummary("sourceSummary");
		target.merge(source);
		assertEquals("sourceSummary", target.getSummary());
	}

	public void testCloneTaskDifferentRepositoryTypesCloneMappedAttribues() {
		StubTaskAttributeMapper targetMapper = new StubTaskAttributeMapper(taskRepository);
		target = new TaskMapper(new TaskData(targetMapper, "otherkind", "http://url", "2"), true);

		// key is not part of common schema
		source.getTaskData().getRoot().createAttribute("key").setValue("source");
		target.getTaskData().getRoot().createAttribute("key").setValue("target");
		target.merge(source);
		assertEquals("target", target.getTaskData().getRoot().getAttribute("key").getValue());

		// map key in source factory only
		mapper.attributeMap.put(TaskAttribute.COMPONENT, "key");
		target.merge(source);
		assertEquals("target", target.getTaskData().getRoot().getAttribute("key").getValue());

		// map key in target factory to different key
		targetMapper.attributeMap.put(TaskAttribute.PRODUCT, "key");
		target.merge(source);
		assertEquals("target", target.getTaskData().getRoot().getAttribute("key").getValue());

		// map key in both factories
		targetMapper.attributeMap.put(TaskAttribute.COMPONENT, "key");
		target.merge(source);
		assertEquals("source", target.getTaskData().getRoot().getAttribute("key").getValue());
	}

	public void testNoCreationOfAttributes() {
		target = new TaskMapper(new TaskData(mapper, "otherkind", "http://url", "2"));
		target.setDescription("abc");
		assertNull(target.getTaskData().getRoot().getAttribute(TaskAttribute.DESCRIPTION));
		assertEquals(0, target.getTaskData().getRoot().getAttributes().size());

		target = new TaskMapper(new TaskData(mapper, "otherkind", "http://url", "2"), false);
		target.setDescription("abc");
		assertNull(target.getTaskData().getRoot().getAttribute(TaskAttribute.DESCRIPTION));
		assertEquals(0, target.getTaskData().getRoot().getAttributes().size());
	}

	private class StubTaskAttributeMapper extends TaskAttributeMapper {

		public StubTaskAttributeMapper(TaskRepository taskRepository) {
			super(taskRepository);
		}

		private final Map<String, String> attributeMap = new HashMap<String, String>();

		@Override
		public String mapToRepositoryKey(TaskAttribute parent, String key) {
			String mappedKey = attributeMap.get(key);
			return (mappedKey != null) ? mappedKey : key;
		}

	}

}
