/*******************************************************************************
 * Copyright (c) 2001, 2008 IBM Corporation 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:
 *     Rational Software - initial implementation
 *******************************************************************************/
package org.eclipse.cdt.internal.ui.wizards.dialogfields;

import java.io.File;

import org.eclipse.cdt.internal.ui.wizards.NewWizardMessages;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.core.resources.IPathVariableManager;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Text;

/**
 * This class is part of the NewClassWizard.
 * It handles the Link to file part. 
 */
public class LinkToFileGroup extends StringButtonDialogField {
	protected Listener listener;
	private String initialLinkTarget;
	private int type;
	protected boolean createLink = false;

	// used to compute layout sizes
	//private FontMetrics fontMetrics;

	// widgets
	//private Composite groupComposite;
	protected Text linkTargetField;
	protected Button linkButton;
	protected Button browseButton;
	private Label resolvedPathLabelText;
	private Label resolvedPathLabelData;
	boolean preventDialogFieldChanged = false;
	
	public LinkToFileGroup(IStringButtonAdapter adapter, Listener listener) {
		super(adapter);
		this.listener = listener;
		this.type = IResource.FILE;
	}
	
	@Override
	public Control[] doFillIntoGrid(Composite parent, int nColumns) {
		assertEnoughColumns(nColumns);
		//initializeDialogUnits(parent);
		
		Label label= getLabelControl(parent);
		label.setLayoutData(gridDataForLabel(1));
			
		getLinkCheckButtonControl(parent);		

		Text text= getTextControl(parent);
		text.setLayoutData(gridDataForText(2));

		Button browseButton = getBrowseButtonControl(parent);		
		browseButton.setLayoutData(gridDataForButton(browseButton, 1));
		
		DialogField.createEmptySpace(parent);

		resolvedPathLabelText = new Label(parent, SWT.SINGLE);
		resolvedPathLabelText.setText(NewWizardMessages.CreateLinkedResourceGroup_resolvedPathLabel); 
		resolvedPathLabelText.setVisible(true);		
		
		resolvedPathLabelData = new Label(parent, SWT.SINGLE);
		GridData data = new GridData(GridData.FILL_HORIZONTAL);
		data.horizontalSpan = 3;
		resolvedPathLabelData.setLayoutData(data);
		resolvedPathLabelData.setVisible(true);
		
		return null;
	}
	
	/*
	 * @see DialogField#getNumberOfControls
	 */		
	@Override
	public int getNumberOfControls() {
		return 4;	
	}
	
	public Button getLinkCheckButtonControl(Composite parent){
		if (linkButton == null){
			linkButton = new Button(parent, SWT.CHECK);
			linkButton.setText(NewWizardMessages.NewClassWizardPage_files_linkFileButton); 
			linkButton.setSelection(createLink);
			linkButton.setFont(parent.getFont());
			SelectionListener selectionListener = new SelectionAdapter() {
				@Override
				public void widgetSelected(SelectionEvent e) {
					createLink = linkButton.getSelection();
					browseButton.setEnabled(createLink);
					linkTargetField.setEnabled(createLink);
					resolveVariable();
					if (listener != null)
						listener.handleEvent(new Event());
					if (!preventDialogFieldChanged)
						dialogFieldChanged();
				}
			};
			linkButton.addSelectionListener(selectionListener);
		}
		return linkButton;
	}
	
	@Override
	public String getText() {
		return linkTargetField.getText();
	}
	
	@Override
	public void setText(String text) {
		if (isOkToUse(linkTargetField)) {
			preventDialogFieldChanged = true;
			linkTargetField.setText(text);
			preventDialogFieldChanged = false;
		}
//		dialogFieldChanged();
	}
	
	@Override
	public Text getTextControl(Composite parent){
		if (linkTargetField == null){
			assertCompositeNotNull(parent);
			linkTargetField = new Text(parent, SWT.BORDER);
			linkTargetField.setFont(parent.getFont());
			linkTargetField.setEnabled(createLink);
			linkTargetField.addModifyListener(new ModifyListener() {
				@Override
				public void modifyText(ModifyEvent e) {
					resolveVariable();
					if (listener != null)
						listener.handleEvent(new Event());
					if (!preventDialogFieldChanged)
						dialogFieldChanged();
				}
			});
			if (initialLinkTarget != null)
				linkTargetField.setText(initialLinkTarget);
		}
		return 	linkTargetField;
	}
	
	public static GridData gridDataForText(int span){
		GridData data = new GridData();
		data.widthHint = IDialogConstants.ENTRY_FIELD_WIDTH;
		data.horizontalAlignment= GridData.FILL;
		data.grabExcessHorizontalSpace= false;
		data.horizontalSpan= span;		
		return data;
	}
	
	public Button getBrowseButtonControl(Composite parent){
		// browse button
		if (browseButton == null){
			assertCompositeNotNull(parent);
			browseButton = new Button(parent, SWT.PUSH);
			//setButtonLayoutData(browseButton);
			browseButton.setFont(parent.getFont());
			browseButton.setText(NewWizardMessages.CreateLinkedResourceGroup_browseButton); 
			browseButton.addSelectionListener(new SelectionAdapter() {
				@Override
				public void widgetSelected(SelectionEvent event) {
					handleLinkTargetBrowseButtonPressed();
				}
			});
			browseButton.setEnabled(createLink);
		}
		return browseButton;
	}

