/*
 * Copyright 2003-2011 JetBrains s.r.o.
 *
 * 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 jetbrains.mps;

import com.intellij.navigation.ChooseByNameContributor;
import com.intellij.navigation.ItemPresentation;
import com.intellij.navigation.NavigationItem;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.impl.cache.impl.id.IdIndex;
import com.intellij.psi.impl.cache.impl.id.IdIndexEntry;
import com.intellij.psi.search.FilenameIndex;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.indexing.FileBasedIndex;
import jetbrains.mps.ide.project.ProjectHelper;
import jetbrains.mps.project.MPSProject;
import jetbrains.mps.smodel.ModelAccessHelper;
import jetbrains.mps.util.Computable;
import org.jetbrains.annotations.NotNull;

import javax.swing.Icon;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

public class MPSGoToFileContributor implements ChooseByNameContributor, DumbAware {
  @NotNull
  @Override
  public String[] getNames(Project project, boolean includeNonProjectItems) {
    return FilenameIndex.getAllFilenames(project);
  }

  @NotNull
  @Override
  public NavigationItem[] getItemsByName(final String name, final String pattern, final Project project, boolean includeNonProjectItems) {
    final GlobalSearchScope scope = new AllScope();

    Collection<VirtualFile> files;
    try {
      MPSProject mpsProject = ProjectHelper.fromIdeaProject(project);
      assert mpsProject != null;
      files = new ModelAccessHelper(mpsProject.getModelAccess()).runReadAction(new Computable<Collection<VirtualFile>>() {
        @Override
        public Collection<VirtualFile> compute() {
           return FileBasedIndex.getInstance().getContainingFiles(FilenameIndex.NAME, name, scope);
        }
      });
    } catch (ProcessCanceledException ce){
      files = Collections.emptyList();
    }

    List<NavigationItem> result = new ArrayList<NavigationItem>();
    for (final VirtualFile file : files) {
      result.add(new FileNavigationItem(file, project));
    }

    return result.toArray(new NavigationItem[result.size()]);
  }

  public static class FileNavigationItem implements NavigationItem {
    private final VirtualFile myFile;
    private final Project myProject;

    public FileNavigationItem(VirtualFile file, Project project) {
      myFile = file;
      myProject = project;
    }

    @Override
    public String getName() {
      return myFile.getName();
    }

    public String toString() {
      return myFile.getName();
    }

    @Override
    public ItemPresentation getPresentation() {
      return new ItemPresentation() {
        @Override
        public String getPresentableText() {
          return myFile.getName();
        }

        @Override
        public String getLocationString() {
          return myFile.getParent().getPath();
        }

        @Override
        public Icon getIcon(boolean open) {
          return FileTypeManager.getInstance().getFileTypeByFile(myFile).getIcon();
        }
      };
    }

    @Override
    public void navigate(boolean requestFocus) {
      OpenFileDescriptor descriptor = new OpenFileDescriptor(myProject, getVirtualFile(), -1);
      if (descriptor.canNavigate()) {
        descriptor.navigate(true);
      }
    }

    @Override
    public boolean canNavigate() {
      return true;
    }

    @Override
    public boolean canNavigateToSource() {
      return false;
    }

    public VirtualFile getVirtualFile() {
      return myFile;
    }
  }

  private static class AllScope extends GlobalSearchScope {
    @Override
    public boolean contains(VirtualFile file) {
      return true;
    }

    @Override
    public int compare(VirtualFile file1, VirtualFile file2) {
      return 0;
    }

    @Override
    public boolean isSearchInModuleContent(@NotNull Module aModule) {
      return false;
    }

    @Override
    public boolean isSearchInLibraries() {
      return false;
    }
  }
}
