/**
 *
 *
 */

package org.thdl.tib.input ;

import org.thdl.tib.scanner.TibetanScanner ;
import org.thdl.tib.scanner.LocalTibetanScanner ;
import org.thdl.tib.scanner.RemoteTibetanScanner ;
import org.thdl.tib.scanner.Word ;

import org.thdl.tib.input.SettingsServiceProvider ;
import org.thdl.tib.input.DictionaryLoadState ;
import org.thdl.tib.input.DictionarySettings ;
import org.thdl.tib.dictionary.DictionaryInterface ;
import org.thdl.tib.dictionary.ScannerBasedDictionary ;

import java.awt.GraphicsEnvironment ;
import java.awt.Font ;
import java.net.URL ;
import java.net.URLConnection ;
import java.io.InputStream ;
import java.util.HashMap ;
import java.util.Observer ;
import java.util.Observable ;

public class GlobalResourceHolder
{
    protected static final int NUM_FONTS = 10 ;
    protected static final String FONT_NAME_PREFIX = "TibetanMachineWeb" ;
    
	private static boolean flagIsUsingLocalFonts = false ; 
	private static Font baseTMWFont [] = null ;
	private static Font derivedTMWFont [] = null ;
	private static HashMap nameToNumber = null ;
	private static SettingsServiceProvider settingsServiceProvider ;

	private static DictionarySettings dictionarySettings = null ;
    
    private static int dictionaryLoadState = DictionaryLoadState.UNDEFINED ;
    private static Object dictionaryLoadLock = null ;

    private static DictionaryInterface dictionary = null ;

	static class Listener implements Observer
	{
		public static final int DICTIONARY_SETTINGS = 1 ;

		/**
         * update
         * 
         */
        public void update ( Observable o, Object arg )
        {
            onSettingsChange ( ((Integer)arg).intValue () ) ;
        }
        
		/**
		 * onSettingsChange
		 * 
		 */
		public void onSettingsChange ( int setting )
		{
			if ( null == GlobalResourceHolder.settingsServiceProvider )
				return ;
			if ( DICTIONARY_SETTINGS == setting )
			{			
				//
				// compare with the current settings
				//
				boolean newDictionaryEnabled = GlobalResourceHolder.
                    settingsServiceProvider.getDictionarySettingsEnabled () ;
				boolean newDictionaryLocal = GlobalResourceHolder.
                    settingsServiceProvider.getDictionarySettingsLocal () ;
				String newDictionaryPath = GlobalResourceHolder.
                    settingsServiceProvider.getDictionarySettingsPath () ;

				DictionarySettings newSettings = new DictionarySettings ( newDictionaryEnabled, 
																		  newDictionaryLocal, 
																		  newDictionaryPath ) ;

				if ( ! newSettings.equal ( GlobalResourceHolder.dictionarySettings ) )
				{
					GlobalResourceHolder.dictionarySettings.set ( newSettings ) ;
                    GlobalResourceHolder.dictionary = GlobalResourceHolder.loadDictionary () ;
				}
			}
		}
	} 

	static Listener listenerObj = null ;
    
	static
    {
		listenerObj = new Listener () ;		

		//
		// we have no service provider until the client class is born
		//
		settingsServiceProvider = null ;

        //
        // init the font array
        //
        //
		baseTMWFont = new Font [ NUM_FONTS ] ;
		derivedTMWFont = new Font [ NUM_FONTS ] ;
        
		//
        // if TibetanMachineWeb fonts are not installed
        // load the fonts from the .jar file and set
        // the flag
        //
		if ( ! isTMWInstalled () )
            setLocalFonts () ;

        //
        // initialize the dictionary stuff
        //
		dictionarySettings = new DictionarySettings () ;
        dictionaryLoadLock = new Object () ;
    }

	/**
	 */
	public static Listener getListener ()
	{
		return listenerObj ;
	}

    /**
     *
     */
    public static int getDictionaryLoadState ()
    {
        int state ;
        synchronized ( dictionaryLoadLock )
        {
            state = dictionaryLoadState ;
        }

        return state ;
    }

    public static void waitForDictionary ()
    {
        synchronized ( dictionaryLoadLock )
        {
            
        }
    }

    /**
     *
     *
     */
    public static DictionaryInterface getDictionary ()
    {
        return dictionary ;
    }

    /**
     * loadDictionary
     *
     */
    protected static DictionaryInterface loadDictionary ()
    {
        DictionaryInterface d = null ;

		if ( ! dictionarySettings.isEnabled () )
			return null ;

		dictionarySettings.setValid ( false ) ;

        synchronized ( dictionaryLoadLock )
        {
            dictionaryLoadState = DictionaryLoadState.UNDEFINED ;

		    try
		    {
			    if ( dictionarySettings.isLocal () )
			    {
				    d = new ScannerBasedDictionary ( new LocalTibetanScanner ( dictionarySettings.getPathOrUrl () ) ) ;			
				    dictionarySettings.setValid ( true ) ;
			    }
			    else
			    {
				    d = new ScannerBasedDictionary ( new RemoteTibetanScanner ( dictionarySettings.getPathOrUrl () ) ) ;
				    dictionarySettings.setValid ( true ) ;
			    }

                dictionaryLoadState = DictionaryLoadState.READY ;
		    }
		    catch ( Exception e )
		    {
			    System.err.println ( "TibetanScanner.loadDictionaryScanner () --> " + e.toString () ) ;
                dictionaryLoadState = DictionaryLoadState.ERROR ;
		    }
        }		

		return d ;
    }

