/*******************************************************************************
* Copyright (c)                                                                *
*           2005   Tristan Allwood,                                            *
*           2005   Daniel Burke,                                               *
*           2005   Marc Hull,                                                  *
*           2005   Ekaterina Itskova,                                          *
*           2005   Steve Zymler                                                *
*                                                                              *
* Permission is hereby granted, free of charge, to any person obtaining a      *
* copy of this software and associated documentation files (the                *
* "Software"), to deal in the Software without restriction, including          *
* without limitation the rights to use, copy, modify, merge, publish,          *
* distribute, sublicense, and/or sell copies of the Software, and to           *
* permit persons to whom the Software is furnished to do so, subject to        *
* the following conditions:                                                    *
*                                                                              *
* The above copyright notice and this permission notice shall be included      *
* in all copies or substantial portions of the Software.                       *
*                                                                              *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS      *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF                   *
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.       *
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY         *
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,         *
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE            *
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                       *
*******************************************************************************/
/*
 * Created on 22-Oct-2004 by toa02
 *
 */
package uk.ac.ic.doc.kevlar.core.framework.internal.loaders;

import java.io.File;
import java.util.HashSet;
import java.util.Set;

import uk.ac.ic.doc.kevlar.core.framework.internal.loaders.directorywatcher.DirectoryWatcherProvider;
import uk.ac.ic.doc.kevlar.core.framework.internal.loaders.directorywatcher.IDirectoryWatcher;
import uk.ac.ic.doc.kevlar.core.framework.internal.loaders.util.FrameworkClassLoader;

/**
 * @author toa02
 *
 */
class Loader implements ILoader, Runnable{

    private final TypeLoader itl;
    private final ProgramLoader ipl;
    
    private final Set<ILoadingEventListener> observers;
    private final IDirectoryWatcher watcher ;
    
    private final ClassLoader fcl;
    
    private static final int DIRTIMEOUT = Integer.parseInt(System.getProperty(
            "dir-scan-timeout", "500"));

    
    public Loader ( Set<File> typeDirs, Set<File> programDirs, FrameworkClassLoader fcl ) {
        observers = new HashSet<ILoadingEventListener>();
        watcher = DirectoryWatcherProvider.newInstance();
        itl = new TypeLoader(typeDirs, fcl, watcher);
        ipl = new ProgramLoader(programDirs, itl, watcher);
        this.fcl = fcl;
        itl.addObserver(new ITypeLoaderObserver(){

            public void typeTreeUpdated() {
                Loader.this.typeTreeUpdated();
            }
            
        });
        
        ipl.addObserver(new IProgramLoaderObserver(){

            public void programsAvailableUpdated() {
                programUpdated();
            }
            
        });
        
        ExecuteHolder.getExecutor().execute(this);
        
        synchronized( this ) {
            try {
                wait();
            } catch (InterruptedException e) {
                /* - fail silently - */
            }
        }
    }
    
    
    public void run () {
        while ( true ) {
            
            try {
                Thread.sleep(DIRTIMEOUT);
            } catch (InterruptedException e) {
                /* do nothing */
            }
            
            try{
            watcher.run();
            }catch(Exception e){
               e.printStackTrace();
            }catch(Error ee){
                ee.printStackTrace();
            }
            itl.run();
            ipl.run();
            
            synchronized(this){
                notifyAll();
            }
        }
    }
    
    /* called by the program loader observer when things update */
    void programUpdated(){
        /* fire off the observers */
        synchronized ( observers ) {
            for( final ILoadingEventListener obs : observers ) {
                
                ExecuteHolder.getExecutor().execute(new Runnable(){
                    
                    public void run() {
                        obs.availableProgramsUpdated(Loader.this);
                    }
                });
            }
        }
    }
    
    /* called by the type loader observer when things update */
    void typeTreeUpdated(){
        /* fire off the observers */
        synchronized ( observers ) {
            for( final ILoadingEventListener obs : observers ) {
                
                ExecuteHolder.getExecutor().execute(new Runnable(){
                    
                    public void run() {
                        obs.typeTreeUpdated(Loader.this);
                    }
                });
            }
        }
    }
    
    
    /**
     * @see uk.ac.ic.doc.kevlar.core.framework.internal.loaders.ILoader#getProgramLoader()
     */
    public IProgramLoader getProgramLoader() {
        return ipl;
    }

    /**
     * @see uk.ac.ic.doc.kevlar.core.framework.internal.loaders.ILoader#getTypeLoader()
     */
    public ITypeLoader getTypeLoader() {
        return itl;
    }

    public void addEventObserver( ILoadingEventListener ileo ){
        synchronized ( observers ) {
            observers.add( ileo );
        }
    }

    /**
     * @see uk.ac.ic.doc.kevlar.core.framework.internal.loaders.ILoader#waitTillStable()
     */
    public void waitTillStable() {
        try {
            synchronized ( this ) {
                wait();
            }
        } catch ( InterruptedException ie ){
            /* fail silently */
        }
        
    }


	public ClassLoader getCustomClassLoader() {
		return fcl;
	}
}
