// Copyright 1999 Memesoft.  All rights reserved.

package krb5.lib.util;

import java.util.*;
import java.io.*;
import krb5.lib.Krb5;
import krb5.lib.KrbException;

/**
 * KRB configuration file
 */
public class KrbConfFile {

	/**
	 * File
	 */
    File file;

	/**
	 * Sections
	 */
    Stack sectionStack = new Stack();

	/**
	 * Top level sections
	 */
    Hashtable toplevelSections = new Hashtable();

	/**
	 * Class constructor
	 *
	 * @param path is of type String
	 */
	public KrbConfFile(String path) {
	    file = new File(path);
	}

	/**
	 * Class constructor
	 *
	 * @param _file is of type File
	 */
	public KrbConfFile(File _file) {
	    file = _file;
	}

	/**
	 * Parses the data
	 *
	 * @exception KrbException an exception
	 * @see krb5.lib.KrbException
	 */
	public void parse() throws KrbException {
	    Hashtable section = null;
	    boolean inParens = false;
	    BufferedReader rdr = null;
	    try {
	        rdr = new BufferedReader(new InputStreamReader(
	            new FileInputStream(file)));
	    } catch (FileNotFoundException e) {
	        throw new KrbException(Krb5.CONF_FILE_NOT_FOUND);
	    }
	    while (true) {
	        String line = null;
	        try {
	            line = rdr.readLine();
	        } catch (IOException e) {
	            throw new KrbException(Krb5.CONF_FILE_READ_FAILED);
	        }
	        if (line == null)
	            break;
	        line = line.trim();
	        if (line.length() == 0 || line.startsWith(";") || line.startsWith("#") ||
	            line.startsWith("//")) {
	            //comment line; skip
	            continue;
	        }
	        if (line.equals("}")) {
	            if (!inParens)
	                throw new KrbException(Krb5.CONF_FILE_PARSE_FAILURE);
	            //end of section
	            section = (Hashtable)sectionStack.pop();
	            inParens = false;
	            continue;
	        }
	        if (line.startsWith("[", 0) && line.endsWith("]")) {
	            String name = line.substring(1, line.length() - 1).trim().toLowerCase();
	            if (name.length() == 0 || inParens)
    	            throw new KrbException(Krb5.CONF_FILE_PARSE_FAILURE);
	            Hashtable temp = new Hashtable();
	            toplevelSections.put(name, temp);
	            section = temp;
	            continue;
	        }
	        int equalPos = line.indexOf('=');
	        if (equalPos != -1) {
	            String name = line.substring(0, equalPos).trim();
	            if (name.length() == 0)
    	            throw new KrbException(Krb5.CONF_FILE_PARSE_FAILURE);
	            String value = line.substring(equalPos + 1).trim();
	            if (value.equals("{")) {
	                Hashtable temp = new Hashtable();
	                if (section == null)
        	            throw new KrbException(Krb5.CONF_FILE_PARSE_FAILURE);
	                sectionStack.push(section);
	                section.put(name, temp);
	                section = temp;
	                inParens = true;
	            } else {
	                //store the value under the name in the current section
	                section.put(name, value);
	            }
	            continue;
	        }
	        //things didn't work out
	        throw new KrbException(Krb5.CONF_FILE_PARSE_FAILURE);
	    }
	    try {
	        rdr.close();
	    } catch (IOException e) {}

	}

	/**
	 * Returns value for a given section and key
	 *
	 * @return String is a result
	 * @param sectionName is of type String
	 * @param valueName is of type String
	 */
	public String getValue(String sectionName, String valueName) {
	    return getValue((Hashtable)toplevelSections.get(sectionName), valueName);
	}

	/**
	 * Returns value for a given section and key
	 *
	 * @return String is a result
	 * @param section is of type Hashtable
	 * @param valueName is of type String
	 */
	public String getValue(Hashtable section, String valueName) {
	    if (section != null) {
	        Object o = section.get(valueName);
	        if (o instanceof String);
	            return (String)o;
	    }
	    return null;
	}

	/**
	 * Returns a subsection
	 *
	 * @return Hashtable is a result
	 * @param sectionName is of type String
	 * @param subsectionName is of type String
	 */
	public Hashtable getSubsection(String sectionName, String subsectionName) {
	    return getSubsection((Hashtable)toplevelSections.get(sectionName), subsectionName);
	}

	/**
	 * Returns a subsection
	 *
	 * @return Hashtable is a result
	 * @param section is of type Hashtable
	 * @param subsectionName is of type String
	 */
	public Hashtable getSubsection(Hashtable section, String subsectionName) {
	    if (section != null) {
	        Object o = section.get(subsectionName);
	        if (o instanceof Hashtable);
	            return (Hashtable)o;
	    }
	    return null;
	}

	/**
	 * Returns the key/value for a given section
	 *
	 * @return Enumeration is a result
	 * @param sectionName is of type String
	 */
	public Enumeration getValueNames(String sectionName) {
	    return getValueNames((Hashtable)toplevelSections.get(sectionName));
    }

	/**
	 * Returns the key/value for a given section
	 *
	 * @return Enumeration is a result
	 * @param section is of type Hashtable
	 */
	public Enumeration getValueNames(Hashtable section) {
	    if (section != null)
    	    return section.keys();
	    return null;
    }

	/**
	 * Print
	 */
	public void print() {
	    print(toplevelSections, 0);
	}

	/**
	 * Print
	 *
	 * @param h is of type Hashtable
	 * @param level is of type int
	 */
	static void print(Hashtable h, int level) {
	    Enumeration e = h.keys();
	    while (e.hasMoreElements()) {
	        String key = (String)e.nextElement();
	        Object o = h.get(key);
	        for (int i = 0; i < level; i++)
	            System.out.print("\t");
	        if (o instanceof Hashtable) {
	            if (level > 0)
    	            System.out.println(key + " = {");
	            else
	                System.out.println("[" + key + "]");
	            print((Hashtable)o, level + 1);
	            if (level > 0)
	                System.out.println("}");
	        } else if ((o instanceof String)) {
	            System.out.println(key + " = " + (String)o);
	        } else {
	            System.out.println(key + ": key refers to unsupported object class");
	        }
	    }
	}

	/**
	 * Main
	 *
	 * @param args is of type String[]
	 */
	public static void main(String args[]) {
	    try {
	        KrbConfFile f = new KrbConfFile("C:\\cygnus\\kerbnet\\etc\\krb5.conf");
	        f.parse();
	        f.print();
	        String s = f.getValue("libdefault", "foo");
	        s = f.getValue("libdefaults", "foo");
	        s = f.getValue("libdefaults", "default_tkt_enctypes");
	        Hashtable h = f.getSubsection("realms", "MEMESOFT.COM");
	        s = f.getValue(h, "admin");
	        s = f.getValue(h, "admin_server");
	        h = f.getSubsection("realms", "MEMESFT.COM");
	        System.out.println("ok");
	    } catch (KrbException e) {
			e.printStackTrace();
			System.out.println(e.krbErrorMessage());
	    }
    }	
}