/*******************************************************************************
* Copyright (c) 2006 IONA Technologies PLC
* 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:
*     IONA Technologies PLC - initial API and implementation
*******************************************************************************/
package org.eclipse.stp.sc.common.utils;

import org.eclipse.core.filebuffers.FileBuffers;
import org.eclipse.core.filebuffers.ITextFileBufferManager;
import org.eclipse.core.filebuffers.LocationKind;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.jdt.internal.corext.CorextMessages;
import org.eclipse.jdt.internal.corext.ValidateEditException;
import org.eclipse.jdt.internal.corext.util.Resources;
import org.eclipse.jdt.internal.ui.JavaUIStatus;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.RewriteSessionEditProcessor;
import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.TextEdit;

/**
 * help class to apply changes to the current editor instead of reset the buffer
 * on compiliation unit
 * @author jma
 *
 */
public class TextEditorHelper {

	public static void applyRewrite(ICompilationUnit cu, ASTRewrite rewrite) 
	    throws MalformedTreeException, JavaModelException, IllegalArgumentException {
		applyRewrite(cu, rewrite, false);
	}
	
	public static void applyRewrite(ICompilationUnit cu, ASTRewrite rewrite, boolean save) 
	    throws MalformedTreeException, JavaModelException, IllegalArgumentException {
		MultiTextEdit edit = new MultiTextEdit();
    	edit.addChild(rewrite.rewriteAST());
        try {
			applyEdit(cu, edit, save, null);
		} catch (ValidateEditException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (CoreException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
    /**
 	 * Applies an text edit to a compilation unit. Filed bug 117694 against jdt.core. 
 	 * 	@param cu the compilation unit to apply the edit to
 	 * 	@param edit the edit to apply
 	 * @param save is set, save the CU after the edit has been applied
 	 * @param monitor the progress monitor to use
 	 * @throws CoreException Thrown when the access to the CU failed
 	 * @throws ValidateEditException if validate edit fails
 	 */	
 	public static void applyEdit(ICompilationUnit cu, TextEdit edit, boolean save, IProgressMonitor monitor) throws CoreException, ValidateEditException {
 		if (monitor == null) {
 			monitor= new NullProgressMonitor();
 		}
 		monitor.beginTask(CorextMessages.JavaModelUtil_applyedit_operation, 3); 

 		try {
 			IDocument document= null;
 			try {
 				document= aquireDocument(cu, new SubProgressMonitor(monitor, 1));
 				if (save) {
 					commitDocument(cu, document, edit, new SubProgressMonitor(monitor, 1));
 				} else {
 					new RewriteSessionEditProcessor(document, edit, TextEdit.UPDATE_REGIONS).performEdits();
 				}
 			} catch (BadLocationException e) {
 				throw new CoreException(JavaUIStatus.createError(IStatus.ERROR, e));
 			} finally {
 				releaseDocument(cu, document, new SubProgressMonitor(monitor, 1));
 			}
 		} finally {
 			monitor.done();
 		}		
 	}

 	private static IDocument aquireDocument(ICompilationUnit cu, IProgressMonitor monitor) throws CoreException {
 		if (isPrimary(cu)) {
 			IFile file= (IFile) cu.getResource();
 			if (file.exists()) {
 				ITextFileBufferManager bufferManager= FileBuffers.getTextFileBufferManager();
 				IPath path= cu.getPath();
 				bufferManager.connect(path, LocationKind.IFILE, monitor);
 				return bufferManager.getTextFileBuffer(path, LocationKind.IFILE).getDocument();
 			}
 		}
 		monitor.done();
 		return new Document(cu.getSource());
 	}
 	
 	private static void commitDocument(ICompilationUnit cu, IDocument document, TextEdit edit, IProgressMonitor monitor) throws CoreException, MalformedTreeException, BadLocationException {
 		if (isPrimary(cu)) {
 			IFile file= (IFile) cu.getResource();
 			if (file.exists()) {
 				IStatus status= Resources.makeCommittable(file, null);
 				if (!status.isOK()) {
 					throw new ValidateEditException(status);
 				}
 				new RewriteSessionEditProcessor(document, edit, TextEdit.UPDATE_REGIONS).performEdits(); // apply after file is commitable
 				
 				ITextFileBufferManager bufferManager= FileBuffers.getTextFileBufferManager();
 				bufferManager.getTextFileBuffer(file.getFullPath(), LocationKind.IFILE).commit(monitor, true);
 				return;
 			}
 		}
 		// no commit possible, make sure changes are in
 		new RewriteSessionEditProcessor(document, edit, TextEdit.UPDATE_REGIONS).performEdits();
 	}

 	
 	
 	private static void releaseDocument(ICompilationUnit cu, IDocument document, IProgressMonitor monitor) throws CoreException {
 		if (isPrimary(cu)) {
 			IFile file= (IFile) cu.getResource();
 			if (file.exists()) {
 				ITextFileBufferManager bufferManager= FileBuffers.getTextFileBufferManager();
 				bufferManager.disconnect(file.getFullPath(), LocationKind.IFILE, monitor);
 				return;
 			}
 		}
 		cu.getBuffer().setContents(document.get());
 		monitor.done();
 	}
 	
 	public static boolean isPrimary(ICompilationUnit cu) {
		return cu.getOwner() == null;
	}
}