    /*
     * isTMWInstalled ()
     * 
     * returns true if TibetanMachineWeb fonts are 
     * installed on the system.
     */
    protected static boolean isTMWInstalled ()
    {
        String [] familyNames = 
            GraphicsEnvironment.getLocalGraphicsEnvironment ().getAvailableFontFamilyNames () ;
 
        int mask = 0 ;
        
        for ( int i = 0; i < familyNames.length; i++ )
        {
            String family = familyNames [i] ;
            
            if ( family.startsWith ( FONT_NAME_PREFIX ) )
            {
                int fontNum = 0 ;

                if ( family == FONT_NAME_PREFIX )
                {
                    fontNum = 1 ;
                }
                else
                {
                    fontNum = Character.digit ( family.charAt ( family.length () - 1 ), 10 ) ;

                    if ( fontNum < 0 || fontNum > NUM_FONTS )
                    {
                        fontNum = 0 ;
                    }                    
                }

                if ( fontNum > 0 )
                {
                    mask |= ( 1 << (fontNum-1) ) ;
                    if ( ( ( 1 << NUM_FONTS ) - 1 ) == mask )
                        return true ;
                }
            }
        }
 
        return false ;
    }

    /*
     * setLocalFonts ()
     * 
     * loads the fonts from Fonts directory in
     * the .jar file, if the dir exists
     * 
     */
    protected static void setLocalFonts ()
    {
		nameToNumber = new HashMap () ;

        for ( int i = 0; i < NUM_FONTS; i++ )
        {
            String suffix = ((i>0)?String.valueOf (i):"") ;
            URL url = 
                GlobalResourceHolder.class.getResource ( "/Fonts/TibetanMachineWeb/timwn" + suffix + ".ttf" ) ;

            if ( null != url )
            {
                try
                {
                    URLConnection conn = url.openConnection () ;
                    InputStream is = conn.getInputStream () ;
                    baseTMWFont [i] = Font.createFont ( Font.TRUETYPE_FONT, is ) ;
                    is.close () ;
                }
                catch ( Exception e )
                {
                    System.err.println ( "Failed to load fonts from JAR !" ) ;
                    flagIsUsingLocalFonts = false ;
                    return ;
                }
            }    

			//
			// we use a hash map to translate font names into their numbers (indices)
			//
			nameToNumber.put ( FONT_NAME_PREFIX + ( ( 0 == i ) ? "" : String.valueOf (i) ), new Integer ( i ) ) ;
        }   

        flagIsUsingLocalFonts = true ;		
    }

	/*
	 * setFontSize
	 * 
	 * notifies the GlobalResource about the most probably used font size
	 * 
	 */
	protected static void setFontSize ( int fontSize )
	{
		if ( !flagIsUsingLocalFonts )
			return ;

		if ( null == derivedTMWFont [0] || fontSize != derivedTMWFont [0].getSize () )
		{
			for ( int i = 0; i < NUM_FONTS; i++ )
			{
				derivedTMWFont [i] = baseTMWFont [i].deriveFont ( Font.PLAIN, fontSize ) ;
			}
		}
	}

	/*
	 * getFont ( fontName, size )
	 * 
	 */
	public static Font getFont ( String fontName, int fontSize )
	{
		Integer intObj = (Integer)nameToNumber.get ( fontName ) ;

		if ( intObj != null )
		{
			int fontNum = intObj.intValue () ;
			return getFont ( fontNum, fontSize ) ;
		}

		return null ;
	}

	/*
	 * getFont ( fontNum, size )
	 * 
	 */
	public static Font getFont ( int fontNum, int fontSize )
	{		
		Font font = null ;

		if ( flagIsUsingLocalFonts )
		{
			if ( null == derivedTMWFont [fontNum] || fontSize != derivedTMWFont [fontNum].getSize () )
			{
				font = derivedTMWFont [fontNum] = baseTMWFont [fontNum].deriveFont ( Font.PLAIN, fontSize ) ;
			}
		}

		return font ;
	}

    /*
     * isUsingLocalFonts ()
     *
     * returns true if the app should use the fonts from the package .jar file
     * (==> fonts are not installed on the system)
     * 
     */
    public static boolean isUsingLocalFonts ()
    {
        return flagIsUsingLocalFonts ;
    }

	/**
	 * 
	 */
	public static void setSettingsServiceProvider ( SettingsServiceProvider theSettingsServiceProvider )
	{
		settingsServiceProvider = theSettingsServiceProvider ;
        theSettingsServiceProvider.getObservable ().addObserver ( listenerObj ) ;
	}
    
	/**
	 *
	 */
	public static void removeSettingsServiceProvider 
        ( SettingsServiceProvider theSettingsServiceProvider )
	{
		settingsServiceProvider = null ;
        theSettingsServiceProvider.getObservable ().deleteObserver ( listenerObj ) ;
	}

	/**
	 * 
	 */
	public static DictionarySettings getDictionarySettings ()
	{
		return dictionarySettings ;
	}    
};
