/**********************************************************************/
/*                Package Desscriptor class for J2CPS                 */
/*                                                                    */   
/*                      (c) copyright QUT                             */ 
/**********************************************************************/
package J2CPS;

import java.io.*;
import java.util.*;

public class PackageDesc {

  private static final char qSepCh = '/';
  private static final char fSepCh = 
                             System.getProperty("file.separator").charAt(0);
  private static final char jSepCh = '.';
  private static final char nSepCh = '_';
  private static Vector toDo = new Vector(2);
  private static Vector syms = new Vector(2);
  private static Hashtable packageList = new Hashtable();
  private File packageFile;

  public ClassDesc[] classes;
  public String name, cpName, javaName, dirName;
  public Vector imports = new Vector();
  public int impNum = -1;
  public boolean anonPackage = false;

  public PackageDesc(String pName, boolean anon) {
    if (anon) {
      name = pName;
      cpName = pName;
      javaName = pName;
      anonPackage = true;
    } else {
      MakeName(pName);
      packageList.put(name,this); 
    }
    toDo.addElement(this); 
  }

  private void MakeName(String pName) {
    name = pName.replace(jSepCh,qSepCh);
    name = name.replace(fSepCh,qSepCh);  /* name is now .../... */
    cpName = name.replace(qSepCh,nSepCh);
    javaName = name.replace(qSepCh,jSepCh);
    if (qSepCh != fSepCh) {
      dirName = name.replace(qSepCh,fSepCh);
    } else {
      dirName = name;
    }
  }
 
  public static PackageDesc getPackage(String packName) {
    packName = packName.replace(jSepCh,qSepCh); 
    PackageDesc pack = (PackageDesc)packageList.get(packName);
    if (pack == null) { pack = new PackageDesc(packName,false); }
    return pack;
  }

  public static PackageDesc getClassPackage(String className) {
    className = className.replace(jSepCh,qSepCh); 
    String pName = className.substring(0,className.lastIndexOf(qSepCh));
    PackageDesc pack = (PackageDesc)packageList.get(pName);
    if (pack == null) { pack = new PackageDesc(pName,false); }
    return pack;
  }

  public void AddImport(TypeDesc ty) {
    if (ty instanceof ClassDesc) {
      ClassDesc aClass = (ClassDesc)ty;
      if (aClass.packageDesc == null) {
        System.err.println("ERROR: Class "+aClass.qualName+" has no package");
        System.exit(0);
      } 
      if ((this!=aClass.packageDesc)&&(!imports.contains(aClass.packageDesc))){ 
        imports.addElement(aClass.packageDesc); 
      }
    } 
  }
 
  public void AddImport(PackageDesc pack) {
    if ((this != pack) && (!imports.contains(pack))){ 
      imports.addElement(pack); 
    }
  }

  public void ResetImports() {
    for (int i=0; i < imports.size(); i++) {
      ((PackageDesc)imports.elementAt(i)).impNum = -1;
    }
  }

  private void AddImportList(Vector impList) {
    for (int i=0; i < impList.size(); i++) {
      AddImport((PackageDesc)impList.elementAt(i));
    }
  }

  public void ReadPackage() throws IOException, FileNotFoundException {
    syms.addElement(this);
    if (anonPackage) {
      classes = new ClassDesc[1];
      classes[0] = ClassDesc.GetClassDesc(name,this);
      boolean ok = classes[0].ReadClassFile(J2CPSFiles.OpenClassFile(name));
      return;
    } 
    packageFile = J2CPSFiles.getPackageFile(dirName);
    String[] classFiles = packageFile.list(new J2CPSFiles());
    classes = new ClassDesc[classFiles.length];
    for (int i = 0; i < classFiles.length; i++) {
      String cName = name + qSepCh + 
                     classFiles[i].substring(0,classFiles[i].lastIndexOf('.'));
      ClassDesc nextClass = ClassDesc.GetClassDesc(cName,this);
      if (nextClass.ReadClassFile(J2CPSFiles.OpenClassFile(packageFile, 
                                                        classFiles[i]))) {
        classes[i] = nextClass;
      }
    } 
  }

  public static void ReadPackages() throws IOException, FileNotFoundException {
    ((PackageDesc)toDo.elementAt(0)).ReadPackage();
    for (int i=1; i < toDo.size(); i++) {
      PackageDesc pack = (PackageDesc)toDo.elementAt(i);
      /* look for symbol file first */
      pack.packageFile = J2CPSFiles.FindSymbolFile(pack.cpName);
      if (pack.packageFile == null) {
        pack.ReadPackage();
      } else {
        if (ClassDesc.verbose)  {
          System.out.println("Reading Symbol File <" + 
                                             pack.packageFile.getPath() + ">");
        }
        SymbolFile.ReadSymbolFile(pack.packageFile,pack);
    }
      
    }
  }

  public static void WriteSymbolFiles() throws IOException {
    for (int i=0; i < syms.size(); i++) {
      Hashtable pScope = new Hashtable();
      PackageDesc nextPack = (PackageDesc)syms.elementAt(i);
      for (int j=0; j < nextPack.classes.length; j++) {
        if (nextPack.classes[j] != null) {
          if (ClassDesc.overloadedNames) {
            nextPack.classes[j].GetSuperImports(); 
          } else {
            nextPack.classes[j].GetSuperFields(pScope); 
          }
          nextPack.AddImportList(nextPack.classes[j].imports);
          ClassDesc superCl = nextPack.classes[j].superClass;
          while (superCl != null) {
            nextPack.AddImport(superCl);
            nextPack.AddImportList(superCl.imports);
            superCl = superCl.superClass;
          }
        }
      }
    }
    for (int i=0; i < syms.size(); i++) {
      PackageDesc nextPack = (PackageDesc)syms.elementAt(i);
      SymbolFile.WriteSymbolFile(nextPack);
    }
  }



}
