package com.redhat.ceylon.eclipse.code.refactor;

import static com.redhat.ceylon.compiler.typechecker.tree.Util.formatPath;
import static com.redhat.ceylon.eclipse.core.builder.CeylonBuilder.getProjectTypeChecker;

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

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.CompositeChange;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.TextFileChange;
import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
import org.eclipse.ltk.core.refactoring.participants.RenameParticipant;
import org.eclipse.ltk.core.refactoring.participants.RenameProcessor;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.ReplaceEdit;

import com.redhat.ceylon.compiler.typechecker.TypeChecker;
import com.redhat.ceylon.compiler.typechecker.context.PhasedUnit;
import com.redhat.ceylon.compiler.typechecker.tree.Tree.ImportPath;
import com.redhat.ceylon.compiler.typechecker.tree.Visitor;
import com.redhat.ceylon.eclipse.core.vfs.IFileVirtualFile;

public class RenamePackageRefactoringParticipant extends RenameParticipant {

	private IPackageFragment javaPackageFragment;
	
	private static Map<IPackageFragment,String> allPackagesMoving = new HashMap<IPackageFragment,String>();

    @Override
	protected boolean initialize(Object element) {
		javaPackageFragment= (IPackageFragment) element;
		final String newName = getArguments().getNewName();
		allPackagesMoving.put(javaPackageFragment, newName);
		return getProcessor() instanceof RenameProcessor &&
		        getProjectTypeChecker(javaPackageFragment.getJavaProject().getProject())!=null;
	}

    @Override
	public String getName() {
		return "Rename participant for Ceylon source";
	}
	
    @Override
	public RefactoringStatus checkConditions(IProgressMonitor pm, CheckConditionsContext context) {
		return new RefactoringStatus();
	}

	@Override
	public Change createChange(IProgressMonitor pm) throws CoreException {
		
		final String newName = getArguments().getNewName();
		final String oldName = javaPackageFragment.getElementName();
        final IProject project = javaPackageFragment.getJavaProject().getProject();
		
        final List<Change> changes = new ArrayList<Change>();
        TypeChecker tc = getProjectTypeChecker(project);
        if (tc==null) return null;
		for (PhasedUnit phasedUnit: tc.getPhasedUnits().getPhasedUnits()) {
            
            final List<ReplaceEdit> edits = new ArrayList<ReplaceEdit>();
            phasedUnit.getCompilationUnit().visit(new Visitor() {
                @Override
                public void visit(ImportPath that) {
                    super.visit(that);
                    if (formatPath(that.getIdentifiers()).equals(oldName)) {
                        edits.add(new ReplaceEdit(that.getStartIndex(), 
                                oldName.length(), newName));
                    }
                }
            });
            
            if (!edits.isEmpty()) {
                try {
                    final IFile file = ((IFileVirtualFile) phasedUnit.getUnitFile()).getFile();
                    IFile movedFile = getMovedFile(file);
                    TextFileChange change= new MovingTextFileChange(movedFile.getName(), movedFile, file);
                    change.setEdit(new MultiTextEdit());
                    for (ReplaceEdit edit: edits) {
                        change.addEdit(edit);
                    }
                    changes.add(change);
                }       
                catch (Exception e) { 
                    e.printStackTrace(); 
                }
            }
            
        }
                
		if (changes.isEmpty()) {
			return null;
		}
		else {
		    CompositeChange result = new CompositeChange("Ceylon source changes") {
		        @Override
		        public Change perform(IProgressMonitor pm) throws CoreException {
		            allPackagesMoving.clear();
		            return super.perform(pm);
		        }
		    };
		    for (Change change: changes) {
		        result.add(change);
		    }
		    return result;
		}
	}
	
	private static IFile getMovedFile(IFile file) {
	    for (Map.Entry<IPackageFragment,String> e: allPackagesMoving.entrySet()) {
	        IPackageFragment javaPackageFragment = e.getKey();
	        String newName = e.getValue();
	        String oldPath = javaPackageFragment.getElementName().replace('.', '/');
	        String newPath = newName.replace('.', '/');
	        IPath pathInSourceFolder = file.getParent().getProjectRelativePath()
	                .removeFirstSegments(1); //TODO: lame, it assumes a the source folder belongs directly to the project
	        if (pathInSourceFolder.toPortableString().equals(oldPath)) {
	            return file.getProject().getFile(file.getParent().getProjectRelativePath()
	                    .removeLastSegments(pathInSourceFolder.segmentCount())
	                    .append(newPath).append(file.getName()));
	        }
	    }
	    return file;
	}
}
@@ -572,24 +572,106 @@
 geFragment;%0A
+import org.eclipse.jdt.internal.corext.refactoring.rename.RenamePackageProcessor;%0A
 import org.e
@@ -955,16 +955,91 @@
 ontext;%0A
+import org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor;%0A
 import o
@@ -1106,78 +1106,8 @@
 nt;%0A
-import org.eclipse.ltk.core.refactoring.participants.RenameProcessor;%0A
 impo
@@ -1905,16 +1905,456 @@
 Name();%0A
+%09%09RefactoringProcessor processor = getProcessor();%0A%09%09if (processor instanceof RenamePackageProcessor) %7B%0A%09%09%09RenamePackageProcessor renamePackageProcessor = (RenamePackageProcessor) processor;%0A%09%09%09if (renamePackageProcessor.getUpdateQualifiedNames() &&%0A%09%09%09%09%09(renamePackageProcessor.getFilePatterns().equals(%22*%22) %7C%7C%0A%09%09%09%09%09renamePackageProcessor.getFilePatterns().contains(%22*.ceylon%22))) %7B%0A%09%09%09%09return false;%0A%09%09%09%7D%0A%09%09%7D%0A%09%09else %7B%0A%09%09%09return false;%0A%09%09%7D%0A
 %09%09allPac
@@ -2413,63 +2413,8 @@
 urn 
-getProcessor() instanceof RenameProcessor &&%0A%09%09        
 getP

fix #777