package cutils.putils;

//import cutils.bcel.de.fub.bytecode.classfile.ClassParser;
//import cutils.bcel.de.fub.bytecode.classfile.JavaClass;
import futils.DirList;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.jar.JarFile;

import utils.ReplaceString;

public class ClassPathUtils {
  public static void main(String args[]) {
    //print("loading packages from");
    //print(getClassPaths());
    JarFile jfs[] = getJarFiles();

    print(jfs);
    loadJars(jfs);


    //loadPackages();
    //Class classArray[] = classList.getClasses();
    //print(classArray);
    //cl.print();
    //print(getClassFiles());
    //ClassList.sort(ca);

    //PackageTree pt = new PackageTree(buildTree(ca));
    //pt.setBounds(0, 0, 380, 280);
    //pt.setVisible(true);
  }

  public static String classFileToClassName(File ccf) {
    // you need the BCEL for this to compile.
    //JavaClass jc = null;
    //try {
    //  ClassParser cp = new ClassParser(ccf.toString());
    //  jc = cp.parse();
    //} catch (IOException e) {
    //  e.printStackTrace();
    //  System.exit(0);
   // } catch (ClassFormatError e) {
   //   e.printStackTrace();
    //  System.exit(0);
   // }
  //  print("converted " + ccf);
  //  print("to a class called:" + jc.getClassName());
  //  return jc.getClassName();
    return null;
  }

  public static void addClassPath(String dir) {
    Properties p = System.getProperties();
    String oldPath = System.getProperty("java.class.path");
    String newPath = dir + System.getProperty("path.separator") + oldPath;
    System.out.println("before path=" + oldPath);
    p.put("java.class.path", newPath);
    System.setProperties(p);
    System.out.println("new path=" +
                       System.getProperty("java.class.path"));
  }

  public static void addClassPath(File f[]) {
    for (int i = 0; i < f.length; i++)
      addClassPath(f[i].toString());
  }


  public static boolean contains(String s1, String s2) {
    if (-1 == s1.indexOf(s2)) return false;
    return true;
  }

  public static Vector buildTree(Class ca[]) {
    Vector root = new Vector();
    Package p[] = getPackages();
    Vector pv = new Vector();
    pv.add("packages");
    Vector cv = new Vector();
    for (int i = 0; i < p.length; i++) {

      Package pp = p[i];
      String packageName = pp.getName();

      pv.add(packageName);
    }
    root.add(pv);
    for (int j = 0; j < ca.length; j++) {
      if ((j % 10) == 0) {
        root.add(cv);
        cv = new Vector();
      }
      String className = ca[j].getName();
      // System.out.println(className);
      if (contains(className, "cutils.putils")) ;
      cv.add(className);
    }
    root.add(cv);
    return root;
  }

  public static void print(Object o) {
    System.out.println(o);
  }

  public static void printSystemInfo(String args[]) {
    System.out.println("loadPackages:");
    loadPackages();
    System.out.println("loaded packages");
    print(getPackages());
    System.out.println("loaded "
                       + classList.getSize()
                       + " classes");
    System.out.println("number of methods=" +
                       classList.getNumberOfMethods());
    print(classList.getClasses());
  }


  private static ClassList classList = new ClassList();

  /**
   *   list all the classes loaded into
   * the system.
   */
  public static Class[] getClasses() {
    return classList.getClasses();
  }

  public static void printClassPaths() {
    String s[] = getClassPaths();
    print(s);
  }

  public static void printJars(String jfn[]) {
    for (int i = 0; i < jfn.length; i++)
      printJars(jfn[i]);
  }

  public static void printJars(String jfn) {
    try {
      JarFile jf = new JarFile(jfn);
      System.out.println("jarName=" + jf.getName());
      print(jf);
    } catch (java.io.IOException e) {
      e.printStackTrace();
    }
  }


  public static void loadJars(JarFile jf[]) {
    if (jf == null) return;
    for (int i = 0; i < jf.length; i++)
      loadJar(jf[i]);
  }

  public static void loadClasses(File cf[]) {
    if (cf == null) return;
    for (int i = 0; i < cf.length; i++)
      loadClass(cf[i].toString());
  }

