/*
 * Java-Gnome Bindings Library
 * 
 * Copyright 1998-2004 the Java-Gnome Team, all rights reserved.
 * 
 * The Java-Gnome bindings library is free software distributed under the terms
 * of the GNU Library General Public License version 2.
 */
package org.gnu.gconf;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Vector;

import org.gnu.glib.Error;
import org.gnu.glib.GObject;
import org.gnu.glib.Handle;
import org.gnu.glib.Struct;

/**
 * ConfClient provides a client-side cache for a specified list of directories
 * your're interested in. You can preload entire directories into cache to
 * enhance performance. It also provides events when a value changes.
 *
 * @deprecated This class is part of the java-gnome 2.x family of libraries,
 *             which, due to their inefficiency and complexity, are no longer
 *             being maintained and have been abandoned by the java-gnome
 *             project. This class probably may or may not have an equivalent
 *             in java-gnome 4.0; have a look for
 *             <code>org.gnome.gconf.ConfClient</code>.
 */
public class ConfClient extends GObject {

    private class NotifyData {
        public String namespace;

        public Vector listeners;
    }

    private class NotifyClient {
        public int id;

        public ConfClientListener lis;
    }

    /**
     * Listeners for handling notify events
     * @deprecated Superceeded by java-gnome 4.0; this method may or may not
     *             exist in the new bindings but if it does, it will likely have 
     *             a different name or signature in order that the presented API
     *             is a more algorithmic mapping of the underlying native libraries.
     */
    private Hashtable listeners = null;

    private ConfClient(Handle handle) {
        super(handle);
    }

    private static ConfClient getConfClient(Handle handle) {
        if (handle == null) {
            return null;
        }

        ConfClient obj = (ConfClient) GObject.getGObjectFromHandle(handle);

        if (obj == null) {
            obj = new ConfClient(handle);
        }

        return obj;
    }

    /**
     * Method to get the default ConfClient
     * 
     * @return The default ConfClient.
     * @deprecated Superceeded by java-gnome 4.0; this method may or may not
     *             exist in the new bindings but if it does, it will likely have 
     *             a different name or signature in order that the presented API
     *             is a more algorithmic mapping of the underlying native libraries.
     */
    public static ConfClient getInstance() {
        return ConfClient.getConfClient(gconf_client_get_default());
    }

    /**
     * Add a directory to the list of directories the ConfClient will watch. Any
     * changes to keys below this directory will cause the "value_changed" event
     * to be fired.
     * 
     * @param dir
     * @param type
     * @throws ConfException
     * @deprecated Superceeded by java-gnome 4.0; this method may or may not
     *             exist in the new bindings but if it does, it will likely have 
     *             a different name or signature in order that the presented API
     *             is a more algorithmic mapping of the underlying native libraries.
     */
    public void addDirectory(String dir, ConfClientPreloadType type)
            throws ConfException {
        Handle errorHandle = gconf_client_add_dir(getHandle(), dir, type
                .getValue());
        checkError(errorHandle);
    }

    /**
     * Remove a directory from the list created with addDirectory.
     * 
     * @param dir
     * @throws ConfException
     * @deprecated Superceeded by java-gnome 4.0; this method may or may not
     *             exist in the new bindings but if it does, it will likely have 
     *             a different name or signature in order that the presented API
     *             is a more algorithmic mapping of the underlying native libraries.
     */
    public void removeDirectory(String dir) throws ConfException {
        Handle errorHandle = gconf_client_remove_dir(getHandle(), dir);
        checkError(errorHandle);
    }

