gt:         retLibRef = fileMap.get(key);
context: /* Copyright (c) 2010, Carl Burch. License information is located in the
   * com.cburch.logisim.Main source code and at www.cburch.com/logisim/. */
  
  package com.cburch.logisim.file;
  
  import java.io.File;
  import java.io.IOException;
  import java.lang.ref.WeakReference;
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.HashMap;
  import java.util.WeakHashMap;
  
  import com.cburch.logisim.tools.Library;
  import static com.cburch.logisim.util.LocaleString.*;
  
  class LibraryManager {
      public static final LibraryManager instance = new LibraryManager();
  
      private static char desc_sep = '#';
  
      private static abstract class LibraryDescriptor {
          abstract boolean concernsFile(File query);
          abstract String toDescriptor(Loader loader);
          abstract void setBase(Loader loader, LoadedLibrary lib)
              throws LoadFailedException;
      }
  
      private static class LogisimProjectDescriptor extends LibraryDescriptor {
          private File file;
  
          LogisimProjectDescriptor(File file) {
              this.file = file;
          }
  
          @Override
          boolean concernsFile(File query) {
              return file.equals(query);
          }
  
          @Override
          String toDescriptor(Loader loader) {
              return "file#" + toRelative(loader, file);
          }
  
          @Override
          void setBase(Loader loader, LoadedLibrary lib) throws LoadFailedException {
              lib.setBase(loader.loadLogisimFile(file));
          }
  
          @Override
          public boolean equals(Object other) {
              if (!(other instanceof LogisimProjectDescriptor)) {
                  return false;
              }
  
              LogisimProjectDescriptor o = (LogisimProjectDescriptor) other;
              return this.file.equals(o.file);
          }
  
          @Override
          public int hashCode() {
              return file.hashCode();
          }
      }
  
      private static class JarDescriptor extends LibraryDescriptor {
          private File file;
          private String className;
  
          JarDescriptor(File file, String className) {
              this.file = file;
              this.className = className;
          }
  
          @Override
          boolean concernsFile(File query) {
              return file.equals(query);
          }
  
          @Override
          String toDescriptor(Loader loader) {
              return "jar#" + toRelative(loader, file) + desc_sep + className;
          }
  
          @Override
          void setBase(Loader loader, LoadedLibrary lib) throws LoadFailedException {
              lib.setBase(loader.loadJarFile(file, className));
          }
  
          @Override
          public boolean equals(Object other) {
              if (!(other instanceof JarDescriptor)) {
                  return false;
              }
  
              JarDescriptor o = (JarDescriptor) other;
              return this.file.equals(o.file) && this.className.equals(o.className);
          }
  
          @Override
          public int hashCode() {
              return file.hashCode() * 31 + className.hashCode();
          }
      }
  
      private HashMap<LibraryDescriptor,WeakReference<LoadedLibrary>> fileMap;
      private WeakHashMap<LoadedLibrary,LibraryDescriptor> invMap;
  
      private LibraryManager() {
          fileMap = new HashMap<LibraryDescriptor,WeakReference<LoadedLibrary>>();
          invMap = new WeakHashMap<LoadedLibrary,LibraryDescriptor>();
          ProjectsDirty.initialize();
      }
  
      void setDirty(File file, boolean dirty) {
          LoadedLibrary lib = findKnown(file);
          if (lib != null) {
              lib.setDirty(dirty);
          }
      }
  
      Collection<LogisimFile> getLogisimLibraries() {
          ArrayList<LogisimFile> ret = new ArrayList<LogisimFile>();
          for (LoadedLibrary lib : invMap.keySet()) {
              if (lib.getBase() instanceof LogisimFile) {
                  ret.add((LogisimFile) lib.getBase());
              }
          }
          return ret;
      }
  
      public Library loadLibrary(Loader loader, String desc) {
          // It may already be loaded.
          // Otherwise we'll have to decode it.
          int sep = desc.indexOf(desc_sep);
          if (sep < 0) {
              loader.showError(getFromLocale("fileDescriptorError", desc));
              return null;
          }
          String type = desc.substring(0, sep);
          String name = desc.substring(sep + 1);
  
          if (type.equals("")) {
              Library ret = loader.getBuiltin().getLibrary(name);
              if (ret == null) {
                  loader.showError(getFromLocale("fileBuiltinMissingError", name));
                  return null;
              }
              return ret;
          } else if (type.equals("file")) {
              File toRead = loader.getFileFor(name, Loader.LOGISIM_FILTER);
              return loadLogisimLibrary(loader, toRead);
          } else if (type.equals("jar")) {
              int sepLoc = name.lastIndexOf(desc_sep);
              String fileName = name.substring(0, sepLoc);
              String className = name.substring(sepLoc + 1);
              File toRead = loader.getFileFor(fileName, Loader.JAR_FILTER);
              return loadJarLibrary(loader, toRead, className);
          } else {
              loader.showError(getFromLocale("fileTypeError",
                  type, desc));
              return null;
          }
      }
  
      public LoadedLibrary loadLogisimLibrary(Loader loader, File toRead) {
          LoadedLibrary ret = findKnown(toRead);
          if (ret != null) {
              return ret;
          }
  
  
          try {
              ret = new LoadedLibrary(loader.loadLogisimFile(toRead));
          } catch (LoadFailedException e) {
              loader.showError(e.getMessage());
              return null;
          }
  
          LogisimProjectDescriptor desc = new LogisimProjectDescriptor(toRead);
          fileMap.put(desc, new WeakReference<LoadedLibrary>(ret));
          invMap.put(ret, desc);
          return ret;
      }
  
      public LoadedLibrary loadJarLibrary(Loader loader, File toRead, String className) {
          JarDescriptor jarDescriptor = new JarDescriptor(toRead, className);
          LoadedLibrary ret = findKnown(jarDescriptor);
          if (ret != null) {
              return ret;
          }
  
  
          try {
              ret = new LoadedLibrary(loader.loadJarFile(toRead, className));
          } catch (LoadFailedException e) {
              loader.showError(e.getMessage());
              return null;
          }
  
          fileMap.put(jarDescriptor, new WeakReference<LoadedLibrary>(ret));
          invMap.put(ret, jarDescriptor);
          return ret;
      }
  
      public void reload(Loader loader, LoadedLibrary lib) {
          LibraryDescriptor descriptor = invMap.get(lib);
          if (descriptor == null) {
              loader.showError(getFromLocale("unknownLibraryFileError",
                      lib.getDisplayName()));
          } else {
              try {
                  descriptor.setBase(loader, lib);
              } catch (LoadFailedException e) {
                  loader.showError(e.getMessage());
              }
          }
      }
  
      public Library findReference(LogisimFile file, File query) {
          for (Library lib : file.getLibraries()) {
              LibraryDescriptor desc = invMap.get(lib);
              if (desc != null && desc.concernsFile(query)) {
                  return lib;
              }
              if (lib instanceof LoadedLibrary) {
                  LoadedLibrary loadedLib = (LoadedLibrary) lib;
                  if (loadedLib.getBase() instanceof LogisimFile) {
                      LogisimFile loadedProj = (LogisimFile) loadedLib.getBase();
                      Library ret = findReference(loadedProj, query);
                      if (ret != null) {
                          return lib;
                      }
  
                  }
              }
          }
          return null;
      }
  
      public void fileSaved(Loader loader, File dest, File oldFile, LogisimFile file) {
          LoadedLibrary old = findKnown(oldFile);
          if (old != null) {
              old.setDirty(false);
          }
  
          LoadedLibrary lib = findKnown(dest);
          if (lib != null) {
              LogisimFile clone = file.cloneLogisimFile(loader);
              clone.setName(file.getName());
              clone.setDirty(false);
              lib.setBase(clone);
          }
      }
  
      public String getDescriptor(Loader loader, Library lib) {
          if (loader.getBuiltin().getLibraries().contains(lib)) {
              return desc_sep + lib.getName();
          } else {
              LibraryDescriptor desc = invMap.get(lib);
              if (desc != null) {
                  return desc.toDescriptor(loader);
              } else {
                  throw new LoaderException(getFromLocale("fileDescriptorUnknownError", lib.getDisplayName()));
              }
          }
      }
  
      private LoadedLibrary findKnown(Object key) {
          WeakReference<LoadedLibrary> retLibRef;
  