  public static void loadJar(JarFile jf) {
    for (Enumeration e = jf.entries(); e.hasMoreElements();) {
      Object o = e.nextElement();
      String s = o.toString();
      loadClass(s);
    }
  }

  /**
   *      <code>loadClass</code> will load a class, at your peril
   * static data members will be automatically invoked upon load using this
   * method. Such elements should probably be invoked from within a thread.
   */
  public static void loadClass(String classString) {
    if (!classString.endsWith(".class")) return;
    classString = makeClassString(classString);
    System.out.println("attempting to load:" + classString);
    try {
      Class c = loadClassName(classString);
      if (c == null) return;
      classList.add(c);
    } catch (Exception e) {
      System.out.println(classString + ":failed to load");
      return;
    }
  }

  /**
   *  takes a string of the
   *  java/lang/String.class form and returns
   *  java.lang.String
   */
  public static String makeClassString(String s) {
    s = ReplaceString.sub(s, ".class", "");
    s = s.replace('/', '.');
    return s;
  }

  private static Class loadClassName(String s)
      throws Exception {

    return Class.forName(s);
  }

  public static void print(JarFile jf) {
    for (Enumeration e = jf.entries(); e.hasMoreElements();)
      System.out.println(" " + e.nextElement());
  }

  public static void print(Object s[]) {
    if (s == null) return;
    for (int i = 0; i < s.length; i++)
      System.out.println(s[i]);
    System.out.println("found:" + s.length + " items");
  }

  public static void print(Class s[]) {

    if (s == null) return;
    for (int i = 0; i < s.length; i++)
      System.out.println(s[i].getName());
    System.out.println("found:" + s.length + " Classes");
  }

  public static JarFile[] getJars() {
    String s[] = getClassPaths();
    Vector v = new Vector();
    for (int i = 0; i < s.length; i++)
      try {
        JarFile j = new JarFile(s[i]);
        v.addElement(j);
      } catch (java.io.IOException e) {
      }
    JarFile jf[] = new JarFile[v.size()];
    v.copyInto(jf);
    return jf;
  }

  public static int countJars(String s[]) {
    int n = 0;
    for (int i = 0; i < s.length; i++)
      if (s[i].endsWith("jar")) n++;
    return n;
  }

  public static File[] getClassFiles() {
    DirList dl = new DirList(".class");
    return dl.getFiles();
  }

  public static JarFile[] getJarFiles() {
    DirList dl = new DirList(".jar");
    File f[] = dl.getFiles();
    JarFile jf[] = new JarFile[f.length];
    for (int i = 0; i < jf.length; i++)
      try {
        jf[i] = new JarFile(f[i]);
      } catch (IOException e) {
        System.out.println("could not make jar file out of:" + f[i]);
      }
    return jf;
  }

  public static String[] getClassPaths() {
    String cp = getClassPath();
    String propertySeparator = System.getProperty("path.separator");
    StringTokenizer st =
        new StringTokenizer(cp, propertySeparator);
    int n = st.countTokens();
    String s[] = new String[n];
    for (int i = 0; i < n; i++)
      s[i] = st.nextToken();
    return s;
  }

  public static String getClassPath() {
    return System.getProperty("java.class.path");
  }

  // add new classes for any
  // elements you want loaded.
  private static void loadPackages() {
    loadJars(getJars());
    // loadClasses(getClassFiles());
  }


  private static Package[] getPackages() {
    return Package.getPackages();
  }

  public static void print(Package[] pkgs) {
    SortPackages(pkgs);
    for (int i = 0; i < pkgs.length; i++)
      System.out.println("  " + pkgs[i].getName());
    System.out.println("printed:" + pkgs.length + " packages.");
  }

  private static void SortPackages(Package[] pkgs) {
    Arrays.sort(pkgs,
                new PackageComparator()
    );
  }

  private static class PackageComparator implements Comparator {
    public int compare(Object a, Object b) {
      return ((Package) a).getName().compareTo(
          ((Package) b).getName());
    }
  }

}