// Copyright 2014 Google Inc. All Rights Reserved.
//
// 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.google.enterprise.adaptor.fs;

import com.google.common.base.Charsets;
import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;
import com.google.common.io.CharStreams;
import com.google.enterprise.adaptor.AsyncDocIdPusher;

import static org.junit.Assert.*;

import org.junit.*;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;

import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.AclFileAttributeView;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
import java.util.Set;
import java.util.concurrent.BlockingQueue;

/** Tests for {@link NioFileDelegate} */
public class NioFileDelegateTest {
  private FileDelegate delegate = new TestNioFileDelegate();

  @Rule
  public TemporaryFolder temp = new TemporaryFolder();

  private Path newTempDir(String name) throws IOException {
    return temp.newFolder(name).toPath().toRealPath();
  }

  private Path newTempFile(String name) throws IOException {
    return temp.newFile(name).toPath().toRealPath();
  }

  private Path newTempFile(Path parent, String name) throws IOException {
    Preconditions.checkArgument(parent.startsWith(temp.getRoot().toPath()
        .toRealPath()));
    return Files.createFile(parent.resolve(name));
  }


  @Test
  public void testGetPath() throws Exception {
    testGetPath("foo");
    testGetPath("/foo/bar/baz");
    testGetPath("\\\\host\\share\\file.txt");
    testGetPath(temp.getRoot().getAbsolutePath());
  }

  private void testGetPath(String pathname) throws Exception {
    assertTrue(Paths.get(pathname).equals(delegate.getPath(pathname)));
  }

  @Test
  public void testIsDirectory() throws Exception {
    Path dir = newTempDir("testDir");
    Path file = newTempFile("test");
    assertTrue(delegate.isDirectory(dir));
    assertFalse(delegate.isDirectory(file));
    assertFalse(delegate.isDirectory(dir.resolve("notExist")));
  }

  @Test
  public void testIsRegularFile() throws Exception {
    Path dir = newTempDir("testDir");
    Path file = newTempFile("test");
    assertTrue(delegate.isRegularFile(file));
    assertFalse(delegate.isRegularFile(dir));
    assertFalse(delegate.isRegularFile(dir.resolve("notExist")));
  }

  @Test
  public void testIsHidden() throws Exception {
    Path hiddenFile = newTempFile(".hiddenFile");
    if (System.getProperty("os.name").startsWith("Windows")) {
      Files.setAttribute(hiddenFile, "dos:hidden", Boolean.TRUE);
    }
    try {
      assertTrue(delegate.isHidden(hiddenFile));
      assertFalse(delegate.isHidden(newTempFile("bar")));
    } finally {
      // Windows won't let me delete the hidden file in tearDown().
      if (System.getProperty("os.name").startsWith("Windows")) {
        Files.setAttribute(hiddenFile, "dos:hidden", Boolean.FALSE);
      }
    }
  }

  @Test
  public void testReadBasicAttributesDirectory() throws Exception {
    Path dir = newTempDir("testDir");
    BasicFileAttributes attrs = delegate.readBasicAttributes(dir);
    assertTrue(attrs.isDirectory());
    assertFalse(attrs.isRegularFile());
    assertFalse(attrs.isSymbolicLink());
    assertFalse(attrs.isOther());
  }

  @Test
  public void testReadBasicAttributesFile() throws Exception {
    byte[] content = "Hello World".getBytes(Charsets.UTF_8);
    Path file = newTempFile("test");
    Files.write(file, content);
    BasicFileAttributes attrs = delegate.readBasicAttributes(file);
    assertTrue(attrs.isRegularFile());
    assertFalse(attrs.isDirectory());
    assertFalse(attrs.isSymbolicLink());
    assertFalse(attrs.isOther());
    assertEquals(content.length, attrs.size());
  }

  @Test
  public void testProbeContentType() throws Exception {
    TestHelper.assumeOsIsNotMac();
    String content = "<html><title>Foo</title><body>Bar</body></html>";
    Path file = newTempFile("Foo.html");
    Files.write(file, content.getBytes(Charsets.UTF_8));
    assertEquals("text/html", delegate.probeContentType(file));
  }

  @Test
  public void testNewInputStream() throws Exception {
    String content = "<html><title>Foo</title><body>Bar</body></html>";
    Path file = newTempFile("Foo.html");
    Files.write(file, content.getBytes(Charsets.UTF_8));
    assertEquals(content, CharStreams.toString(new InputStreamReader(
        delegate.newInputStream(file), Charsets.UTF_8)));
  }

  @Test
  public void testNewDirectoryStream() throws Exception {
    Path dir = newTempDir("testDir");
    Path file1 = newTempFile(dir, "test1");
    Path file2 = newTempFile(dir, "test2");
    Path file3 = newTempFile(dir, "test3");
    Set<Path> expected = Sets.newHashSet(file1, file2, file3);
    DirectoryStream<Path> ds = delegate.newDirectoryStream(dir);
    assertNotNull(ds);
    Set<Path> actual = Sets.newHashSet(ds);
    ds.close();
    assertEquals(expected, actual);
  }

  @Test
  public void testNewDocId() throws Exception {
    Path root = temp.getRoot().toPath().toRealPath();
    Path dir = newTempDir("testDir");
    Path file = newTempFile(dir, "test");

    String id = delegate.newDocId(root).getUniqueId();
    assertTrue(id.contains(root.toString()));
    assertTrue(id.endsWith("/"));

    id = delegate.newDocId(dir).getUniqueId();
    assertTrue(id.contains(root.toString()));
    assertTrue(id.contains(dir.toString()));
    assertTrue(id.endsWith("/"));

    id = delegate.newDocId(file).getUniqueId();
    assertTrue(id.contains(root.toString()));
    assertTrue(id.contains(dir.toString()));
    assertTrue(id.contains(file.toString()));
    assertFalse(id.endsWith("/"));
  }

  @Test
  public void testSetLastAccessTime() throws Exception {
    Path file = newTempFile("test");
    BasicFileAttributes attrs = delegate.readBasicAttributes(file);
    FileTime originalTime = attrs.lastAccessTime();
    FileTime newTime = FileTime.fromMillis(originalTime.toMillis() + 10000);
    delegate.setLastAccessTime(file, newTime);
    attrs = delegate.readBasicAttributes(file);
    assertEquals(newTime, attrs.lastAccessTime());
  }

  private static class TestNioFileDelegate extends NioFileDelegate {
    @Override
    public void destroy() {}

    @Override
    public void startMonitorPath(Path watchPath, AsyncDocIdPusher pusher) {
      throw new UnsupportedOperationException();
    }
      
    @Override
    public void stopMonitorPath() {
      throw new UnsupportedOperationException();
    }

    @Override
    public AclFileAttributeViews getAclViews(Path doc) throws IOException {
      throw new UnsupportedOperationException();
    }

    @Override
    public AclFileAttributeView getShareAclView(Path doc) throws IOException {
      throw new UnsupportedOperationException();
    }

    @Override
    public AclFileAttributeView getDfsShareAclView(Path doc) {
      throw new UnsupportedOperationException();
    }

    @Override
    public Path getDfsUncActiveStorageUnc(Path doc) throws IOException {
      throw new UnsupportedOperationException();
    }
  }
}
