/*
 * Copyright 2008 Google Inc.
 *
 * 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.gwt.dev.resource.impl;

import org.apache.tools.ant.types.ZipScanner;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Represents the abstract path prefix that goes between the
 * {@link ClassPathEntry} and the rest of resource's abstract path. This concept
 * allows us to specify subsets of path hierarchies orthogonally from path
 * roots. For example, a path root might be <code>/home/gwt/src/</code> and an
 * abstract path prefix might be <code>module/client/</code>. Importantly,
 * you can apply the same abstract path prefix to multiple path roots and find
 * more than one set of resources residing in disjoint locations yet occupying
 * the same logical hierarchy. Sorry this explanation is so abstract; it's how
 * we model things like the GWT module's client source path, public path, and
 * super source path.
 */
public final class PathPrefix {

  public static final PathPrefix ALL = new PathPrefix("", null);

  private final Set<String> exclusions;
  private ZipScanner exclusionScanner;
  private final List<ResourceFilter> filters;
  private final String prefix;
  private int priority = -1;
  private final boolean shouldReroot;

  /**
   * Construct a non-rerooting prefix.
   *
   * @param prefix a string prefix that (1) is the empty string or (2) begins
   *          with something other than a slash and ends with a slash
   * @param filter the resource filter to use, or <code>null</code> for no
   *          filter; note that the filter must always return the same answer
   *          for the same candidate path (doing otherwise will produce
   *          inconsistent behavior in identifying available resources)
   */
  public PathPrefix(String prefix, ResourceFilter filter) {
    this(prefix, filter, false, null);
  }

  /**
   * Construct a prefix without global exclusions.
   *
   * @param prefix a string prefix that (1) is the empty string or (2) begins
   *          with something other than a slash and ends with a slash
   * @param filter the resource filter to use, or <code>null</code> for no
   *          filter; note that the filter must always return the same answer
   *          for the same candidate path (doing otherwise will produce
   *          inconsistent behavior in identifying available resources)
   * @param shouldReroot if <code>true</code>, any matching {@link Resource}
   *          for this prefix will be rerooted to not include the initial prefix
   *          path; if <code>false</code>, the prefix will be included in a
   *          matching resource's path.
   */
  public PathPrefix(String prefix, ResourceFilter filter, boolean shouldReroot) {
    this(prefix, filter, shouldReroot, null);
  }

  /**
   * Construct a prefix.
   *
   * @param prefix a string prefix that (1) is the empty string or (2) begins
   *          with something other than a slash and ends with a slash
   * @param filter the resource filter to use, or <code>null</code> for no
   *          filter; note that the filter must always return the same answer
   *          for the same candidate path (doing otherwise will produce
   *          inconsistent behavior in identifying available resources)
   * @param shouldReroot if <code>true</code>, any matching {@link Resource}
   *          for this prefix will be rerooted to not include the initial prefix
   *          path; if <code>false</code>, the prefix will be included in a
   *          matching resource's path.
   * @param excludeList list of globs that should be removed from <i>any</i>
   *          module's resources.
   */
  public PathPrefix(String prefix, ResourceFilter filter, boolean shouldReroot,
      String[] excludeList) {
    assertValidPrefix(prefix);
    this.prefix = prefix;
    this.filters = new ArrayList<ResourceFilter>(1);
    this.filters.add(filter);
    this.shouldReroot = shouldReroot;
    this.exclusions = new HashSet<String>();
    if (excludeList != null) {
      for (String exclude : excludeList) {
        exclusions.add(exclude);
      }
    }
  }

  /**
   * Determines whether or not a given path is allowed by this path prefix by
   * checking both the prefix string and the filter.
   *
   * @param path
   * @return
   */
  public boolean allows(String path) {
    if (!path.startsWith(prefix)) {
      return false;
    }
    if (filters.size() == 0 && exclusions.size() == 0) {
      return true;
    }
    if (shouldReroot) {
      path = getRerootedPath(path);
    }

    createExcludeFilter();
    if (exclusionScanner != null && exclusionScanner.match(path)) {
      return false;
    }
    for (ResourceFilter filter : filters) {
      if (filter == null || filter.allows(path)) {
        return true;
      }
    }
    return false;
  }

  /**
   * Equality is based on prefixes representing the same string. Importantly,
   * the filter does not affect equality.
   */
  @Override
  public boolean equals(Object obj) {
    if (obj instanceof PathPrefix) {
      if (prefix.equals(((PathPrefix) obj).prefix)) {
        return true;
      }
    }
    return false;
  }

  /**
   * The prefix.
   *
   * @return the result is guaranteed to be non-<code>null</code>, and
   *         either be the empty string or it will not begin with a slash and
   *         will end with a slash; these guarantees are very useful when
   *         concatenating paths that incorporate prefixes
   */
  public String getPrefix() {
    return prefix;
  }

  public String getRerootedPath(String path) {
    assert (path.startsWith(prefix));
    if (shouldReroot) {
      return path.substring(prefix.length());
    } else {
      return path;
    }
  }

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

  /**
   * Consolidate a given {@code PathPrefix} with this one, such that resources
   * excluded by neither prefix and included by either are allowed.
   *
   * @param pathPrefix
   */
  public void merge(PathPrefix pathPrefix) {
    assert prefix.equals(pathPrefix.prefix);
    for (ResourceFilter filter : pathPrefix.filters) {
      filters.add(filter);
    }
    exclusions.addAll(pathPrefix.exclusions);
    if (exclusionScanner != null && !exclusions.isEmpty()) {
      exclusionScanner = null;  // lose the stale one; we'll recreate later
    }
  }

  public boolean shouldReroot() {
    return shouldReroot;
  }

  @Override
  public String toString() {
    return prefix + (shouldReroot ? "**" : "*") + (filters.size() == 0 ? "" : "?");
  }

  int getPriority() {
    return priority;
  }

  void setPriority(int priority) {
    assert (this.priority == -1);
    this.priority = priority;
  }

  private void assertValidPrefix(String prefix) {
    assert (prefix != null);
    assert ("".equals(prefix) || (!prefix.startsWith("/") && prefix.endsWith("/"))) : "malformed prefix";
  }

  private void createExcludeFilter() {
    if (exclusionScanner == null && !exclusions.isEmpty()) {
      exclusionScanner = new ZipScanner();
      exclusionScanner.setIncludes(exclusions.toArray(new String[exclusions.size()]));
      exclusionScanner.init();
      exclusions.clear();
    }
  }
}