    /**
     * Register an object to handle notify events.
     * 
     * @see org.gnu.gconf.ConfClientListener
     * @deprecated Superceeded by java-gnome 4.0; this method may or may not
     *             exist in the new bindings but if it does, it will likely have 
     *             a different name or signature in order that the presented API
     *             is a more algorithmic mapping of the underlying native libraries.
     */
    public void addListener(ConfClientListener listener, String nameSpace)
            throws ConfException {
        Handle errorHandle = Struct.getNullHandle();
        int id = gconf_client_notify_add(getHandle(), nameSpace, errorHandle);
        checkError(errorHandle);

        NotifyData nd = null;
        if (null == listeners)
            listeners = new Hashtable();
        else
            nd = (NotifyData) listeners.get(nameSpace);

        if (null == nd) {
            nd = new NotifyData();
            nd.namespace = nameSpace;
            nd.listeners = new Vector();
            listeners.put(nameSpace, nd);
        }
        NotifyClient nc = new NotifyClient();
        nc.id = id;
        nc.lis = listener;
        nd.listeners.addElement(nc);
    }

    /**
     * Removes a listener.
     * 
     * @see #addListener(ConfClientListener, String)
     * @deprecated Superceeded by java-gnome 4.0; this method may or may not
     *             exist in the new bindings but if it does, it will likely have 
     *             a different name or signature in order that the presented API
     *             is a more algorithmic mapping of the underlying native libraries.
     */
    public void removeListener(ConfClientListener listener, String nameSpace) {
        int id = -1;

        // get the object from the hashtable.
        if (null == listeners)
            return;
        NotifyData nd = (NotifyData) listeners.get(nameSpace);
        if (null == nd)
            return;

        for (int i = 0; i < nd.listeners.size(); i++) {
            NotifyClient nc = (NotifyClient) nd.listeners.elementAt(i);
            if (nc.lis == listener) {
                id = nc.id;
                nd.listeners.remove(nc.lis);
                break;
            }
        }
        if (-1 == id)
            return;

        gconf_client_notify_remove(getHandle(), id);
    }

    /**
     * If you know you're done reading values for a while you can blow away the
     * cache. Note that this nullifies the effect of any preloading you may have
     * done. However it frees some memory.
     * @deprecated Superceeded by java-gnome 4.0; this method may or may not
     *             exist in the new bindings but if it does, it will likely have 
     *             a different name or signature in order that the presented API
     *             is a more algorithmic mapping of the underlying native libraries.
     */
    public void clearCache() {
        gconf_client_clear_cache(getHandle());
    }

    /**
     * Preload a directory. The directory must have been added already. This is
     * only useful as an optimization if you clear the cache, then later want to
     * do a lot a reads again.
     * 
     * @param directory
     *            The directory to load
     * @param type
     *            How to preload the directory.
     * @throws ConfException
     * @deprecated Superceeded by java-gnome 4.0; this method may or may not
     *             exist in the new bindings but if it does, it will likely have 
     *             a different name or signature in order that the presented API
     *             is a more algorithmic mapping of the underlying native libraries.
     */
    public void preload(String directory, ConfClientPreloadType type)
            throws ConfException {
        Handle errorHandle = Struct.getNullHandle();
        gconf_client_preload(getHandle(), directory, type.getValue(),
                errorHandle);
        checkError(errorHandle);
    }

    /**
     * Set the value of a configuration key.
     * 
     * @param key
     * @param value
     * @throws ConfException
     * @deprecated Superceeded by java-gnome 4.0; this method may or may not
     *             exist in the new bindings but if it does, it will likely have 
     *             a different name or signature in order that the presented API
     *             is a more algorithmic mapping of the underlying native libraries.
     */
    public void set(String key, ConfValue value) throws ConfException {
        Handle errorHandle = Struct.getNullHandle();
        gconf_client_set(getHandle(), key, value.getHandle(), errorHandle);
        checkError(errorHandle);
    }

    /**
     * Get the value of a configuration key.
     * 
     * @param key
     * @throws ConfException
     * @deprecated Superceeded by java-gnome 4.0; this method may or may not
     *             exist in the new bindings but if it does, it will likely have 
     *             a different name or signature in order that the presented API
     *             is a more algorithmic mapping of the underlying native libraries.
     */
    public ConfValue get(String key) throws ConfException {
        Handle errorHandle = Struct.getNullHandle();
        Handle hndl = gconf_client_get(getHandle(), key, errorHandle);
        checkError(errorHandle);
        return ConfValue.getConfValue(hndl);
    }

