package code.loader;

import code.loader.except.*;
import code.loader.parser.*;
import code.modules.CurryModule;
import code.table.ModuleTable;

import java.io.*;
import java.util.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.Date;
import java.util.Enumeration;


import code.symbols.*;

/**
 * The interface implemented by all module loaders. <P>
 * <p/>
 * <B>Class Responsibilities</B> :
 * <OL>
 * <LI> provide the common interface for all module loaders: CLASS, TXT, XML
 * </LI>
 * </OL>
 * <B>Class Collaborators</B> :
 * <OL>
 * <LI> None </LI>
 * </OL>
 *
 * @author Sunita Marathe 
 * @since Jul 15, 2005
 */

public class TxtXMLModuleLoader implements ModuleLoader {
  /**
   * Read the module specified by moduleFilePath
   *
   * @param moduleName module name (without path)
   * @param moduleFilePath module name with absolute path
   * @throws LoaderException
   */
  private static CurryModule read (String moduleName, String moduleFilePath) throws Exception {

    BufferedReader in = new BufferedReader (new FileReader (moduleFilePath));
    ModuleParser parser = null;
    try {
      // layered initialization pattern to create the parser 
      // instance by the file extension
      parser = ModuleParserFactory.createModParser (moduleFilePath);
      parser.parse(in);
    }
    catch (FileFormatNotSupportException e) {
      throw e;
    }
    catch (ParseException ex) {
      System.err.println(ex);
      System.err.println("\nThe module \""+moduleName+"\" is malformed.");
      System.err.println("This may be due to a currupted file,");
      System.err.println("a compiler error, or a flvm internal error.");
      System.err.println("Please inform the developers <antoy@cs.pdx.edu>\n");
      System.exit(1);
    }

    // If the name of the file and the module differ,
    // the compiler did something is wrong.
    if (!moduleName.equals(parser.moduleName())) {
      String message = "Mismatch in modulename and filename. Filename="
		      + moduleName + " ModuleName=" + parser.moduleName();
      throw new LoaderException (message);
    }

    //construct a CurryModule from the parsed module
    return new CurryModule(moduleName,
			  parser.getImported(),
			  moduleFilePath,
			  // We cannot use the date of the file. 
			  // It could have been copied or touched.
			  // new Date((new File(filePath)).lastModified()),
			  parser.getTimestamp(),
			  parser.getAllSymbols(),
			  parser.isCompiled());
  }

  /**
   * Load module specified by moduleFilePath
   *
   * @param moduleName module name (without path)
   * @param moduleFilePath module name with absolute path
   * @throws Exception
   */
  public CurryModule load (String moduleName, String moduleFilePath) throws Exception {

    CurryModule module = read (moduleName, moduleFilePath);
    ModuleTable.installModule (module);

    // load the imports of this module
    Enumeration importedEnumeration = module.getImportedEnumeration ();
    while (importedEnumeration.hasMoreElements ()) {
      String importedModuleName = (String) importedEnumeration.nextElement ();
      CurryModule importedModule = LoadManager.load_r (importedModuleName);
      if (importedModule.compiled && module.timestamp < importedModule.timestamp) {
	System.err.println("\nWarnning: " + module.moduleName +
	    " is older than its imported module " +
	    importedModule.moduleName + "!!!");
      }
    }
    return module;
  }
}

