/*
* Copyright 2015 Igor Maznitsa.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.igormaznitsa.nbmindmap.nb.refactoring.elements;
import com.igormaznitsa.mindmap.model.MMapURI;
import com.igormaznitsa.mindmap.model.MindMap;
import com.igormaznitsa.mindmap.model.logger.Logger;
import com.igormaznitsa.mindmap.model.logger.LoggerFactory;
import com.igormaznitsa.nbmindmap.nb.refactoring.RefactoringUtils;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import org.netbeans.api.fileinfo.NonRecursiveFolder;
import org.netbeans.api.java.source.TreePathHandle;
import org.netbeans.api.project.FileOwnerQuery;
import org.netbeans.api.project.Project;
import org.netbeans.modules.refactoring.api.AbstractRefactoring;
import org.netbeans.modules.refactoring.api.Problem;
import org.netbeans.modules.refactoring.api.RenameRefactoring;
import org.netbeans.modules.refactoring.api.Scope;
import org.netbeans.modules.refactoring.spi.ProgressProviderAdapter;
import org.netbeans.modules.refactoring.spi.RefactoringElementImplementation;
import org.netbeans.modules.refactoring.spi.RefactoringElementsBag;
import org.netbeans.modules.refactoring.spi.RefactoringPlugin;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.util.Lookup;
public abstract class AbstractPlugin<T extends AbstractRefactoring> extends ProgressProviderAdapter implements RefactoringPlugin {
protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractPlugin.class);
protected final T refactoring;
protected static final ResourceBundle BUNDLE = ResourceBundle.getBundle("com/igormaznitsa/nbmindmap/i18n/Bundle");
private final Map<FileObject, Collection<FileObject>> cache = new HashMap<FileObject, Collection<FileObject>>();
private final List<RefactoringElementImplementation> elements = new ArrayList<RefactoringElementImplementation>();
private final AtomicBoolean canceled = new AtomicBoolean(false);
public AbstractPlugin(final T refactoring) {
super();
this.refactoring = refactoring;
}
protected void addElement(final RefactoringElementImplementation element) {
synchronized (this.elements) {
this.elements.add(element);
}
}
protected Collection<FileObject> allMapsInProject(final Project project) {
final Collection<? extends Scope> scopes = this.refactoring.getRefactoringSource().lookupAll(Scope.class);
if (!scopes.isEmpty()) {
final Collection<FileObject> mindMaps = new HashSet<FileObject>();
for (final Scope s : scopes) {
for (final NonRecursiveFolder f : s.getFolders()) {
synchronized (this.cache) {
Collection<FileObject> found = this.cache.get(f.getFolder());
if (found == null) {
found = RefactoringUtils.findAllMindMapsInFolder(f,this);
this.cache.put(f.getFolder(), found);
}
mindMaps.addAll(found);
}
}
}
return mindMaps;
}
else {
if (project == null) {
return Collections.<FileObject>emptyList();
}
final FileObject projectFolder = project.getProjectDirectory();
synchronized (this.cache) {
Collection<FileObject> result = this.cache.get(projectFolder);
if (result == null) {
result = RefactoringUtils.findAllMindMapsInProject(project, this);
this.cache.put(projectFolder, result);
}
return result;
}
}
}
private Collection<? extends FileObject> findFileObjectInLookup(final Lookup lookup) {
final Collection<? extends FileObject> files = lookup.lookupAll(FileObject.class);
final Collection<? extends NonRecursiveFolder> folders = lookup.lookupAll(NonRecursiveFolder.class);
final Set<FileObject> result = new HashSet<FileObject>();
for (final NonRecursiveFolder f : folders) {
result.add(f.getFolder());
}
result.addAll(files);
final Collection<? extends TreePathHandle> treePaths = lookup.lookupAll(TreePathHandle.class);
for (final TreePathHandle h : treePaths) {
result.add(h.getFileObject());
}
return result;
}
@Override
public Problem checkParameters() {
return null;
}
@Override
public Problem preCheck() {
return null;
}
@Override
public Problem fastCheckParameters() {
return null;
}
@Override
public final Problem prepare(final RefactoringElementsBag session) {
if (isCanceled()) {
return null;
}
final Collection<? extends FileObject> files = findFileObjectInLookup(this.refactoring.getRefactoringSource());
fireProgressListenerStart(RenameRefactoring.PREPARE, files.size());
Problem result = null;
try {
for (final FileObject fileObject : findFileObjectInLookup(this.refactoring.getRefactoringSource())) {
if (isCanceled()) {
return null;
}
if (result != null) {
break;
}
final Project project = FileOwnerQuery.getOwner(fileObject);
result = processFileObject(project, fileObject);
fireProgressListenerStep(1);
}
}
finally {
synchronized (this.elements) {
LOGGER.info("Detected " + this.elements.size() + " elements for refactoring");
if (!isCanceled()) {
session.addAll(refactoring, this.elements);
}
}
fireProgressListenerStop();
}
return result;
}
public Problem processFileObject(final Project project, final FileObject fileObject) {
return _processFileObject(project, 0, fileObject);
}
private Problem _processFileObject(final Project project, int level, final FileObject fileObject) {
final Project theProject;
if (project == null) {
theProject = FileOwnerQuery.getOwner(fileObject);
}
else {
theProject = project;
}
if (theProject == null){
LOGGER.warn("Request process file object without a project as the owner : "+fileObject);
return null;
}
final FileObject projectDirectory = theProject.getProjectDirectory();
if (projectDirectory == null){
LOGGER.warn("Request process file object in a project which doesn't have folder : " + fileObject+", project : "+project);
return null;
}
final File projectFolder = FileUtil.toFile(projectDirectory);
Problem result = processFile(theProject, level, projectFolder, fileObject);
level++;
if (fileObject.isFolder()) {
for (final FileObject fo : fileObject.getChildren()) {
if (result != null) {
break;
}
if (fo.isFolder()) {
result = _processFileObject(theProject, level, fo);
}
else {
result = processFile(theProject, level, projectFolder, fo);
}
}
}
return result;
}
protected abstract Problem processFile(Project project, int level, File projectFolder, FileObject fileObject);
protected boolean doesMindMapContainFileLink(final Project project, final FileObject mindMap, final MMapURI fileToCheck) throws IOException {
final FileObject baseFolder = project.getProjectDirectory();
try {
final MindMap parsedMap = new MindMap(null,new StringReader(mindMap.asText("UTF-8"))); //NOI18N
return parsedMap.doesContainFileLink(FileUtil.toFile(baseFolder), fileToCheck);
}
catch (IllegalArgumentException ex) {
// not mind map
return false;
}
}
@Override
public final void cancelRequest() {
this.canceled.set(true);
}
public boolean isCanceled() {
return this.canceled.get();
}
}