    /**
     * Obtain the full ConfEntry for a value.
     * 
     * @param key
     * @param locale
     * @param useSchemaDefault
     * @throws ConfException
     * @deprecated Superceeded by java-gnome 4.0; this method may or may not
     *             exist in the new bindings but if it does, it will likely have 
     *             a different name or signature in order that the presented API
     *             is a more algorithmic mapping of the underlying native libraries.
     */
    public ConfEntry getEntry(String key, String locale,
            boolean useSchemaDefault) throws ConfException {
        Handle errorHandle = Struct.getNullHandle();
        Handle hndl = gconf_client_get_entry(getHandle(), key, locale,
                useSchemaDefault, errorHandle);
        checkError(errorHandle);
        return ConfEntry.getConfEntry(hndl);
    }

    /**
     * Return the default value stored in the key's schema, if the key has a
     * schema associated and the schema exists and the schema contains a default
     * value.
     * 
     * @param key
     * @throws ConfException
     * @deprecated Superceeded by java-gnome 4.0; this method may or may not
     *             exist in the new bindings but if it does, it will likely have 
     *             a different name or signature in order that the presented API
     *             is a more algorithmic mapping of the underlying native libraries.
     */
    public ConfValue getDefaultFromSchema(String key) throws ConfException {
        Handle errorHandle = Struct.getNullHandle();
        Handle hndl = gconf_client_get_default_from_schema(getHandle(), key,
                errorHandle);
        checkError(errorHandle);
        return ConfValue.getConfValue(hndl);
    }

    /**
     * Unsets the value of the provided key.
     * 
     * @param key
     * @throws ConfException
     * @deprecated Superceeded by java-gnome 4.0; this method may or may not
     *             exist in the new bindings but if it does, it will likely have 
     *             a different name or signature in order that the presented API
     *             is a more algorithmic mapping of the underlying native libraries.
     */
    public boolean unset(String key) throws ConfException {
        Handle errorHandle = Struct.getNullHandle();
        boolean ret = gconf_client_unset(getHandle(), key, errorHandle);
        checkError(errorHandle);
        return ret;
    }

    /**
     * Get a list of all ConfEntries in the provided direcotry.
     * 
     * @param dir
     * @throws ConfException
     * @deprecated Superceeded by java-gnome 4.0; this method may or may not
     *             exist in the new bindings but if it does, it will likely have 
     *             a different name or signature in order that the presented API
     *             is a more algorithmic mapping of the underlying native libraries.
     */
    public List getAllEntries(String dir) throws ConfException {
        Handle errorHandle = Struct.getNullHandle();
        Handle[] array = gconf_client_all_entries(getHandle(), dir, errorHandle);
        checkError(errorHandle);
        if (array == null)
            return null;
        List ret = new ArrayList();
        for (int i = 0; i < array.length; i++) {
            ret.add(ConfEntry.getConfEntry(array[i]));
        }
        return ret;
    }

    /**
     * Get a list of the subdirectories in the provided directory.
     * 
     * @param dir
     * @throws ConfException
     * @deprecated Superceeded by java-gnome 4.0; this method may or may not
     *             exist in the new bindings but if it does, it will likely have 
     *             a different name or signature in order that the presented API
     *             is a more algorithmic mapping of the underlying native libraries.
     */
    public List getAllDirs(String dir) throws ConfException {
        Handle errorHandle = Struct.getNullHandle();
        String[] array = gconf_client_all_dirs(getHandle(), dir, errorHandle);
        checkError(errorHandle);
        if (array == null)
            return null;
        List ret = new ArrayList();
        for (int i = 0; i < array.length; i++) {
            ret.add(array[i]);
        }
        return ret;
    }

    /**
     * Suggest to gconfd that you've just finished a block of changes and it
     * would be an optimal time to sync to permanent storage.
     * 
     * @throws ConfException
     * @deprecated Superceeded by java-gnome 4.0; this method may or may not
     *             exist in the new bindings but if it does, it will likely have 
     *             a different name or signature in order that the presented API
     *             is a more algorithmic mapping of the underlying native libraries.
     */
    public void suggestSync() throws ConfException {
        Handle errorHandle = gconf_client_suggest_sync(getHandle());
        checkError(errorHandle);
    }

