/*
 * Copyright 2000-2014 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 com.intellij.index;

import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileTypes.PlainTextFileType;
import com.intellij.openapi.util.Factory;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiManagerEx;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiSearchHelper;
import com.intellij.testFramework.IdeaTestCase;
import com.intellij.testFramework.PlatformTestUtil;
import com.intellij.testFramework.PsiTestUtil;
import com.intellij.testFramework.SkipSlowTestLocally;
import com.intellij.util.indexing.MapIndexStorage;
import com.intellij.util.indexing.StorageException;
import com.intellij.util.io.*;
import org.jetbrains.annotations.NotNull;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.File;
import java.io.IOException;
import java.util.*;

/**
 * @author Eugene Zhuravlev
 *         Date: Dec 12, 2007
 */
@SkipSlowTestLocally
public class IndexTest extends IdeaTestCase {

  public void testUpdate() throws StorageException, IOException {
    final File storageFile = FileUtil.createTempFile("indextest", "storage");
    final File metaIndexFile = FileUtil.createTempFile("indextest_inputs", "storage");
    final MapIndexStorage indexStorage = new MapIndexStorage(storageFile, new EnumeratorStringDescriptor(), new EnumeratorStringDescriptor(), 16 * 1024);
    final StringIndex index = new StringIndex(indexStorage, new Factory<PersistentHashMap<Integer, Collection<String>>>() {
      @Override
      public PersistentHashMap<Integer, Collection<String>> create() {
        try {
          return createMetaIndex(metaIndexFile);
        }
        catch (IOException e) {
          throw new RuntimeException(e);
        }
      }
    });

    try {
// build index
      index.update("com/ppp/a.java", "a b c d", null);
      index.update("com/ppp/b.java", "a b g h", null);
      index.update("com/ppp/c.java", "a z f", null);
      index.update("com/ppp/d.java", "a a u y z", null);
      index.update("com/ppp/e.java", "a n chj e c d", null);

      assertDataEquals(index.getFilesByWord("a"), "com/ppp/a.java", "com/ppp/b.java", "com/ppp/c.java", "com/ppp/d.java", "com/ppp/e.java");
      assertDataEquals(index.getFilesByWord("b"), "com/ppp/a.java", "com/ppp/b.java");
      assertDataEquals(index.getFilesByWord("c"), "com/ppp/a.java", "com/ppp/e.java");
      assertDataEquals(index.getFilesByWord("d"), "com/ppp/a.java", "com/ppp/e.java");
      assertDataEquals(index.getFilesByWord("g"), "com/ppp/b.java");
      assertDataEquals(index.getFilesByWord("h"), "com/ppp/b.java");
      assertDataEquals(index.getFilesByWord("z"), "com/ppp/c.java", "com/ppp/d.java");
      assertDataEquals(index.getFilesByWord("f"), "com/ppp/c.java");
      assertDataEquals(index.getFilesByWord("u"), "com/ppp/d.java");
      assertDataEquals(index.getFilesByWord("y"), "com/ppp/d.java");
      assertDataEquals(index.getFilesByWord("n"), "com/ppp/e.java");
      assertDataEquals(index.getFilesByWord("chj"), "com/ppp/e.java");
      assertDataEquals(index.getFilesByWord("e"), "com/ppp/e.java");

      // update index

      index.update("com/ppp/d.java", "a u y z", "a a u y z");
      assertDataEquals(index.getFilesByWord("a"), "com/ppp/a.java", "com/ppp/b.java", "com/ppp/c.java", "com/ppp/d.java", "com/ppp/e.java");
      index.update("com/ppp/d.java", "u y z", "a u y z");
      assertDataEquals(index.getFilesByWord("a"), "com/ppp/a.java", "com/ppp/b.java", "com/ppp/c.java", "com/ppp/e.java");
      index.update("com/ppp/d.java", "a a a u y z", "u y z");
      assertDataEquals(index.getFilesByWord("a"), "com/ppp/a.java", "com/ppp/b.java", "com/ppp/c.java", "com/ppp/d.java", "com/ppp/e.java");

      index.update("com/ppp/e.java", "a n chj e c d z", "a n chj e c d");
      assertDataEquals(index.getFilesByWord("z"), "com/ppp/c.java", "com/ppp/d.java", "com/ppp/e.java");

      index.update("com/ppp/b.java", null, "a b g h");
      assertDataEquals(index.getFilesByWord("a"), "com/ppp/a.java", "com/ppp/c.java", "com/ppp/d.java", "com/ppp/e.java");
      assertDataEquals(index.getFilesByWord("b"), "com/ppp/a.java");
      assertDataEquals(index.getFilesByWord("g"));
      assertDataEquals(index.getFilesByWord("h"));
    }
    finally {
      indexStorage.close();
      FileUtil.delete(storageFile);
    }
  }

