/*
 * 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 com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.dev.resource.Resource;
import com.google.gwt.dev.resource.ResourceOracle;
import com.google.gwt.dev.util.log.speedtracer.CompilerEventType;
import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger;
import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger.Event;
import com.google.gwt.dev.util.msg.Message0;
import com.google.gwt.dev.util.msg.Message1String;

import org.apache.commons.collections.map.AbstractReferenceMap;
import org.apache.commons.collections.map.ReferenceMap;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.AccessControlException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

/**
 * The normal implementation of {@link ResourceOracle}.
 */
public class ResourceOracleImpl implements ResourceOracle {

  private static class Messages {
    static final Message1String EXAMINING_PATH_ROOT = new Message1String(TreeLogger.DEBUG,
        "Searching for resources within $0");
    static final Message1String IGNORING_SHADOWED_RESOURCE =
        new Message1String(
            TreeLogger.DEBUG,
            "Resource '$0' is being shadowed by another resource higher in the classpath having the same name; this one will not be used");
    static final Message0 REFRESHING_RESOURCES = new Message0(TreeLogger.TRACE,
        "Refreshing resources");
  }

  /**
   * Wrapper object around a resource to change its path when it is rerooted.
   */
  private static class RerootedResource extends AbstractResource {
    private final String path;
    private final AbstractResource resource;

    public RerootedResource(AbstractResource resource, PathPrefix pathPrefix) {
      this.path = pathPrefix.getRerootedPath(resource.getPath());
      this.resource = resource;
    }

    @Override
    public ClassPathEntry getClassPathEntry() {
      return resource.getClassPathEntry();
    }

    @Override
    public long getLastModified() {
      return resource.getLastModified();
    }

    @Override
    public String getLocation() {
      return resource.getLocation();
    }

    @Override
    public String getPath() {
      return path;
    }

    @Override
    public String getPathPrefix() {
      int fullPathLen = resource.getPath().length();
      return resource.getPath().substring(0, fullPathLen - path.length());
    }

    @Override
    public InputStream openContents() {
      return resource.openContents();
    }

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

  private static class ResourceData implements Comparable<ResourceData> {
    public final PathPrefix pathPrefix;
    public final AbstractResource resource;

    public ResourceData(AbstractResource resource, PathPrefix pathPrefix) {
      this.resource =
          pathPrefix.shouldReroot() ? new RerootedResource(resource, pathPrefix) : resource;
      this.pathPrefix = pathPrefix;
    }

    public int compareTo(ResourceData other) {
      // Rerooted takes precedence over not rerooted.
      if (this.resource.wasRerooted() != other.resource.wasRerooted()) {
        return this.resource.wasRerooted() ? 1 : -1;
      }
      // Compare priorities of the path prefixes, high number == high priority.
      return this.pathPrefix.getPriority() - other.pathPrefix.getPriority();
    }

    @Override
    public boolean equals(Object o) {
      if (!(o instanceof ResourceData)) {
        return false;
      }
      ResourceData other = (ResourceData) o;
      return this.pathPrefix.getPriority() == other.pathPrefix.getPriority()
          && this.resource.wasRerooted() == other.resource.wasRerooted();
    }

    @Override
    public int hashCode() {
      return (pathPrefix.getPriority() << 1) + (resource.wasRerooted() ? 1 : 0);
    }

    @Override
    public String toString() {
      return "{" + resource + "," + pathPrefix + "}";
    }
  }

  @SuppressWarnings("unchecked")
  private static final Map<ClassLoader, List<ClassPathEntry>> classPathCache = new ReferenceMap(
      AbstractReferenceMap.WEAK, AbstractReferenceMap.HARD);

  public static ClassPathEntry createEntryForUrl(TreeLogger logger, URL url)
      throws URISyntaxException, IOException {
    if (url.getProtocol().equals("file")) {
      File f = new File(url.toURI());
      String lowerCaseFileName = f.getName().toLowerCase(Locale.ENGLISH);
      if (f.isDirectory()) {
        return new DirectoryClassPathEntry(f);
      } else if (f.isFile() && lowerCaseFileName.endsWith(".jar")) {
        return ZipFileClassPathEntry.get(f);
      } else if (f.isFile() && lowerCaseFileName.endsWith(".zip")) {
        return ZipFileClassPathEntry.get(f);
      } else {
        // It's a file ending in neither jar nor zip, speculatively try to
        // open as jar/zip anyway.
        try {
          return ZipFileClassPathEntry.get(f);
        } catch (Exception ignored) {
        }
        if (logger.isLoggable(TreeLogger.TRACE)) {
          logger.log(TreeLogger.TRACE, "Unexpected entry in classpath; " + f
              + " is neither a directory nor an archive (.jar or .zip)");
        }
        return null;
      }
    } else {
      logger.log(TreeLogger.WARN, "Unknown URL type for " + url, null);
      return null;
    }
  }

