/*
 * AnswerFile.java
 *
 * Created on March 26, 2001, 12:18 PM
 */

package com.sns.tools.ant.taskdefs;

import org.apache.tools.ant.taskdefs.*;
import org.apache.tools.ant.*;
import java.io.*;
import java.util.*;

/**
 * AnswerFileManager provides the back-end management of answer files
 * for the AskUser task.  It registers connections and keeps a cache of
 * properties objects. Then, when the number of users drops below 1, it
 * flushes all cached objects to disk.
 *
 * @author  <a href="mailto:John.D.Casey@mail.sprint.com">John Casey</a>
 * @version 1.0
 */
public class AnswerFileManager extends Object {
    private Hashtable props;
    private static ArrayList referencingObjs;
    private static AnswerFileManager mgr;

    /** Creates new AnswerFileManager */
    private AnswerFileManager() {
        props = new Hashtable();
        referencingObjs = new ArrayList();
    }
    
    /**
     * Checks if the manager singleton has initialized yet.
     *
     *@return true if the singleton is initialized, false otherwise.
     */
    public static boolean isStarted(){return mgr == null;}
    
    /**
     * Returns a handle to the AnswerFileManager singleton.
     *
     *@param referent The object connecting to the AnswerFileManager
     *@return The handle to the AnswerFileManager singleton
     */
    public static AnswerFileManager getInstance(Object referent){
        if(mgr == null){mgr = new AnswerFileManager();}
        if(!referencingObjs.contains(referent)){
            referencingObjs.add(referent);
        }
        return mgr;
    }
    
    /**
     * Alert the AnswerFileManager to a task releasing it's connection.
     * This is done to keep track of how many tasks are using the cachec objects.
     *
     *@param referent The object that is releasing its connection to the
     * AnswerFileManager.
     */
    public void release(Object referent){
        referencingObjs.remove(referent);
        if(referencingObjs.size() == 0){
            flushCaches();
        }
    }
    
    /**
     * Sets the answerfile values. This information is cached, and will be
     * flushed to disk with the rest.  This method overcomes the problem of
     * non-existent answer files.
     *
     *@param f The filename to store these answers under
     *@param p The properties object storing the current answers.
     */
    public void setAnswerFile(File f, Properties p){
        props.put(f.getAbsolutePath(), p);
    }
    
    /**
     * Retrieves a handle to the properties object representing the answer file
     * in question.  If this properties object is not yet cached, this method
     * will cache it for later use.
     *
     *@param file The filename for the answerfile to retrieve.
     *@return The properties object associated with this answerfile.
     *@exception IOException An error occurred retrieving the answerfile from
     * disk.
     */
    public Properties getAnswerFile(File file) throws IOException{
        Properties p = (Properties)props.get(file.getAbsolutePath());
        if(p == null){
            p = readProperties(file);
            props.put(file.getAbsolutePath(), p);
        }
        return p;
    }
    
    /**
     * Reads the properties object into the cache from this file.
     *
     *@param file The file to retrieve the answers from.
     *@return The properties object associated with this answerfile.
     *@exception IOException An error occurred retrieving the answerfile from
     * disk.
     */
    private Properties readProperties(File file) throws IOException{
        FileInputStream in = null;
        Properties p = new Properties();
        try{
            in = new FileInputStream(file);
            p.load(in);
        }
        catch(IOException ex){
            throw ex;
        }
        catch(Exception ex){
            ex.printStackTrace(System.err);
        }
        finally{
            try{in.close();}
            catch(Exception ex){}
        }
        return p;
    }
    
    /**
     * Writes the properties object associated with this filename to disk.
     *
     *@param filename The name of the answerfile to write the answers to.
     *@param p The properties object to write to disk.
     */
    private void writeProperties(String filename, Properties p){
        FileOutputStream out = null;
        try{
            out = new FileOutputStream(filename);
            p.store(out, "Answer file written by Ant Taskdef: " + this.getClass().getName());
            out.flush();
        }
        catch(Exception ex){
            ex.printStackTrace(System.err);
        }
        finally{
            try{out.close();}
            catch(Exception ex){}
        }
    }
    
    /**
     * Flushes all cached properties objects to their associated answerfiles.
     */
    private void flushCaches(){
        if(props == null){return;}

        Enumeration enum = props.keys();
        String filename = null;
        Properties p = null;
        while(enum.hasMoreElements()){
            filename = (String)enum.nextElement();
            p = (Properties)props.get(filename);
            writeProperties(filename, p);
        }
    }
}
