/*******************************************************************************
 * GenRGenS v.1.0, Generation of Random Genomic Sequences                      *
 * Copyright (C) 2001  Alain Denise/Yann Ponty                                 *
 *                                                                             *
 * This program is free software; you can redistribute it and/or               *
 * modify it under the terms of the GNU General Public License                 *
 * as published by the Free Software Foundation; either version 2              *
 * of the License, or (at your option) any later version.                      *
 *                                                                             *
 * This program is distributed in the hope that it will be useful,             *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of              *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               *
 * GNU General Public License for more details.                                *
 *                                                                             *
 * You should have received a copy of the GNU General Public License           *
 * along with this program; if not, write to the Free Software                 *
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. *
 *******************************************************************************/

package GenRGenS;

import java.util.*;
import java.io.*;
import javax.swing.*;
import GenRGenS.utility.*;
import GenRGenS.utility.holder.*;
import GenRGenS.utility.callbacks.*;
import GenRGenS.IU.*;


public class Linker
{
  private static Hashtable _NameToConfigClass = new Hashtable(31);
  private static Hashtable _NameToLitteralName = new Hashtable(31);
  private static CommandLineParser _parser = new CommandLineParser(
            "\t\t=== GenRGenS v"+GenRGenS.version+
						" ===\nUsage :\n\tjava -cp . GenRGenS [Options ...] [-nb k] -size l <description file>",
            new StringCallback()
              {
                public void fun(String s)
                {
                  GenRGenS.nomFichier = s;
                }
              });


  public static void configureParser()
  {
		_parser.addRule("-size", new IntCallback()
    {
      public void fun(int i)
      {
        if(i>0)
        {
          GenRGenS.size=i;
        }
      }
    },"l>0 : Sets size for the generated sequence.","");
    _parser.addRule("-nb", new IntCallback()
    {
      public void fun(int i)
      {
        if(i>0)
        {
          GenRGenS.howMany=i;
        }
      }
    },"k>0 : Sets number of generated sequences.","");

    _parser.addRule("-v", new IntCallback()
    {
      public void fun(int i)
      {
        if(i>0)
        {
          GenRGenS.verbose=true;
        }
        else
        {
          GenRGenS.verbose=false;
        }
      }
    },"-v 0 : Mode Verbose OFF.\n-v 1 : Mode Verbose ON.","");
  }


  // Charge les différents "packages" dédiés aux différents types de géneration;
  public static void init()
  {
    configureParser();
		try
		{
  		File[] directoryListing = (new File("GenRGenS").listFiles());

		  for(int i = 0 ; i< directoryListing.length; i++)
	  	{
        File PackageDir = directoryListing[i];
  		  try
	  	  {
		      if (PackageDir.isDirectory())
		      {
		        File[] packageDescriptor = PackageDir.listFiles(new FileExtensionFilter("cfg"));
		        if (packageDescriptor.length == 1)
  		      {
	    	      File ConfigurationFile = packageDescriptor[0];
		          char[] cbuf = new char[(int)ConfigurationFile.length()];
		          (new FileReader(ConfigurationFile)).read(cbuf,0,cbuf.length);
		          String GeneratorClass = new String(cbuf);
		          Class ConfigFile = Class.forName(GeneratorClass);
		          GeneratorConfigFile config = (GeneratorConfigFile) ConfigFile.newInstance();
		          installPackage(config);
		        }
		        else
		        { }
		      }
		    }
        catch(IOException io)
	      {
		      // Aïe ...
          GenRGenS.err.println("I/O Error while opening packages !");
  		  }
        catch(ClassNotFoundException cnf)
	      {
		      // Aïe ...
          GenRGenS.err.println("The .cfg file contained in the directory \""+ PackageDir.getAbsolutePath() +"\" links to a wrong class.");
		    }
  		  catch(IllegalAccessException ill)
	  	  {
		      GenRGenS.err.println("Couldn't access the config class in the package \""+ PackageDir.getAbsolutePath() +"\". Check your rights !");
		    }
		    catch(InstantiationException ie)
  		  {
	  	    GenRGenS.err.println("Couldn't create an instance for the config file in the package \""+ PackageDir.getAbsolutePath() +"\" with zero arguments.");
		    }
		  }
		}
    catch (NoSuchMethodError nsme)
	  {
	    //This is an applet ...
	  }
  }