    /**
     * Check to see if a directory exists in the GConf database.
     * 
     * @param dir
     * @throws ConfException
     * @deprecated Superceeded by java-gnome 4.0; this method may or may not
     *             exist in the new bindings but if it does, it will likely have 
     *             a different name or signature in order that the presented API
     *             is a more algorithmic mapping of the underlying native libraries.
     */
    public boolean dirExists(String dir) throws ConfException {
        Handle errorHandle = Struct.getNullHandle();
        boolean ret = gconf_client_dir_exists(getHandle(), dir, errorHandle);
        checkError(errorHandle);
        return ret;
    }

    /**
     * Request the double value stored at the provided key.
     * 
     * @param key
     * @throws ConfException
     * @deprecated Superceeded by java-gnome 4.0; this method may or may not
     *             exist in the new bindings but if it does, it will likely have 
     *             a different name or signature in order that the presented API
     *             is a more algorithmic mapping of the underlying native libraries.
     */
    public double getDouble(String key) throws ConfException {
        Handle errorHandle = Struct.getNullHandle();
        double ret = gconf_client_get_float(getHandle(), key, errorHandle);
        checkError(errorHandle);
        return ret;
    }

    /**
     * Request the int value stored at the provided key.
     * 
     * @param key
     * @throws ConfException
     * @deprecated Superceeded by java-gnome 4.0; this method may or may not
     *             exist in the new bindings but if it does, it will likely have 
     *             a different name or signature in order that the presented API
     *             is a more algorithmic mapping of the underlying native libraries.
     */
    public int getInt(String key) throws ConfException {
        Handle errorHandle = Struct.getNullHandle();
        int ret = gconf_client_get_int(getHandle(), key, errorHandle);
        checkError(errorHandle);
        return ret;
    }

    /**
     * Request the String value stored at the provided key.
     * 
     * @param key
     * @throws ConfException
     * @deprecated Superceeded by java-gnome 4.0; this method may or may not
     *             exist in the new bindings but if it does, it will likely have 
     *             a different name or signature in order that the presented API
     *             is a more algorithmic mapping of the underlying native libraries.
     */
    public String getString(String key) throws ConfException {
        Handle errorHandle = Struct.getNullHandle();
        String ret = gconf_client_get_string(getHandle(), key, errorHandle);
        checkError(errorHandle);
        return ret;
    }

    /**
     * Request the boolean value stored at the provided key.
     * 
     * @param key
     * @throws ConfException
     * @deprecated Superceeded by java-gnome 4.0; this method may or may not
     *             exist in the new bindings but if it does, it will likely have 
     *             a different name or signature in order that the presented API
     *             is a more algorithmic mapping of the underlying native libraries.
     */
    public boolean getBoolean(String key) throws ConfException {
        Handle errorHandle = Struct.getNullHandle();
        boolean ret = gconf_client_get_bool(getHandle(), key, errorHandle);
        checkError(errorHandle);
        return ret;
    }

    /**
     * Request the ConfSchema value stored at the provided key.
     * 
     * @param key
     * @throws ConfException
     * @deprecated Superceeded by java-gnome 4.0; this method may or may not
     *             exist in the new bindings but if it does, it will likely have 
     *             a different name or signature in order that the presented API
     *             is a more algorithmic mapping of the underlying native libraries.
     */
    public ConfSchema getSchema(String key) throws ConfException {
        Handle errorHandle = Struct.getNullHandle();
        Handle ret = gconf_client_get_schema(getHandle(), key, errorHandle);
        checkError(errorHandle);
        return ConfSchema.getConfSchema(ret);
    }