  /**
   * Preinitializes the classpath from the thread default {@link ClassLoader}.
   */
  public static void preload(TreeLogger logger) {
    preload(logger, Thread.currentThread().getContextClassLoader());
  }

  /**
   * Preinitializes the classpath for a given {@link ClassLoader}.
   */
  public static void preload(TreeLogger logger, ClassLoader classLoader) {
    Event resourceOracle =
        SpeedTracerLogger.start(CompilerEventType.RESOURCE_ORACLE, "phase", "preload");
    List<ClassPathEntry> entries = getAllClassPathEntries(logger, classLoader);
    for (ClassPathEntry entry : entries) {
      // We only handle pre-indexing jars, the file system could change.
      if (entry instanceof ZipFileClassPathEntry) {
        ZipFileClassPathEntry zpe = (ZipFileClassPathEntry) entry;
        zpe.index(logger);
      }
    }
    resourceOracle.end();
  }

  /**
   * Rescans the associated paths to recompute the available resources.
   * 
   * TODO(conroy,scottb): This synchronization could be improved upon to allow
   * disjoint sets of oracles to be refreshed simultaneously.
   * 
   * @param logger status and error details are written here
   * @param first At least one ResourceOracleImpl must be passed to refresh
   * @param rest Callers may optionally pass several oracles
   */
  public static synchronized void refresh(TreeLogger logger, ResourceOracleImpl first,
      ResourceOracleImpl... rest) {
    int len = 1 + rest.length;
    ResourceOracleImpl[] oracles = new ResourceOracleImpl[1 + rest.length];
    oracles[0] = first;
    System.arraycopy(rest, 0, oracles, 1, rest.length);

    Event resourceOracle =
        SpeedTracerLogger.start(CompilerEventType.RESOURCE_ORACLE, "phase", "refresh");
    TreeLogger refreshBranch = Messages.REFRESHING_RESOURCES.branch(logger, null);

    /*
     * Allocate fresh data structures in anticipation of needing to honor the
     * "new identity for the collections if anything changes" guarantee. Use a
     * LinkedHashMap because we do not want the order to change.
     */
    List<Map<String, ResourceData>> resourceDataMaps = new ArrayList<Map<String, ResourceData>>();

    List<PathPrefixSet> pathPrefixSets = new ArrayList<PathPrefixSet>();
    for (ResourceOracleImpl oracle : oracles) {
      if (!oracle.classPath.equals(oracles[0].classPath)) {
        throw new IllegalArgumentException("Refreshing multiple oracles with different classpaths");
      }
      resourceDataMaps.add(new LinkedHashMap<String, ResourceData>());
      pathPrefixSets.add(oracle.pathPrefixSet);
    }

    /*
     * Walk across path roots (i.e. classpath entries) in priority order. This
     * is a "reverse painter's algorithm", relying on being careful never to add
     * a resource that has already been added to the new map under construction
     * to create the effect that resources founder earlier on the classpath take
     * precedence.
     * 
     * Exceptions: super has priority over non-super; and if there are two super
     * resources with the same path, the one with the higher-priority path
     * prefix wins.
     */
    for (ClassPathEntry pathRoot : oracles[0].classPath) {
      TreeLogger branchForClassPathEntry =
          Messages.EXAMINING_PATH_ROOT.branch(refreshBranch, pathRoot.getLocation(), null);

      List<Map<AbstractResource, PathPrefix>> resourceToPrefixMaps =
          pathRoot.findApplicableResources(branchForClassPathEntry, pathPrefixSets);
      for (int i = 0; i < len; ++i) {
        Map<String, ResourceData> resourceDataMap = resourceDataMaps.get(i);
        Map<AbstractResource, PathPrefix> resourceToPrefixMap = resourceToPrefixMaps.get(i);
        for (Entry<AbstractResource, PathPrefix> entry : resourceToPrefixMap.entrySet()) {
          ResourceData newCpeData = new ResourceData(entry.getKey(), entry.getValue());
          String resourcePath = newCpeData.resource.getPath();
          ResourceData oldCpeData = resourceDataMap.get(resourcePath);
          // Old wins unless the new resource has higher priority.
          if (oldCpeData == null || oldCpeData.compareTo(newCpeData) < 0) {
            resourceDataMap.put(resourcePath, newCpeData);
          } else {
            Messages.IGNORING_SHADOWED_RESOURCE.log(branchForClassPathEntry, resourcePath, null);
          }
        }
      }
    }

    for (int i = 0; i < len; ++i) {
      Map<String, ResourceData> resourceDataMap = resourceDataMaps.get(i);
      Map<String, Resource> externalMap = new HashMap<String, Resource>();
      Set<Resource> externalSet = new HashSet<Resource>();
      for (Entry<String, ResourceData> entry : resourceDataMap.entrySet()) {
        String path = entry.getKey();
        ResourceData data = entry.getValue();
        externalMap.put(path, data.resource);
        externalSet.add(data.resource);
      }

      // Update exposed collections with new (unmodifiable) data structures.
      oracles[i].exposedResources = Collections.unmodifiableSet(externalSet);
      oracles[i].exposedResourceMap = Collections.unmodifiableMap(externalMap);
      oracles[i].exposedPathNames = Collections.unmodifiableSet(externalMap.keySet());
    }

    resourceOracle.end();
  }