	/**
	 * Returns a new status object with the given severity and message.
	 * 
	 * @return a new status object with the given severity and message.
	 */
	private IStatus createStatus(int severity, String message) {
		return new Status(
			severity,
			CUIPlugin.getPluginId(),
			severity,
			message,	
			null);
	}	
	/**
	 * Returns the link target location entered by the user. 
	 *
	 * @return the link target location entered by the user. null if the user
	 * 	chose not to create a link.
	 */
	public String getLinkTarget() {
		if (createLink && linkTargetField != null && linkTargetField.isDisposed() == false)
			return linkTargetField.getText();

		return null;
	}

	public String getResolvedPath() {
		if (createLink && resolvedPathLabelData != null && resolvedPathLabelData.isDisposed() == false)
			return resolvedPathLabelData.getText();

		return null;
	}

	/**
	 * Opens a file or directory browser depending on the link type.
	 */
	protected void handleLinkTargetBrowseButtonPressed() {
		String linkTargetName = linkTargetField.getText();
		File file = null;
		String selection = null;
	
		if ("".equals(linkTargetName) == false) {	//$NON-NLS-1$
			file = new File(linkTargetName);
			if (file.exists() == false)
				file = null;
		}
		if (type == IResource.FILE) {
			FileDialog dialog = new FileDialog(linkTargetField.getShell());
			dialog.setText(NewWizardMessages.CreateLinkedResourceGroup_open); 
			if (file != null) {
				if (file.isFile())
					dialog.setFileName(linkTargetName);
				else
					dialog.setFilterPath(linkTargetName);
			}
			selection = dialog.open();		
		}
		else {
			DirectoryDialog dialog = new DirectoryDialog(linkTargetField.getShell());
			dialog.setText(NewWizardMessages.CreateLinkedResourceGroup_open); 
			if (file != null) {
				if (file.isFile())
					linkTargetName = file.getParent();
				if (linkTargetName != null)
					dialog.setFilterPath(linkTargetName);
			}
			dialog.setMessage(NewWizardMessages.CreateLinkedResourceGroup_targetSelectionLabel); 
			selection = dialog.open();
		}					
		if (selection != null) {
			linkTargetField.setText(selection);
			if (!preventDialogFieldChanged)
				dialogFieldChanged();
		}
	}
	/**
	 * Tries to resolve the value entered in the link target field as 
	 * a variable, if the value is a relative path.
	 * Displays the resolved value if the entered value is a variable.
	 */
	protected void resolveVariable() {
		if (!linkTargetField.isEnabled()) {
			resolvedPathLabelData.setText(""); //$NON-NLS-1$
			return;
		}
			
		IPathVariableManager pathVariableManager = ResourcesPlugin.getWorkspace().getPathVariableManager();
		IPath path = new Path(linkTargetField.getText());
		IPath resolvedPath = pathVariableManager.resolvePath(path);
	
		resolvedPathLabelData.setText(resolvedPath.toOSString());
	}
	/**
	 * Sets the value of the link target field
	 * 
	 * @param target the value of the link target field
	 */
	public void setLinkTarget(String target) {
		initialLinkTarget = target;
		if (linkTargetField != null && linkTargetField.isDisposed() == false) {
			linkTargetField.setText(target);
			if (!preventDialogFieldChanged)
				dialogFieldChanged();
		}
	}
	/**
	 * Validates the type of the given file against the link type specified
	 * in the constructor.
	 * 
	 * @param linkTargetFile file to validate
	 * @return IStatus indicating the validation result. IStatus.OK if the 
	 * 	given file is valid.
	 */
	private IStatus validateFileType(File linkTargetFile) {
		if (type == IResource.FILE && linkTargetFile.isFile() == false) {
			return createStatus(
				IStatus.ERROR,
				NewWizardMessages.CreateLinkedResourceGroup_linkTargetNotFile);	
		} else if (type == IResource.FOLDER && linkTargetFile.isDirectory() == false) {
			return createStatus(
				IStatus.ERROR,
				NewWizardMessages.CreateLinkedResourceGroup_linkTargetNotFolder);	
		}
		return createStatus(IStatus.OK, ""); //$NON-NLS-1$
	}
	/**
	 * Validates this page's controls.
	 *
	 * @return IStatus indicating the validation result. IStatus.OK if the 
	 * 	specified link target is valid given the linkHandle.
	 */
	public IStatus validateLinkLocation(IResource linkHandle) {
		if (linkTargetField == null || linkTargetField.isDisposed())
			return createStatus(IStatus.OK, "");	//$NON-NLS-1$
	
		IWorkspace workspace = ResourcesPlugin.getWorkspace();
		String linkTargetName = linkTargetField.getText();
		IPath path = new Path(linkTargetName);
	
		if (createLink == false)
			return createStatus(IStatus.OK, ""); //$NON-NLS-1$

		IStatus locationStatus = workspace.validateLinkLocation(linkHandle,	path);
		if (locationStatus.getSeverity() == IStatus.ERROR)
			return locationStatus;

		// use the resolved link target name
		linkTargetName = resolvedPathLabelData.getText();
		path = new Path(linkTargetName);
		File linkTargetFile = new Path(linkTargetName).toFile();
		if (linkTargetFile.exists()) {
			IStatus fileTypeStatus = validateFileType(linkTargetFile);
			if (fileTypeStatus.isOK() == false)
				return fileTypeStatus;
		} else if (locationStatus.getSeverity() == IStatus.OK) {
			// locationStatus takes precedence over missing location warning.
			return createStatus(
				IStatus.WARNING,
				NewWizardMessages.CreateLinkedResourceGroup_linkTargetNonExistent);	
		}
		return locationStatus;
	}
	
	public boolean linkCreated (){
		return createLink;
	}
}