  public static void installPackage(GeneratorConfigFile config)
  {
    if (GenRGenS.verbose ) { GenRGenS.err.println("Loading package : "+config.getDescriptionFileHeader());}

    Option[] opts = config.getOptions();
    // On ajoute les règles destinées au Parsing de la ligne de commande
    for(int j = 0; j<opts.length;j++)
    {
      Option o = opts[j];
      final Holder h = o.getHolder();
      switch(h.getTypename())
      {
        case(Holder.TYPE_BOOLEAN) :
        {
          ParseRule rule = new ParseRule( o.getCommandLineString(),
            new BooleanCallback()
            {
              public void fun(boolean i)
              {
                ((BooleanHolder)h).set(i);
              }
            },
            o.getShortHelp());
          _parser.addRule(rule,config.getLitteralName());
        }
        break;

        case(Holder.TYPE_INT) :
        {
          ParseRule rule = new ParseRule( o.getCommandLineString(),
            new IntCallback()
            {
              public void fun(int i)
              {
                ((IntHolder)h).set(i);
              }
            },
            o.getShortHelp());
          _parser.addRule(rule,config.getLitteralName());
        }
        break;

        case(Holder.TYPE_CHAR) :
        {
          ParseRule rule = new ParseRule( o.getCommandLineString(),
            new CharCallback()
            {
              public void fun(char i)
              {
                ((CharHolder)h).set(i);
              }
            },
            o.getShortHelp());
          _parser.addRule(rule,config.getLitteralName());
        }
        break;

        case(Holder.TYPE_STRING) :
        {
          ParseRule rule = new ParseRule( o.getCommandLineString(),
            new StringCallback()
            {
              public void fun(String i)
              {
                ((StringHolder)h).set(i);
              }
            },
            o.getShortHelp());
          _parser.addRule(rule,config.getLitteralName());
        }
        break;
      }
    }

    _NameToConfigClass.put(config.getDescriptionFileHeader().toUpperCase(),config);
    _NameToLitteralName.put(config.getDescriptionFileHeader().toUpperCase(),config.getLitteralName());
  }



  public static CommandLineParser getCommandLineParser()
  {
    return _parser;
  }

	public static String getDescriptionFileHeader(String fichier)
				throws IOException,GeneratorCreationException
  {
    return getDescriptionFileHeader(new StringReader(fichier));
  }


	public static String getDescriptionFileHeader(File fichier)
				throws IOException,GeneratorCreationException
  {
    return getDescriptionFileHeader(new FileReader(fichier));
  }

	public static String getDescriptionFileHeader(Reader fichier)
				throws IOException,GeneratorCreationException
	{
		/* Lecture du type du fichier */
		// initialisation et positionnement du Tokenizer
    

    
		StreamTokenizer s = new StreamTokenizer(fichier);
		int ttype;
		String tmp;
		s.slashStarComments(true);
		s.slashSlashComments(true);
		s.eolIsSignificant(false);
		s.lowerCaseMode(false);
		s.wordChars('A','Z');
		s.wordChars('a','z');
    
    ttype = s.nextToken();
    tmp = s.sval;
    if (tmp == null )
		{
				throw new GeneratorCreationException("Empty Description file !");
		}
    
    tmp = new String(tmp.toUpperCase());
		if (ttype!=StreamTokenizer.TT_WORD | !tmp.equals("TYPE"))
		{
				throw new GeneratorCreationException("Description file doesn't start with \"TYPE\".");
		}
		if (s.nextToken()!='=')
		{
				throw new GeneratorCreationException("Missing '=' after \"TYPE\".");
		}
		if (s.nextToken()!=StreamTokenizer.TT_WORD)
		{
				throw new GeneratorCreationException("Invalid value for x in the \"TYPE = x ...\" clause.");
		}

		String type = s.sval;

		if (_NameToConfigClass.containsKey(type.toUpperCase()))
		{
		   return type.toUpperCase();
	  }
	  else
	  {
			throw new GeneratorCreationException("Unknown package \""+type+"\", check its presence in dir \"GenRGenS\".");
	  }
	};


  public static Class getGeneratorClassFromType(String type)
  {
    if (type != null)
    {
  		if (_NameToConfigClass.containsKey(type.toUpperCase()))
	  	{
		     return ((GeneratorConfigFile) _NameToConfigClass.get(type.toUpperCase())).getGeneratorClass();
  	  }
	    else
	    {
			  return null;
	    }
    }
    else
    {
			  return null;
    }

  }

  public static GeneratorConfigFile getGeneratorConfigFileFromType(String type)
  {
    if (type != null)
    {
  		if (_NameToConfigClass.containsKey(type.toUpperCase()))
	  	{
		     return ((GeneratorConfigFile) _NameToConfigClass.get(type.toUpperCase()));
  	  }
	    else
	    {
			  return null;
	    }
    }
    else
    {
			  return null;
    }

  }


}