package org.argosdic.dictionary;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.JFacePreferences;
import org.eclipse.jface.util.Assert;
import org.eclipse.jface.util.ListenerList;

/**
 * DictionaryManager.java
 * @author Xavier Cho
 * @version $Revision: 1.2 $ $Date: 2003/09/27 07:44:39 $
 */
public class DictionaryManager {
    private static DictionaryManager instance;

    private static Log log = LogFactory.getLog(DictionaryManager.class);

    private static final int EVENT_DICTIONARY_UPDATED = 0;
    private static final int EVENT_DICTIONARY_CHANGED = 1;

    private ListenerList listeners;
    private Map dictionaries;
    private Dictionary selectedDictionary;

    private DictionaryManager() {
        initialize();
    }

    public void initialize() {
        if (log.isInfoEnabled()) {
            log.info("Initializing DictionaryManager..."); //$NON-NLS-1$
        }

        IPreferenceStore preferences = JFacePreferences.getPreferenceStore();

        String path = preferences.getString("data.dir"); //$NON-NLS-1$

        if (log.isInfoEnabled()) {
            log.info("Searching for dictionaries : " + path); //$NON-NLS-1$
        }

        File dataDir = new File(path);

        if (!dataDir.exists() || !dataDir.isDirectory()) {
            String msg = "The specified path is not a valid data directory."; //$NON-NLS-1$
            log.warn(msg);

            return;
        }

        File[] files = dataDir.listFiles();

        int count = files.length;

        this.dictionaries = new HashMap(count);

        for (int i = 0; i < count; i++) {
            File dir = files[i];

            if (dir.isDirectory()) {
                StringBuffer buffer = new StringBuffer();
                buffer.append(dir.getAbsolutePath());
                buffer.append(File.separator);
                buffer.append("dictionary.properties"); //$NON-NLS-1$

                try {
                    String id = dir.getName();

                    File descriptor = new File(buffer.toString());
                    addDictionary(id, descriptor);
                } catch (Exception e) {
                    if (log.isWarnEnabled()) {
                        String msg = "Unable to read directory file : " + e.toString(); //$NON-NLS-1$
                        log.warn(msg, e);
                    }
                }
            }
        }

        fireDictionaryUpdated();
    }

    private void addDictionary(String id, File descriptor) throws IOException {
        if (descriptor.exists()) {
            if (log.isDebugEnabled()) {
                log.debug("Processing : " + descriptor.getAbsolutePath()); //$NON-NLS-1$
            }

            InputStream in = null;
            try {
                in = new FileInputStream(descriptor);
                in = new BufferedInputStream(in);

                Properties props = new Properties();
                props.load(in);

                Dictionary dictionary = new Dictionary(id, props);
                dictionaries.put(dictionary.getId(), dictionary);

                if (log.isInfoEnabled()) {
                    log.info("Added new dictionary : "); //$NON-NLS-1$
                    log.info("  - id : " + dictionary.getId()); //$NON-NLS-1$
                    log.info("  - name : " + dictionary.getName()); //$NON-NLS-1$
                    log.info("  - analyzer : " + dictionary.getAnalyzer()); //$NON-NLS-1$
                    log.info("  - description : " + dictionary.getDescription()); //$NON-NLS-1$
                    log.info("  - copyright : " + dictionary.getCopyright()); //$NON-NLS-1$
                }
            } finally {
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                    }
                }
            }
        }
    }

    public Dictionary getDictionary(String id) {
        Assert.isNotNull(id);

        if (dictionaries == null) {
            String msg = "DictionaryManager has not been initialized."; //$NON-NLS-1$
            throw new IllegalStateException(msg);
        }

        return (Dictionary) dictionaries.get(id);
    }

    public int getDictionaryCount() {
        return dictionaries != null ? dictionaries.size() : 0;
    }

    public Iterator getDictionaries() {
        if (dictionaries == null) {
            String msg = "DictionaryManager has not been initialized."; //$NON-NLS-1$
            throw new IllegalStateException(msg);
        }

        return dictionaries.values().iterator();
    }

    public void addDictionaryListener(DictionaryListener listener) {
        Assert.isNotNull(listener);

        if (listeners == null) {
            synchronized (this) {
                this.listeners = new ListenerList(30);
            }
        }
        listeners.add(listener);
    }

    /**
     * @return
     */
    public Dictionary getSelectedDictionary() {
        return selectedDictionary;
    }

    /**
     * @param id
     */
    public void setSelectedDictionary(String id) {
        Assert.isNotNull(id);
        this.selectedDictionary = (Dictionary) dictionaries.get(id);

        fireDictionaryChanged();
    }

    public void removeDictionaryListener(DictionaryListener listener) {
        Assert.isNotNull(listener);

        if (listeners != null) {
            listeners.remove(listener);
        }
    }

    protected void fireDictionaryUpdated() {
        fireDictionaryEvent(EVENT_DICTIONARY_UPDATED);
    }

    protected void fireDictionaryChanged() {
        if (log.isInfoEnabled() && selectedDictionary != null) {
            log.info("Use dictionary : " + selectedDictionary.getName()); //$NON-NLS-1$ //$NON-NLS-2$
        }

        fireDictionaryEvent(EVENT_DICTIONARY_CHANGED);
    }

    private void fireDictionaryEvent(int eventCode) {
        if (listeners != null) {
            Object[] array = null;
            synchronized (listeners) {
                array = listeners.getListeners();
            }

            DictionaryEvent event =
                new DictionaryEvent(this, selectedDictionary);

            if (array != null) {
                for (int i = 0; i < array.length; i++) {
                    DictionaryListener listener = (DictionaryListener) array[i];

                    switch (eventCode) {
                        case EVENT_DICTIONARY_CHANGED :
                            listener.dictionaryChanged(event);
                            break;
                        case EVENT_DICTIONARY_UPDATED :
                            listener.dictionaryUpdated(event);
                            break;
                    }
                }
            }
        }
    }

    public static DictionaryManager getInstance() {
        if (instance == null) {
            synchronized (DictionaryManager.class) {
                instance = new DictionaryManager();
            }
        }
        return instance;
    }
}
