/*******************************************************************************
 * Copyright (c) 2000, 2004 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.ui.internal.ide.dialogs;

import java.text.MessageFormat;

import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Preferences;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.preference.PreferencePage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.*;
import org.eclipse.ui.IWorkbenchPreferencePage;
import org.eclipse.ui.help.WorkbenchHelp;
import org.eclipse.ui.internal.ide.IHelpContextIds;
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
/**
 * The FileStatesPage is the page used to set the file states sizes for the workbench.
 */
public class FileStatesPage
	extends PreferencePage
	implements IWorkbenchPreferencePage, Listener {

	private static final String LONGEVITY_TITLE = IDEWorkbenchMessages.getString("FileHistory.longevity"); //$NON-NLS-1$
	private static final String MAX_FILE_STATES_TITLE = IDEWorkbenchMessages.getString("FileHistory.entries"); //$NON-NLS-1$
	private static final String MAX_FILE_STATE_SIZE_TITLE = IDEWorkbenchMessages.getString("FileHistory.diskSpace"); //$NON-NLS-1$
	private static final String POSITIVE_MESSAGE = IDEWorkbenchMessages.getString("FileHistory.mustBePositive"); //$NON-NLS-1$
	private static final String INVALID_VALUE_MESSAGE = IDEWorkbenchMessages.getString("FileHistory.invalid"); //$NON-NLS-1$
	private static final String SAVE_ERROR_MESSAGE = IDEWorkbenchMessages.getString("FileHistory.exceptionSaving"); //$NON-NLS-1$
	private static final String NOTE_MESSAGE = IDEWorkbenchMessages.getString("FileHistory.restartNote"); //$NON-NLS-1$
	private static final String NOTE_LABEL = IDEWorkbenchMessages.getString("Preference.note"); //$NON-NLS-1$

	private static final int FAILED_VALUE = -1;

	//Set the length of the day as we have to convert back and forth
	private static final long DAY_LENGTH = 86400000;
	private static final long MEGABYTES = 1024 * 1024;

	private Text longevityText;
	private Text maxStatesText;
	private Text maxStateSizeText;

	//Choose a maximum to prevent OutOfMemoryErrors
	private int FILE_STATES_MAXIMUM = 10000;
	private long STATE_SIZE_MAXIMUM = 100;

	/**
	 * This method takes the string for the title of a text field and the value for the
	 * text of the field.
	 * @return org.eclipse.swt.widgets.Text
	 * @param labelString java.lang.String
	 * @param textValue java.lang.String
	 * @param parent Composite 
	 */
	private Text addLabelAndText(
		String labelString,
		String textValue,
		Composite parent) {
		Label label = new Label(parent, SWT.LEFT);
		label.setText(labelString);

		Text text = new Text(parent, SWT.LEFT | SWT.BORDER);
		GridData data = new GridData();
		text.addListener(SWT.Modify, this);
		data.horizontalAlignment = GridData.FILL;
		data.grabExcessHorizontalSpace = true;
		data.verticalAlignment = GridData.CENTER;
		data.grabExcessVerticalSpace = false;
		text.setLayoutData(data);
		text.setText(textValue);
		return text;
	}
	/**
	 * Recomputes the page's error state by validating all
	 * the fields.
	 */
	private void checkState() {
		// Assume invalid if the controls not created yet
		if (longevityText == null
			|| maxStatesText == null
			|| maxStateSizeText == null) {
			setValid(false);
			return;
		}

		if (validateLongTextEntry(longevityText) == FAILED_VALUE) {
			setValid(false);
			return;
		}

		if (validateMaxFileStates() == FAILED_VALUE) {
			setValid(false);
			return;
		}

		if (validateMaxFileStateSize() == FAILED_VALUE) {
			setValid(false);
			return;
		}

		setValid(true);
		setErrorMessage(null);
	}
	/* 
	* Create the contents control for the workspace file states.
	* @returns Control
	* @param parent Composite
	*/

	protected Control createContents(Composite parent) {

		WorkbenchHelp.setHelp(
			parent,
			IHelpContextIds.FILE_STATES_PREFERENCE_PAGE);

		// button group
		Composite composite = new Composite(parent, SWT.NONE);
		GridLayout layout = new GridLayout();
		layout.numColumns = 2;
		composite.setLayout(layout);

		IWorkspaceDescription description = getWorkspaceDescription();

		//Get the current value and make sure we get at least one day out of it.
		long days = description.getFileStateLongevity() / DAY_LENGTH;
		if (days < 1)
			days = 1;

		long megabytes = description.getMaxFileStateSize() / MEGABYTES;
		if (megabytes < 1)
			megabytes = 1;

		this.longevityText =
			addLabelAndText(LONGEVITY_TITLE, String.valueOf(days), composite);
		this.maxStatesText =
			addLabelAndText(
				MAX_FILE_STATES_TITLE,
				String.valueOf(description.getMaxFileStates()),
				composite);
		this.maxStateSizeText =
			addLabelAndText(
				MAX_FILE_STATE_SIZE_TITLE,
				String.valueOf(megabytes),
				composite);

		checkState();

		//Create a spacing label to breakup the note from the fields
		Label spacer = new Label(composite, SWT.NONE);
		GridData spacerData = new GridData();
		spacerData.horizontalSpan = 2;
		spacer.setLayoutData(spacerData);

		Composite noteComposite =
			createNoteComposite(
				parent.getFont(),
				composite,
				NOTE_LABEL,
				NOTE_MESSAGE);
		GridData noteData = new GridData();
		noteData.horizontalSpan = 2;
		noteComposite.setLayoutData(noteData);
		
		applyDialogFont(composite);

		return composite;
	}
	/**
	 * Get the Workspace Description this page is operating on.
	 * @return org.eclipse.core.resources.IWorkspaceDescription
	 */
	private IWorkspaceDescription getWorkspaceDescription() {
		return ResourcesPlugin.getWorkspace().getDescription();
	}
	/**
	 * Sent when an event that the receiver has registered for occurs.
	 *
	 * @param event the event which occurred
	 */
	public void handleEvent(Event event) {
		checkState();
	}
	/**
	 * Initializes this preference page for the given workbench.
	 * <p>
	 * This method is called automatically as the preference page is being created
	 * and initialized. Clients must not call this method.
	 * </p>
	 *
	 * @param workbench the workbench
	 */
	public void init(org.eclipse.ui.IWorkbench workbench) {
	}
	/**
	 * Performs special processing when this page's Defaults button has been pressed.
	 * Reset the entries to thier default values.
	 */
	protected void performDefaults() {
		super.performDefaults();

		Preferences prefs = ResourcesPlugin.getPlugin().getPluginPreferences();

		long days =
			prefs.getDefaultLong(ResourcesPlugin.PREF_FILE_STATE_LONGEVITY)
				/ DAY_LENGTH;
		long megabytes =
			prefs.getDefaultLong(ResourcesPlugin.PREF_MAX_FILE_STATE_SIZE)
				/ MEGABYTES;
		this.longevityText.setText(String.valueOf(days));
		this.maxStatesText.setText(
			prefs.getDefaultString(ResourcesPlugin.PREF_MAX_FILE_STATES));
		this.maxStateSizeText.setText(String.valueOf(megabytes));
		checkState();
	}
	/** 
	 * Perform the result of the OK from the receiver.
	 */
	public boolean performOk() {

		long longevityValue = validateLongTextEntry(longevityText);
		int maxFileStates = validateMaxFileStates();
		long maxStateSize = validateMaxFileStateSize();
		if (longevityValue == FAILED_VALUE
			|| maxFileStates == FAILED_VALUE
			|| maxStateSize == FAILED_VALUE)
			return false;

		IWorkspaceDescription description = getWorkspaceDescription();
		description.setFileStateLongevity(longevityValue * DAY_LENGTH);
		description.setMaxFileStates(maxFileStates);
		description.setMaxFileStateSize(maxStateSize * MEGABYTES);

		try {
			//As it is only a copy save it back in
			ResourcesPlugin.getWorkspace().setDescription(description);
		} catch (CoreException exception) {
			ErrorDialog.openError(
				getShell(),
				SAVE_ERROR_MESSAGE,
				exception.getMessage(),
				exception.getStatus());
			return false;
		}

		return true;

	}
	/**
	 * Validate a text entry for an integer field. Return the result if there are
	 * no errors, otherwise return -1 and set the entry field error. 
	 * @return int
	 */
	private int validateIntegerTextEntry(Text text) {

		int value;

		try {
			value = Integer.parseInt(text.getText());

		} catch (NumberFormatException exception) {
			setErrorMessage(
				MessageFormat.format(
					INVALID_VALUE_MESSAGE,
					new Object[] { exception.getLocalizedMessage()}));
			return FAILED_VALUE;
		}

		//Be sure all values are non zero and positive
		if (value <= 0) {
			setErrorMessage(POSITIVE_MESSAGE);
			return FAILED_VALUE;
		}

		return value;
	}
	/**
	 * Validate a text entry for a long field. Return the result if there are
	 * no errors, otherwise return -1 and set the entry field error. 
	 * @return long
	 */
	private long validateLongTextEntry(Text text) {

		long value;

		try {
			value = Long.parseLong(text.getText());

		} catch (NumberFormatException exception) {
			setErrorMessage(
				MessageFormat.format(
					INVALID_VALUE_MESSAGE,
					new Object[] { exception.getLocalizedMessage()}));
			return FAILED_VALUE;
		}

		//Be sure all values are non zero and positive
		if (value <= 0) {
			setErrorMessage(POSITIVE_MESSAGE);
			return FAILED_VALUE;
		}

		return value;
	}

	/**
	 * Validate the maximum file states.
	 * Return the value if successful, otherwise
	 * return FAILED_VALUE.
	 * Set the error message if it fails.
	 * @return int
	 */
	private int validateMaxFileStates() {
		int maxFileStates = validateIntegerTextEntry(this.maxStatesText);
		if (maxFileStates == FAILED_VALUE)
			return maxFileStates;

		if (maxFileStates > FILE_STATES_MAXIMUM) {
			setErrorMessage(
				IDEWorkbenchMessages.format(
					"FileHistory.aboveMaxEntries", //$NON-NLS-1$
					new String[] { String.valueOf(FILE_STATES_MAXIMUM)}));
			return FAILED_VALUE;
		}

		return maxFileStates;
	}

	/**
	 * Validate the maximum file state size.
	 * Return the value if successful, otherwise
	 * return FAILED_VALUE.
	 * Set the error message if it fails.
	 * @return long
	 */
	private long validateMaxFileStateSize() {
		long maxFileStateSize = validateLongTextEntry(this.maxStateSizeText);
		if (maxFileStateSize == FAILED_VALUE)
			return maxFileStateSize;

		if (maxFileStateSize > STATE_SIZE_MAXIMUM) {
			setErrorMessage(
				IDEWorkbenchMessages.format(
					"FileHistory.aboveMaxFileSize", //$NON-NLS-1$
					new String[] { String.valueOf(STATE_SIZE_MAXIMUM)}));
			return FAILED_VALUE;
		}

		return maxFileStateSize;
	}

}
