/*******************************************************************************
 * 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.internal.context.tasks.ui;

import java.io.File;

import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.mylyn.context.core.AbstractContextListener;
import org.eclipse.mylyn.context.core.ContextChangeEvent;
import org.eclipse.mylyn.context.core.ContextCore;
import org.eclipse.mylyn.context.core.IInteractionContext;
import org.eclipse.mylyn.internal.context.core.ContextCorePlugin;
import org.eclipse.mylyn.internal.monitor.ui.MonitorUiPlugin;
import org.eclipse.mylyn.internal.tasks.core.ITasksCoreConstants;
import org.eclipse.mylyn.internal.tasks.core.externalization.AbstractExternalizationParticipant;
import org.eclipse.mylyn.internal.tasks.core.externalization.ExternalizationManager;
import org.eclipse.mylyn.internal.tasks.core.externalization.IExternalizationContext;
import org.eclipse.mylyn.internal.tasks.ui.Messages;
import org.eclipse.mylyn.monitor.ui.IUserAttentionListener;
import org.eclipse.mylyn.tasks.core.ITask;
import org.eclipse.mylyn.tasks.core.ITaskActivityListener;
import org.eclipse.mylyn.tasks.ui.TasksUi;

/**
 * This externalization participant only handles saving the active context periodically. No snapshots are taken and task
 * activation and deactivation control the load and final write of the context in InteractionContextManager.
 * 
 * @author Shawn Minto
 */
@SuppressWarnings("restriction")
public class ActiveContextExternalizationParticipant extends AbstractExternalizationParticipant implements
		ITaskActivityListener, IUserAttentionListener {
	private boolean isDirty = false;

	private final ExternalizationManager manager;

	private long lastUpdate;

	private IInteractionContext currentlyActiveContext;

	private final AbstractContextListener listener = new AbstractContextListener() {
		@Override
		public void contextChanged(ContextChangeEvent event) {
			switch (event.getEventKind()) {
			case ACTIVATED:
				currentlyActiveContext = event.getContext();
				break;
			case DEACTIVATED:
				currentlyActiveContext = null;
				setDirty(false);
				break;
			}
		}
	};

	public ActiveContextExternalizationParticipant(ExternalizationManager manager) {
		this.manager = manager;
	}

	public void registerListeners() {
		ContextCore.getContextManager().addListener(listener);
		TasksUi.getTaskActivityManager().addActivityListener(this);
		MonitorUiPlugin.getDefault().getActivityContextManager().addListener(this);
		currentlyActiveContext = ContextCore.getContextManager().getActiveContext();
	}

	// currently not called since no way to remove a participant
	public void dispose() {
		ContextCore.getContextManager().removeListener(listener);
		TasksUi.getTaskActivityManager().removeActivityListener(this);
		if (MonitorUiPlugin.getDefault().getActivityContextManager() != null) {
			(MonitorUiPlugin.getDefault().getActivityContextManager()).removeListener(this);
		}
	}

	@Override
	public void execute(IExternalizationContext context, IProgressMonitor monitor) throws CoreException {
		Assert.isNotNull(context);
		switch (context.getKind()) {
		case SAVE:
			if (shouldWriteContext()) {
				setDirty(false);
				ContextCorePlugin.getContextManager().saveContext(currentlyActiveContext);
			}
			break;
		case LOAD:
			// ignore loads since we will do this synchronously with task activation
			break;
		case SNAPSHOT:
			// ignore snapshots
			break;
		}
	}

	@Override
	public String getDescription() {
		return Messages.ActiveContextExternalizationParticipant_Active_Task_Context;
	}

	@Override
	public ISchedulingRule getSchedulingRule() {
		return ITasksCoreConstants.ACTIVE_CONTEXT_SCHEDULING_RULE;
	}

	@Override
	public boolean isDirty() {
		return isDirty(false);
	}

	@Override
	public boolean isDirty(boolean full) {
		synchronized (this) {
			return isDirty || (full && shouldWriteContext());
		}
	}

	public void setDirty(boolean dirty) {
		synchronized (this) {
			isDirty = dirty;
		}
	}

	@Override
	public String getFileName() {
		// ignore
		return null;
	}

	@Override
	public void load(File sourceFile, IProgressMonitor monitor) throws CoreException {
		// ignore see execute method
	}

	@Override
	public void save(File targetFile, IProgressMonitor monitor) throws CoreException {
		// ignore see execute method
	}

	public void elapsedTimeUpdated(ITask task, long newElapsedTime) {
		if (System.currentTimeMillis() - lastUpdate > 1000 * 60 * 3) {
			// TODO check if context is dirty
			setDirty(shouldWriteContext());
			if (isDirty()) {
				manager.requestSave();
			}
			lastUpdate = System.currentTimeMillis();
		}
	}

	private boolean shouldWriteContext() {
		if (ContextCorePlugin.getContextManager() != null && currentlyActiveContext != null
				&& currentlyActiveContext.getAllElements().size() > 0) {
			// we could add a check here for whether there were changes to the context
			return true;
		}
		return false;
	}

	public void activityReset() {
		// ignore
	}

	public void userAttentionGained() {
		// ignore
	}

	public void userAttentionLost() {
		setDirty(shouldWriteContext());
		if (isDirty()) {
			manager.requestSave();
		}
		lastUpdate = System.currentTimeMillis();
	}

}
