/*
 * Copyright (C) 2007-2009 KenD00
 * 
 * This file is part of DumpHD.
 * 
 * DumpHD 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 3 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, see <http://www.gnu.org/licenses/>.
 */
package dumphd.bdplus;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

import bdvm.vm.BDVMException;
import bdvm.vm.BDVMInterface;

/**
 * This class is a loader for the BDVM.
 * 
 * It can load the BDVM dynamically at runtime from a Jar file and create multiple instances of it.
 * 
 * To still be able to compile DumpHD without the BDVM present and to not need to use reflection to
 * call the BDVM methods the known BDVMInterface is used. This interface MUST be identical in DumpHD
 * and the BDVM or various errors can occur!
 * 
 * @author KenD00
 */
public class BDVMLoader {
   
   /**
    * The default constructor of the BDVM class
    */
   private Constructor<?> bdvmConstructor = null;
   
   
   /**
    * Constructs a new BDVMLoader.
    */
   public BDVMLoader() {
      // Nothing to do
   }
   
   /**
    * Loads the BDVM from the given Jar file.
    * 
    * This method tries to load the main class of the BDVM from the given Jar file and resolves its default constructor.
    * No instance of the BDVM is created here.
    * 
    * @param jarFile Jar archive which contains the BDVM
    * @throws BDVMException The BDVM class could not be loaded
    */
   public void loadClass(File jarFile) throws BDVMException {
      try {
         URL[] urls = { jarFile.toURI().toURL() };
         URLClassLoader cl = URLClassLoader.newInstance(urls);
         Class<?> bdvmClass = cl.loadClass("bdvm.vm.BDVM");
         bdvmConstructor = bdvmClass.getConstructor();
      } catch (MalformedURLException e) {
         throw new BDVMException(e.getMessage(), e);
      } catch (ClassNotFoundException e) {
         throw new BDVMException(e.getMessage(), e);
      } catch (SecurityException e) {
         throw new BDVMException(e.getMessage(), e);
      } catch (NoSuchMethodException e) {
         throw new BDVMException(e.getMessage(), e);
      }
   }
   
   /**
    * Creates a new instance of the BDVM class.
    * 
    * @return A new BDVM or null if the class is not loaded.
    * @throws BDVMException An error occurred while created the instance
    */
   public BDVMInterface newInstance() throws BDVMException {
      try {
         if (bdvmConstructor != null) {
            return (BDVMInterface) bdvmConstructor.newInstance();
         } else {
            return null;
         }
      } catch (IllegalArgumentException e) {
         throw new BDVMException(e.getMessage(), e);
      } catch (InstantiationException e) {
         throw new BDVMException(e.getMessage(), e);
      } catch (IllegalAccessException e) {
         throw new BDVMException(e.getMessage(), e);
      } catch (InvocationTargetException e) {
         throw new BDVMException(e.getMessage(), e);
      } catch (ClassCastException e) {
         throw new BDVMException(e.getMessage(), e);
      }
   }
   
}
