// Copyright 2014 The Bazel Authors. 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.devtools.build.lib.skyframe;

import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import com.google.common.collect.Interner;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.concurrent.BlazeInterners;
import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
import com.google.devtools.build.lib.vfs.Dirent;
import com.google.devtools.build.lib.vfs.RootedPath;
import com.google.devtools.build.lib.vfs.Symlinks;
import com.google.devtools.build.skyframe.AbstractSkyKey;
import com.google.devtools.build.skyframe.SkyFunctionName;
import com.google.devtools.build.skyframe.SkyValue;
import java.io.IOException;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Objects;
import javax.annotation.Nullable;

/**
 * Encapsulates the filesystem operations needed to get the directory entries of a directory.
 *
 * <p>This class is an implementation detail of {@link DirectoryListingValue}.
 */
@AutoCodec.VisibleForSerialization
public final class DirectoryListingStateValue implements SkyValue {

  private final CompactSortedDirents compactSortedDirents;

  private DirectoryListingStateValue(Collection<Dirent> dirents) {
    this.compactSortedDirents = CompactSortedDirents.create(dirents);
  }

  @AutoCodec.Instantiator
  public static DirectoryListingStateValue create(Collection<Dirent> dirents) {
    return new DirectoryListingStateValue(dirents);
  }

  public static DirectoryListingStateValue create(RootedPath dirRootedPath) throws IOException {
    Collection<Dirent> dirents = dirRootedPath.asPath().readdir(Symlinks.NOFOLLOW);
    return create(dirents);
  }

  @ThreadSafe
  public static Key key(RootedPath rootedPath) {
    return Key.create(rootedPath);
  }

  @AutoCodec.VisibleForSerialization
  @AutoCodec
  static class Key extends AbstractSkyKey<RootedPath> {
    private static final Interner<Key> interner = BlazeInterners.newWeakInterner();

    private Key(RootedPath arg) {
      super(arg);
    }

    @AutoCodec.VisibleForSerialization
    @AutoCodec.Instantiator
    static Key create(RootedPath arg) {
      return interner.intern(new Key(arg));
    }

    @Override
    public SkyFunctionName functionName() {
      return SkyFunctions.DIRECTORY_LISTING_STATE;
    }
  }

  /**
   * Returns the directory entries for this directory, in a stable order.
   *
   * <p>Symlinks are not expanded.
   */
  public Dirents getDirents() {
    return compactSortedDirents;
  }

  @Override
  public int hashCode() {
    return compactSortedDirents.hashCode();
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    if (!(obj instanceof DirectoryListingStateValue)) {
      return false;
    }
    DirectoryListingStateValue other = (DirectoryListingStateValue) obj;
    return compactSortedDirents.equals(other.compactSortedDirents);
  }

  @Override
  public String toString() {
    return MoreObjects.toStringHelper(this)
        .add("dirents", Iterables.toString(getDirents()))
        .toString();
  }

  /** A space-efficient, sorted, immutable dirent structure. */
  private static final class CompactSortedDirents implements Dirents {

    private final String[] names;
    private final BitSet packedTypes;

    private CompactSortedDirents(String[] names, BitSet packedTypes) {
      this.names = names;
      this.packedTypes = packedTypes;
    }

    public static CompactSortedDirents create(Collection<Dirent> dirents) {
      final Dirent[] direntArray = dirents.toArray(new Dirent[dirents.size()]);
      Integer[] indices = new Integer[dirents.size()];
      for (int i = 0; i < dirents.size(); i++) {
        indices[i] = i;
      }
      Arrays.sort(indices,
          new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
              return direntArray[o1].compareTo(direntArray[o2]);
            }
          });
      String[] names = new String[dirents.size()];
      BitSet packedTypes = new BitSet(dirents.size() * 2);
      for (int i = 0; i < dirents.size(); i++) {
        Dirent dirent = direntArray[indices[i]];
        names[i] = dirent.getName();
        packType(packedTypes, dirent.getType(), i);
      }
      return new CompactSortedDirents(names, packedTypes);
    }

    @Override
    public boolean equals(Object obj) {
      if (!(obj instanceof CompactSortedDirents)) {
        return false;
      }
      if (this == obj) {
        return true;
      }
      CompactSortedDirents other = (CompactSortedDirents) obj;
      return Arrays.equals(names,  other.names) && packedTypes.equals(other.packedTypes);
    }

    @Override
    public int hashCode() {
      return Objects.hash(Arrays.hashCode(names), packedTypes);
    }

    @Override
    @Nullable
    public Dirent maybeGetDirent(String baseName) {
      int pos = Arrays.binarySearch(names, baseName);
      return pos < 0 ? null : direntAt(pos);
    }

    @Override
    public Iterator<Dirent> iterator() {
      return new Iterator<Dirent>() {

        private int i = 0;

        @Override
        public boolean hasNext() {
          return i < size();
        }

        @Override
        public Dirent next() {
          return direntAt(i++);
        }

        @Override
        public void remove() {
          throw new UnsupportedOperationException();
        }
      };
    }

    @Override
    public int size() {
      return names.length;
    }

    /** Returns the type of the ith dirent. */
    private Dirent.Type unpackType(int i) {
      int start = i * 2;
      boolean upper = packedTypes.get(start);
      boolean lower = packedTypes.get(start + 1);
      if (!upper && !lower) {
        return Dirent.Type.FILE;
      } else if (!upper && lower){
        return Dirent.Type.DIRECTORY;
      } else if (upper && !lower) {
        return Dirent.Type.SYMLINK;
      } else {
        return Dirent.Type.UNKNOWN;
      }
    }

    /** Sets the type of the ith dirent. */
    private static void packType(BitSet bitSet, Dirent.Type type, int i) {
      int start = i * 2;
      switch (type) {
        case FILE:
          pack(bitSet, start, false, false);
          break;
        case DIRECTORY:
          pack(bitSet, start, false, true);
          break;
        case SYMLINK:
          pack(bitSet, start, true, false);
          break;
        case UNKNOWN:
          pack(bitSet, start, true, true);
          break;
        default:
          throw new IllegalStateException("Unknown dirent type: " + type);
      }
    }

    private static void pack(BitSet bitSet, int start, boolean upper, boolean lower) {
      bitSet.set(start, upper);
      bitSet.set(start + 1, lower);
    }

    private Dirent direntAt(int i) {
      Preconditions.checkState(i >= 0 && i < size(), "i: %s, size: %s", i, size());
      return new Dirent(names[i], unpackType(i));
    }
  }
}