    /**
     * Request the object array stored at the key. The return object array is of
     * the type provided.
     * 
     * @param key
     * @param listType
     * @throws ConfException
     * @deprecated Superceeded by java-gnome 4.0; this method may or may not
     *             exist in the new bindings but if it does, it will likely have 
     *             a different name or signature in order that the presented API
     *             is a more algorithmic mapping of the underlying native libraries.
     */
    public Object[] getList(String key, ConfValueType listType)
            throws ConfException {
        Handle errorHandle = Struct.getNullHandle();
        Object[] list = gconf_client_get_list(getHandle(), key, listType
                .getValue(), errorHandle);
        checkError(errorHandle);
        return list;
    }

    /**
     * Change the value stored at the provided key to the provided double value.
     * 
     * @param key
     * @param value
     * @throws ConfException
     * @deprecated Superceeded by java-gnome 4.0; this method may or may not
     *             exist in the new bindings but if it does, it will likely have 
     *             a different name or signature in order that the presented API
     *             is a more algorithmic mapping of the underlying native libraries.
     */
    public boolean setDouble(String key, double value) throws ConfException {
        Handle errorHandle = Struct.getNullHandle();
        boolean ret = gconf_client_set_float(getHandle(), key, value,
                errorHandle);
        checkError(errorHandle);
        return ret;
    }

    /**
     * Change the value stored at the provided key to the provided int value.
     * 
     * @param key
     * @param value
     * @throws ConfException
     * @deprecated Superceeded by java-gnome 4.0; this method may or may not
     *             exist in the new bindings but if it does, it will likely have 
     *             a different name or signature in order that the presented API
     *             is a more algorithmic mapping of the underlying native libraries.
     */
    public boolean setInt(String key, int value) throws ConfException {
        Handle errorHandle = Struct.getNullHandle();
        boolean ret = gconf_client_set_int(getHandle(), key, value, errorHandle);
        checkError(errorHandle);
        return ret;
    }

    /**
     * Change the value stored at the provided key to the provided String value.
     * 
     * @param key
     * @param value
     * @throws ConfException
     * @deprecated Superceeded by java-gnome 4.0; this method may or may not
     *             exist in the new bindings but if it does, it will likely have 
     *             a different name or signature in order that the presented API
     *             is a more algorithmic mapping of the underlying native libraries.
     */
    public boolean setString(String key, String value) throws ConfException {
        Handle errorHandle = Struct.getNullHandle();
        boolean ret = gconf_client_set_string(getHandle(), key, value,
                errorHandle);
        checkError(errorHandle);
        return ret;
    }

    /**
     * Change the value stored at the provided key to the provided boolean
     * value.
     * 
     * @param key
     * @param value
     * @throws ConfException
     * @deprecated Superceeded by java-gnome 4.0; this method may or may not
     *             exist in the new bindings but if it does, it will likely have 
     *             a different name or signature in order that the presented API
     *             is a more algorithmic mapping of the underlying native libraries.
     */
    public boolean setBoolean(String key, boolean value) throws ConfException {
        Handle errorHandle = Struct.getNullHandle();
        boolean ret = gconf_client_set_bool(getHandle(), key, value,
                errorHandle);
        checkError(errorHandle);
        return ret;
    }

    /**
     * Change the value stored at the provided key to the provided ConfSchema
     * value.
     * 
     * @param key
     * @param value
     * @throws ConfException
     * @deprecated Superceeded by java-gnome 4.0; this method may or may not
     *             exist in the new bindings but if it does, it will likely have 
     *             a different name or signature in order that the presented API
     *             is a more algorithmic mapping of the underlying native libraries.
     */
    public boolean setSchema(String key, ConfSchema value) throws ConfException {
        Handle errorHandle = Struct.getNullHandle();
        boolean ret = gconf_client_set_schema(getHandle(), key, value
                .getHandle(), errorHandle);
        checkError(errorHandle);
        return ret;
    }

    public boolean setList(String key, ConfValueType listType, List value)
            throws ConfException {
        // FIXME MUSTDO
        return false;
    }

    public void notifyCallback() {

    }

    public void t() {

    }