  private static void addAllClassPathEntries(TreeLogger logger, ClassLoader classLoader,
      List<ClassPathEntry> classPath) {
    // URL is expensive in collections, so we use URI instead
    // See:
    // http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html
    Set<URI> seenEntries = new HashSet<URI>();
    for (; classLoader != null; classLoader = classLoader.getParent()) {
      if (classLoader instanceof URLClassLoader) {
        URLClassLoader urlClassLoader = (URLClassLoader) classLoader;
        URL[] urls = urlClassLoader.getURLs();
        for (URL url : urls) {
          URI uri;
          try {
            uri = url.toURI();
          } catch (URISyntaxException e) {
            logger.log(TreeLogger.WARN, "Error processing classpath URL '" + url + "'", e);
            continue;
          }
          if (seenEntries.contains(uri)) {
            continue;
          }
          seenEntries.add(uri);
          Throwable caught;
          try {
            ClassPathEntry entry = createEntryForUrl(logger, url);
            if (entry != null) {
              classPath.add(entry);
            }
            continue;
          } catch (AccessControlException e) {
            if (logger.isLoggable(TreeLogger.DEBUG)) {
              logger.log(TreeLogger.DEBUG, "Skipping URL due to access restrictions: " + url);
            }
            continue;
          } catch (URISyntaxException e) {
            caught = e;
          } catch (IOException e) {
            caught = e;
          }
          logger.log(TreeLogger.WARN, "Error processing classpath URL '" + url + "'", caught);
        }
      }
    }
  }

  private static synchronized List<ClassPathEntry> getAllClassPathEntries(TreeLogger logger,
      ClassLoader classLoader) {
    List<ClassPathEntry> classPath = classPathCache.get(classLoader);
    if (classPath == null) {
      classPath = new ArrayList<ClassPathEntry>();
      addAllClassPathEntries(logger, classLoader, classPath);
      classPathCache.put(classLoader, classPath);
    }
    return classPath;
  }

  private final List<ClassPathEntry> classPath;

  private Set<String> exposedPathNames = Collections.emptySet();

  private Map<String, Resource> exposedResourceMap = Collections.emptyMap();

  private Set<Resource> exposedResources = Collections.emptySet();

  private PathPrefixSet pathPrefixSet = new PathPrefixSet();

  /**
   * Constructs a {@link ResourceOracleImpl} from a set of
   * {@link ClassPathEntry ClassPathEntries}. The list is held by reference and
   * must not be modified.
   */
  public ResourceOracleImpl(List<ClassPathEntry> classPath) {
    this.classPath = classPath;
  }

  /**
   * Constructs a {@link ResourceOracleImpl} from the thread's default
   * {@link ClassLoader}.
   */
  public ResourceOracleImpl(TreeLogger logger) {
    this(logger, Thread.currentThread().getContextClassLoader());
  }

  /**
   * Constructs a {@link ResourceOracleImpl} from a {@link ClassLoader}. The
   * specified {@link ClassLoader} and all of its parents which are instances of
   * {@link URLClassLoader} will have their class path entries added to this
   * instances underlying class path.
   */
  public ResourceOracleImpl(TreeLogger logger, ClassLoader classLoader) {
    this(getAllClassPathEntries(logger, classLoader));
  }

  public void clear() {
    exposedPathNames = Collections.emptySet();
    exposedResourceMap = Collections.emptyMap();
    exposedResources = Collections.emptySet();
  }

  public Set<String> getPathNames() {
    return exposedPathNames;
  }

  public PathPrefixSet getPathPrefixes() {
    return pathPrefixSet;
  }

  public Map<String, Resource> getResourceMap() {
    return exposedResourceMap;
  }

  public Set<Resource> getResources() {
    return exposedResources;
  }

  public void setPathPrefixes(PathPrefixSet pathPrefixSet) {
    this.pathPrefixSet = pathPrefixSet;
  }

  // @VisibleForTesting
  List<ClassPathEntry> getClassPath() {
    return classPath;
  }
}