  private PersistentHashMap<Integer, Collection<String>> createMetaIndex(File metaIndexFile) throws IOException {
    return new PersistentHashMap<Integer, Collection<String>>(metaIndexFile, new EnumeratorIntegerDescriptor(), new DataExternalizer<Collection<String>>() {
      @Override
      public void save(@NotNull DataOutput out, Collection<String> value) throws IOException {
        DataInputOutputUtil.writeINT(out, value.size());
        for (String key : value) {
          out.writeUTF(key);
        }
      }

      @Override
      public Collection<String> read(@NotNull DataInput in) throws IOException {
        final int size = DataInputOutputUtil.readINT(in);
        final List<String> list = new ArrayList<String>();
        for (int idx = 0; idx < size; idx++) {
          list.add(in.readUTF());
        }
        return list;
      }
    });
  }

  /*
  public void testStubIndexUnsavedDocumentsIndexing() throws IncorrectOperationException, IOException, StorageException {
    IdeaTestUtil.registerExtension(StubIndexExtension.EP_NAME, new TextStubIndexExtension(), getTestRootDisposable());
    IdeaTestUtil.registerExtension(StubIndexExtension.EP_NAME, new ClassNameStubIndexExtension(), getTestRootDisposable());
    FileTypeManager.getInstance().registerFileType(TestFileType.INSTANCE, "fff");
    final FFFLangParserDefinition parserDefinition = new FFFLangParserDefinition();
    LanguageParserDefinitions.INSTANCE.addExplicitExtension(FFFLanguage.INSTANCE, parserDefinition);

    final TestStubElementType stubType = new TestStubElementType();
    SerializationManager.getInstance().registerSerializer(TestStubElement.class, stubType);

    final File fffFile = new File(FileUtil.createTempDirectory("testing", "stubindex"), "MyClass.fff");
    fffFile.createNewFile();

    final VirtualFile vFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(fffFile);

    assertNotNull(vFile);
    assertEquals(TestFileType.INSTANCE, vFile.getFileType());

    try {
      final MockPsiFile psiFile = new MockPsiFile(vFile, MockPsiManager.getInstance(myProject));

      final MockPsiClass cls = new MockPsiClass("com.company.MyClass");
      psiFile.add(cls);

      final MockPsiMethod aaaMethod = new MockPsiMethod("aaa");
      cls.addMethod(aaaMethod);
      final MockPsiMethod bbbMethod = new MockPsiMethod("bbb");
      cls.addMethod(bbbMethod);

      final PsiFileStubImpl fileStub = new PsiFileStubImpl(psiFile);
      final TestStubElement clsStub = stubType.createStub(cls, fileStub);
      stubType.createStub(aaaMethod, clsStub);
      stubType.createStub(bbbMethod, clsStub);

      final ByteArrayOutputStream arrayStream = new ByteArrayOutputStream();
      SerializationManager.getInstance().serialize(fileStub, new DataOutputStream(arrayStream));

      final FileBasedIndex fbi = FileBasedIndex.getInstance();
      final UpdatableIndex<Integer, SerializedStubTree, FileContent> stubUpdatingIndex = fbi.getIndex(StubUpdatingIndex.INDEX_ID);
      final MemoryIndexStorage storage = (MemoryIndexStorage)((MapReduceIndex)stubUpdatingIndex).getStorage();

      // initial
      final int fileId = FileBasedIndex.getFileId(vFile);
      final byte[] bytes = arrayStream.toByteArray();
      stubUpdatingIndex.update(fileId, new FileContent(vFile, bytes), null);

      final ValueContainer<SerializedStubTree> data = stubUpdatingIndex.getData(fileId);
      final List<SerializedStubTree> trees = data.toValueList();

      final SerializedStubTree tree = assertOneElement(trees);

      assertTrue(Comparing.equal(bytes, tree.getBytes()));

      final StubElement deserialized = tree.getStub();
    }
    finally {
      LanguageParserDefinitions.INSTANCE.removeExplicitExtension(FFFLanguage.INSTANCE, parserDefinition);
    }

  }
  */

  private static <T> void assertDataEquals(List<T> actual, T... expected) {
    assertTrue(new HashSet<T>(Arrays.asList(expected)).equals(new HashSet<T>(actual)));
  }