    protected void notifyCallback(Handle e, String nameSpace) {
        if (listeners == null) {
            return;
        }
        NotifyData nd = (NotifyData) listeners.get(nameSpace);
        if (null == nd)
            return;
        ConfEntry entry = ConfEntry.getConfEntry(e);
        Vector notifyListeners = nd.listeners;
        if (null != notifyListeners) {
            for (int i = 0; i < notifyListeners.size(); i++) {
                NotifyClient nc = (NotifyClient) notifyListeners.elementAt(i);
                nc.lis.clientNotify(entry);
            }
        }
    }

    private void checkError(Handle errorHandle) throws ConfException {
        if (errorHandle == null) {
            return;
        }
        if (errorHandle.isNull()) {
            return;
        }
        Error error = new Error(errorHandle);
        throw new ConfException(error.getErrorCode());
    }

    native static final protected Handle gconf_client_get_default();

    native static final protected Handle gconf_client_get_for_engine(
            Handle engine);

    native static final protected Handle gconf_client_add_dir(Handle client,
            String dir, int preloadType);

    native static final protected Handle gconf_client_remove_dir(Handle client,
            String dir);

    native final protected int gconf_client_notify_add(Handle client,
            String namespace, Handle error);

    native static protected void gconf_client_notify_remove(Handle client,
            int cnxn);

    native static final protected void gconf_client_clear_cache(Handle client);

    native static final protected void gconf_client_preload(Handle client,
            String dirname, int type, Handle error);

    native static final protected void gconf_client_set(Handle client,
            String key, Handle val, Handle error);

    native static final protected Handle gconf_client_get(Handle client,
            String key, Handle error);

    native static final protected Handle gconf_client_get_without_default(
            Handle client, String key, Handle error);

    native static final protected Handle gconf_client_get_entry(Handle client,
            String key, String locale, boolean useSchemaDefault, Handle error);

    native static final protected Handle gconf_client_get_default_from_schema(
            Handle client, String key, Handle error);

    native static final protected boolean gconf_client_unset(Handle client,
            String key, Handle error);

    native static final protected Handle[] gconf_client_all_entries(
            Handle client, String dir, Handle error);

    native static final protected String[] gconf_client_all_dirs(Handle client,
            String dir, Handle error);

    native static final protected Handle gconf_client_suggest_sync(Handle client);

    native static final protected boolean gconf_client_dir_exists(
            Handle client, String dir, Handle error);

    native static final protected double gconf_client_get_float(Handle client,
            String key, Handle error);

    native static final protected int gconf_client_get_int(Handle client,
            String key, Handle error);

    native static final protected String gconf_client_get_string(Handle client,
            String key, Handle error);

    native static final protected boolean gconf_client_get_bool(Handle client,
            String key, Handle error);

    native static final protected Handle gconf_client_get_schema(Handle client,
            String key, Handle error);

    native static final protected Object[] gconf_client_get_list(Handle client,
            String key, int listType, Handle error);

    native static final protected boolean gconf_client_get_pair(Handle client,
            String key, int carType, int cdrType, int[] car, int[] cdr,
            Handle error);

    native static final protected boolean gconf_client_set_float(Handle client,
            String key, double val, Handle error);

    native static final protected boolean gconf_client_set_int(Handle client,
            String key, int val, Handle error);

    native static final protected boolean gconf_client_set_string(
            Handle client, String key, String val, Handle error);

    native static final protected boolean gconf_client_set_bool(Handle client,
            String key, boolean val, Handle error);

    native static final protected boolean gconf_client_set_schema(
            Handle client, String key, Handle val, Handle error);

    native static final protected boolean gconf_client_set_list(Handle client,
            String key, int listType, Object[] list, Handle error);

    native static final protected boolean gconf_client_set_pair(Handle client,
            String key, int carType, int cdrType, Handle car, Handle cdr, Handle error);

    native static final protected void gconf_client_value_changed(
            Handle client, String key, Handle value);

    static {
        System.loadLibrary(Config.LIBRARY_NAME + Config.GCONF_API_VERSION);
    }
}
