package turgen.generator;

import java.util.*;
import java.io.*;
import turgen.PulsesException;
import turgen.plugin.Plugin;
import turgen.Turgen;

/** Pulse cache holds information about all available pulses. This cache
 *  can be reloaded if necessary. Pulses can be shared between plugins
 */
public class PulseCache {

    private HashMap pluginMap;

    public PulseCache() {
        pluginMap = new HashMap();
    }

    /** Load pulses from specified file
     *
     * @param filespec Pulses specification file
     * @throws Exception
     */
    public void load(String filespec) throws Exception {

        /*Erase map*/
        pluginMap = new HashMap();

        /*Initialize file reading*/
        FileReader fr = new FileReader(filespec);
        BufferedReader br = new BufferedReader(fr);

        /*State*/
        Vector currentPlugins=new Vector();


        /*Read file line per line*/
        String line=null;
        while ( (line=br.readLine())!=null) {

            /*Trim & skip blank lines*/
            line=line.trim();
            if (line.equals("")) continue;

            /*Skip comments*/
            if (line.startsWith("#")) continue;

            /*Is that list of plugins?*/
            if (line.startsWith(">")) {
                
                currentPlugins.clear();
                StringTokenizer tk = new StringTokenizer(line.substring(1),",");

                while(tk.hasMoreTokens()) {
                    currentPlugins.add(tk.nextToken());
                }

                continue;
            }

            /*Is the information about pulses for some plugin ?*/
            if (currentPlugins.isEmpty()==true) continue;

            /*Add information about pulses*/
            addPulsesForPlugins(line,currentPlugins);
        }

    }

    public PulseCrate[] getPulsesForPlugin(Plugin p) {
        return getPulsesForPlugin( Turgen.pluginManager.getPluginClassName(p));
    }


    public PulseCrate[] getPulsesForPlugin(String pluginId) {
        
        Vector v = (Vector)pluginMap.get(pluginId);
        
        if (v!=null) {

            int l=v.size();
            PulseCrate[] rv = new PulseCrate[l];

            for(int i=0;i<l;i++) {
                PulseCrate pCrate = (PulseCrate)v.elementAt(i);
                rv[i]=pCrate;
            }

            return rv;
        }

        return new PulseCrate[0];

    }


    private void addPulsesForPlugins(String line, Vector currentPlugins) throws Exception {

        final String MALFORMED_PULSES = "Malformed pulses information";

        /*Are the plugins in the map? If not add their vectors into map*/
        Iterator it = currentPlugins.iterator();

        while(it.hasNext()) {
            String pluginId = (String)it.next();

            if (!pluginMap.containsKey(pluginId)) {
                pluginMap.put(pluginId, new Vector());
            }
        }

        /*Tokenize information about pulses*/
        StringTokenizer tk = new StringTokenizer(line,",");
        PulseCrate pCrate = new PulseCrate();

        if (tk.hasMoreTokens()) pCrate.name=tk.nextToken().trim(); else throw new PulsesException(MALFORMED_PULSES);
        if (tk.hasMoreTokens()) pCrate.baudRate=Integer.parseInt(tk.nextToken().trim()); else throw new PulsesException(MALFORMED_PULSES);
        if (tk.hasMoreTokens()) pCrate.pilotTonePulseWidth=Integer.parseInt(tk.nextToken().trim()); else throw new PulsesException(MALFORMED_PULSES);
        if (tk.hasMoreTokens()) pCrate.longPulseWidth=Integer.parseInt(tk.nextToken().trim()); else throw new PulsesException(MALFORMED_PULSES);
        if (tk.hasMoreTokens()) pCrate.shortPulseWidth=Integer.parseInt(tk.nextToken().trim()); else throw new PulsesException(MALFORMED_PULSES);
        if (tk.hasMoreTokens()) pCrate.syncPulseWidth=Integer.parseInt(tk.nextToken().trim()); else throw new PulsesException(MALFORMED_PULSES);
        if (tk.hasMoreTokens()) pCrate.stopPulseWidth=Integer.parseInt(tk.nextToken().trim()); else throw new PulsesException(MALFORMED_PULSES);

        /*Add pulse crate to corresponding vectors*/
        it = currentPlugins.iterator();

        while(it.hasNext()) {
            String pluginId = (String)it.next();
            Vector v = (Vector)pluginMap.get(pluginId);
            v.add(pCrate);
        }
    }

    /** Dump PulseCache to standard output*/
    public void dump() {

        System.out.println("PulseCache {");

        Set keySet = pluginMap.keySet();
        Iterator it = keySet.iterator();

        while(it.hasNext()) {

            String key = (String)it.next();
            System.out.println(key);

            Vector v = (Vector)pluginMap.get(key);

            Iterator vit = v.iterator();
            while(vit.hasNext()) {
                PulseCrate pCrate = (PulseCrate)vit.next();
                System.out.println(pCrate.name);
                System.out.println(pCrate.baudRate);
                System.out.println(pCrate.pilotTonePulseWidth);
                System.out.println(pCrate.longPulseWidth);
                System.out.println(pCrate.shortPulseWidth);
                System.out.println(pCrate.syncPulseWidth);
                System.out.println(pCrate.stopPulseWidth);
            }

            System.out.println("");

        }

        System.out.println("}");
    }

    /** Get a possibly fresher version of pulses from the cache
     * 
     * @param pulsesName Name of pulses to be refreshed
     * @param p Plugin
     * @return PulseCrate or null when there are no such pulses
     */
    public PulseCrate getRefreshedPulses(String pulsesName,Plugin p) {
        
        PulseCrate[] pulseCrates = getPulsesForPlugin(p);
        for(int i=0;i<pulseCrates.length;i++) {
            if (pulseCrates[i].name.equals(pulsesName)) {
             return pulseCrates[i]; 
            }
        }
        return null;
    }

    
}