  public void testCollectedPsiWithChangedDocument() throws IOException {
    VirtualFile dir = getVirtualFile(createTempDirectory());
    PsiTestUtil.addSourceContentToRoots(myModule, dir);

    final VirtualFile vFile = createChildData(dir, "Foo.java");
    VfsUtil.saveText(vFile, "class Foo {}");

    final GlobalSearchScope scope = GlobalSearchScope.allScope(getProject());
    final JavaPsiFacade facade = JavaPsiFacade.getInstance(getProject());
    assertNotNull(facade.findClass("Foo", scope));
    WriteCommandAction.runWriteCommandAction(null, new Runnable() {
      @Override
      public void run() {
        PsiFile psiFile = PsiManager.getInstance(getProject()).findFile(vFile);
        assertNotNull(psiFile);

        Document document = FileDocumentManager.getInstance().getDocument(vFile);
        document.deleteString(0, document.getTextLength());
        assertNotNull(facade.findClass("Foo", scope));

        psiFile = null;
        PlatformTestUtil.tryGcSoftlyReachableObjects();
        assertNull(((PsiManagerEx)PsiManager.getInstance(getProject())).getFileManager().getCachedPsiFile(vFile));

        PsiClass foo = facade.findClass("Foo", scope);
        assertNotNull(foo);
        assertTrue(foo.isValid());
        assertEquals("class Foo {}", foo.getText());
        assertTrue(foo.isValid());

        PsiDocumentManager.getInstance(myProject).commitAllDocuments();
        assertNull(facade.findClass("Foo", scope));
      }
    });
  }

  public void testSavedUncommittedDocument() throws IOException {
    VirtualFile dir = getVirtualFile(createTempDirectory());
    PsiTestUtil.addSourceContentToRoots(myModule, dir);

    final VirtualFile vFile = createChildData(dir, "Foo.java");
    VfsUtil.saveText(vFile, "");

    final GlobalSearchScope scope = GlobalSearchScope.allScope(getProject());
    final JavaPsiFacade facade = JavaPsiFacade.getInstance(getProject());
    assertNull(facade.findClass("Foo", scope));
    WriteCommandAction.runWriteCommandAction(null, new Runnable() {
      @Override
      public void run() {
        PsiFile psiFile = PsiManager.getInstance(getProject()).findFile(vFile);
        assertNotNull(psiFile);

        long count = PsiManager.getInstance(myProject).getModificationTracker().getModificationCount();

        Document document = FileDocumentManager.getInstance().getDocument(vFile);
        document.insertString(0, "class Foo {}");
        FileDocumentManager.getInstance().saveDocument(document);

        assertTrue(count == PsiManager.getInstance(myProject).getModificationTracker().getModificationCount());
        assertNull(facade.findClass("Foo", scope));

        PsiDocumentManager.getInstance(myProject).commitAllDocuments();
        assertNotNull(facade.findClass("Foo", scope));
        assertNotNull(facade.findClass("Foo", scope).getText());
        // if Foo exists now, mod count should be different
        assertTrue(count != PsiManager.getInstance(myProject).getModificationTracker().getModificationCount());
      }
    });
  }

  public void testSkipUnknownFileTypes() throws IOException {
    VirtualFile dir = getVirtualFile(createTempDirectory());
    PsiTestUtil.addSourceContentToRoots(myModule, dir);

    final VirtualFile vFile = createChildData(dir, "Foo.test");
    VfsUtil.saveText(vFile, "Foo");
    assertEquals(PlainTextFileType.INSTANCE, vFile.getFileType());
    assertOneElement(PsiSearchHelper.SERVICE.getInstance(myProject).findFilesWithPlainTextWords("Foo"));

    final Document document = FileDocumentManager.getInstance().getDocument(vFile);
    //todo should file type be changed silently without events?
    //assertEquals(UnknownFileType.INSTANCE, vFile.getFileType());

    final PsiFile file = getPsiFile(document);
    assertInstanceOf(file, PsiPlainTextFile.class);
    assertEquals("Foo", file.getText());

    assertOneElement(PsiSearchHelper.SERVICE.getInstance(myProject).findFilesWithPlainTextWords("Foo"));

    WriteCommandAction.runWriteCommandAction(myProject, new Runnable() {
      @Override
      public void run() {
        document.insertString(0, " ");
        assertEquals("Foo", file.getText());
        assertOneElement(PsiSearchHelper.SERVICE.getInstance(myProject).findFilesWithPlainTextWords("Foo"));

        FileDocumentManager.getInstance().saveDocument(document);
        assertEquals("Foo", file.getText());
        assertOneElement(PsiSearchHelper.SERVICE.getInstance(myProject).findFilesWithPlainTextWords("Foo"));

        PsiDocumentManager.getInstance(myProject).commitAllDocuments();
        assertEquals(" Foo", file.getText());
        assertOneElement(PsiSearchHelper.SERVICE.getInstance(myProject).findFilesWithPlainTextWords("Foo"));

      }
    });
  }

}
