package org.argosdic.dictionary;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.document.Document;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.JFacePreferences;
import org.eclipse.jface.util.Assert;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.ListenerList;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.widgets.Event;

/**
 * SearchHistory.java
 * 
 * @author Xavier Cho
 * @version $Revision: 1.10 $ $Date: 2003/10/19 14:41:35 $
 */
public class SearchHistory {
    private static Log log = LogFactory.getLog(SearchHistory.class);

    private List words;
    private Map documents;
    private int historySize;
    private int currentIndex = 0;
    private ListenerList listeners;

    public SearchHistory() {
        IPreferenceStore preferences = JFacePreferences.getPreferenceStore();

        preferences.addPropertyChangeListener(new IPropertyChangeListener() {
            public void propertyChange(PropertyChangeEvent event) {
                createMap();
            }
        });

        createMap();
    }

    private void createMap() {
        synchronized (this) {
            IPreferenceStore preferences =
                JFacePreferences.getPreferenceStore();

            int value = preferences.getInt("history.size"); //$NON-NLS-1$
            Assert.isTrue(value > 0);

            this.historySize = value;

            List list = new ArrayList(historySize);
            Map map = new HashMap(historySize);

            if (words != null) {
                if (words.size() > historySize) {
                    list.addAll(words.subList(0, historySize - 1));
                } else {
                    list.addAll(words);
                }

                Iterator it = list.iterator();
                while (it.hasNext()) {
                    String word = (String) it.next();
                    map.put(word, documents.get(word));
                }
            }

            this.words = list;
            this.documents = map;
        }
    }

    public void add(Document document) {
        String word = document.getField("word").stringValue(); //$NON-NLS-1$

        if (log.isDebugEnabled()) {
            String msg = "Added to search history : " + word; //$NON-NLS-1$
            log.debug(msg);
        }

        words.add(currentIndex, word);

        if (documents.containsKey(word)) {
            int size = words.size();

            for (int i = 0; i < size; i++) {
                String value = (String) words.get(i);
                if (word.equals(value)) {
                    words.remove(i);
                    break;
                }
            }
        } else {
            currentIndex++;
        }

        while (currentIndex < words.size()) {
            int index = words.size() - 1;
            String value = (String) words.get(index);
            words.remove(index);
            documents.remove(value);
        }

        documents.put(word, document);

        while (words.size() > historySize) {
            word = (String) words.get(0);
            documents.remove(word);
            words.remove(0);

            currentIndex--;
        }

        fireHistoryUpdated();
    }

    public String forward() {
        String word = null;

        if (isForwardEnabled()) {
            currentIndex++;
            word = (String) words.get(currentIndex - 1);
        }

        fireHistoryUpdated();

        return word;
    }

    public String back() {
        String word = null;

        if (isBackEnabled()) {
            currentIndex--;
            word = (String) words.get(currentIndex - 1);
        }

        fireHistoryUpdated();

        return word;
    }

    public String go(int index) {
        String word = null;

        if (index >= 0 && index < words.size()) {
            currentIndex = index + 1;
            word = (String) words.get(index);

            fireHistoryUpdated();
        }

        return word;
    }

    public boolean isBackEnabled() {
        return (currentIndex > 1);
    }

    public boolean isForwardEnabled() {
        return (currentIndex < words.size());
    }

    public Document get(String word) {
        Assert.isNotNull(word);

        return (Document) documents.get(word);
    }

    public int getSize() {
        return words.size();
    }

    public List getBackwardHistory() {
        List list = null;

        synchronized (words) {
            if (words.size() > 0) {
                list = words.subList(0, currentIndex - 1);
                list = new ArrayList(list);

                Collections.reverse(list);
            } else {
                list = new ArrayList(0);
            }
        }

        return list;
    }

    public List getForwardHistory() {
        List list = null;

        synchronized (words) {
            if (words.size() > 0) {
                list = words.subList(currentIndex, words.size());
                list = new ArrayList(list);
            } else {
                list = new ArrayList(0);
            }
        }

        return list;
    }

    public int getCurrentIndex() {
        return currentIndex - 1;
    }

    public void clear() {
        synchronized (this) {
            this.currentIndex = 0;
            this.words.clear();
            this.documents.clear();
        }

        fireHistoryUpdated();
    }

    public void addHistoryListener(HistoryListener listener) {
        Assert.isNotNull(listener);

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

    public void removeHistoryListener(HistoryListener listener) {
        Assert.isNotNull(listener);

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

    protected void fireHistoryUpdated() {
        if (listeners != null) {
            Object[] array = null;
            synchronized (listeners) {
                array = listeners.getListeners();
            }

            Event event = new Event();

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