/*******************************************************************************
* Copyright (c)                                                                *
*           2005   Tristan Allwood,                                            *
*           2005   Daniel Burke,                                               *
*           2005   Marc Hull,                                                  *
*           2005   Ekaterina Itskova,                                          *
*           2005   Steve Zymler                                                *
*                                                                              *
* Permission is hereby granted, free of charge, to any person obtaining a      *
* copy of this software and associated documentation files (the                *
* "Software"), to deal in the Software without restriction, including          *
* without limitation the rights to use, copy, modify, merge, publish,          *
* distribute, sublicense, and/or sell copies of the Software, and to           *
* permit persons to whom the Software is furnished to do so, subject to        *
* the following conditions:                                                    *
*                                                                              *
* The above copyright notice and this permission notice shall be included      *
* in all copies or substantial portions of the Software.                       *
*                                                                              *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS      *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF                   *
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.       *
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY         *
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,         *
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE            *
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                       *
*******************************************************************************/
/*
 * Created on 17-Nov-2004
 *
 */
package uk.ac.ic.doc.kevlar.gui.internal.widgets.listbox;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;

import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;

import uk.ac.ic.doc.kevlar.gui.internal.ADrawableObject;
import uk.ac.ic.doc.kevlar.gui.internal.AMouseListenerObject;
import uk.ac.ic.doc.kevlar.gui.internal.animation.AAnimation;
import uk.ac.ic.doc.kevlar.gui.internal.animation.AnimationGroupListenerEntry;
import uk.ac.ic.doc.kevlar.gui.internal.animation.AnimationManager;
import uk.ac.ic.doc.kevlar.gui.internal.animation.IAnimationListener;
import uk.ac.ic.doc.kevlar.gui.internal.caches.ColorCache;
import uk.ac.ic.doc.kevlar.gui.internal.widgets.IScrollingWindow;
import uk.ac.ic.doc.kevlar.gui.internal.widgets.StretchyBox;
import uk.ac.ic.doc.kevlar.gui.internal.widgets.scrollbars.AScrollbar;
import uk.ac.ic.doc.kevlar.gui.internal.widgets.scrollbars.VerticalScrollBar;

/**
 * @author Marc
 **/
public class ListBox extends AMouseListenerObject implements IScrollingWindow, IAnimationListener {

    public static final int ENTRY_LIST_WIDTH = 150;
    public static final String DEFAULT_SKIN = "unknownheading";
    
    protected VerticalScrollBar scrollbar;
    protected StretchyBox contents;
    protected ArrayList<ListEntry> entries;
    protected ArrayList data;
    protected IListSelectionListener listener;
    protected String filter;
    protected int selectedEntry;
    protected boolean drawBackground;
    
    public ListBox() {
        
        super();
        
        scrollbar = new VerticalScrollBar(this);
        contents = new StretchyBox(false, true);
        entries = new ArrayList<ListEntry>();
        filter = "";
        drawBackground = false;
        selectedEntry = -1;
        
        super.addChild(scrollbar);        
        super.addChild(contents);
        
    }
    
    public void drawBefore(GC gc, Rectangle redrawArea) {
        
        if (drawBackground) {
            
            gc.setForeground(ColorCache.get(255, 255, 255));
            gc.setBackground(ColorCache.get(255, 255, 255));
            gc.fillRectangle(redrawArea);
            
        }
        
    }
    
    public void setDrawBackground(boolean drawBackground) {
        
        this.drawBackground = drawBackground;
        
    }
    
    public void setData(Collection data) {
    	
    	this.data = new ArrayList(data);
    	update();
    	
    }
    
    public void setFilter(String filter) {
        
        this.filter = filter.toLowerCase();
        update();
        
    }
    
    public void setSelectionListener(IListSelectionListener listener) {
        
        this.listener = listener;
        
    }
    
    public void entrySelected(Object entry) {
        
        if (listener != null) {
            
            listener.entrySelected(entry);
            
        }
        
    }
    
    public boolean matchesFilter(String text) {
        
        return text.toLowerCase().startsWith(filter);
        
    }
    
    protected void update() {
    	
/*        contents.removeAllChildren();
        entries.clear(); */
        
        int j = 0;
        
        while (j < entries.size()) {
            
            ListEntry entry = entries.get(j);
            boolean found = false;
            
            for (Object o : data) {
                
                if (o == entry.getData() && matchesFilter(entry.getText())) {
                    
                    found = true;
                    
                }
                
            }
            
            if (!found) {
                
                entry.deselect();
                entry.dispose();
                entries.remove(entry);
                
            } else {
                
                j++;
                
            }
            
        }
        
        ArrayList<AAnimation> anims = new ArrayList<AAnimation>();
        int positionIndex = 0;
        
    	for (int i=0; i<data.size(); i++) {
    	    
    	    Object o = data.get(i);
    	    ListEntry entry = getEntry(o);
    	    
    	    if (entry != null) {
    	        
    	        anims.add(entry.setIndex(positionIndex));
        	    positionIndex++;
    	        
    	    } else {
    	    
    	        entry = createEntry(o, positionIndex);
    	        
    	        if (entry != null && matchesFilter(entry.getText())) {
    	        
    	            entries.add(entry);
    	            addChild(entry);
    	            positionIndex++;
    	            
    	        }
    	        
    	    }
    	    
    	}
    	
    	AnimationManager.getSingleton().addAnimationListener(new AnimationGroupListenerEntry(this, anims));
    	Collections.sort(entries);
//    	selectEntry(0);
    	
    }
    
    protected ListEntry createEntry(Object o, int index) {
        
        return new ListEntry(this, index, o, DEFAULT_SKIN);
        
    }
    
    protected ListEntry getEntry(Object o) {
        
        for (ListEntry entry : entries) {
            
            if (!entry.isDisposed() && entry.getData() == o) {
                
                return entry;
                
            }
            
        }
        
        return null;
        
    }
    
    public int entryCount() {
        
        return entries.size();
        
    }
    
    public void selectEntry(int i) {
        
        for (int j=0; j<entries.size(); j++) {
            
            entries.get(j).deselect();
            
        }
        
        if (i >= 0 && i < entries.size()) {
            
            entries.get(i).select();
            selectedEntry = i;            
            scrollToChild(entries.get(i));
                
        } else {
            
            selectedEntry = -1;
            
        }
        
    }
    
    public void moveSelectionUp() {

        if (selectedEntry <= 0) {
            
            selectedEntry = entryCount();
            
        }
        
        selectedEntry--;            
        selectEntry(selectedEntry);
                
    }
    
    public void moveSelectionDown() {
                
        selectedEntry++;            
        
        if (selectedEntry == entryCount()) {
            
            selectedEntry = 0;
            
        }
        
        selectEntry(selectedEntry);
        
    }
    
    public void scrollToChild(ADrawableObject child) {
        
        Rectangle childArea = child.getAreaRelativeTo(this);
        
        if (childArea.y+childArea.height > area.height) {
            
            contents.setPosition(new Point(0, contents.getPosition().y-((childArea.y+childArea.height)-area.height)));
            scrollbar.updateFromWindow();
            
        } else if (childArea.y < 0) {
            
            contents.setPosition(new Point(0, contents.getPosition().y-childArea.y));
            scrollbar.updateFromWindow();
                        
        }
        
    }
    
    public int getSelectedIndex() {
        
        return selectedEntry;
        
    }
    
    public ListEntry getEntry(int i) {
        
        if (i >= 0 && i < entries.size()) {
            
            return entries.get(i);
            
        }
        
        return null;
        
    }
    
    public void addChild(ADrawableObject child) {
        
        contents.addChild(child);
        
    }
    
    public void removeChild(ADrawableObject child) {
        
        contents.removeChild(child);
        
    }
    
    public void removeAllChildren() {
        
        contents.removeAllChildren();
        
    }
    
    public void setHorizontalPosition(int position) {
        
        contents.setPosition(new Point(-position, contents.getPosition().y));
        redraw();
        applyRedraw();
        
    }
    
    public void setVerticalPosition(int position) {
        
        contents.setPosition(new Point(contents.getPosition().x, -position));
        redraw();
        applyRedraw();
        
    }
    
    public int getHorizontalPosition() {
        
        return -contents.getPosition().x;
        
    }
    
    public int getVerticalPosition() {
        
        return -contents.getPosition().y;
        
    }
    
    public void updateDimensions() {
        
        super.updateDimensions();
        scrollbar.setSize(area.height);
        contents.setSize(new Point(area.width-AScrollbar.SCROLLBAR_SIZE, 0));
        
    }
    
    public void childDimensionsChanged(ADrawableObject child) {
        
        if (child == contents) {
            
            scrollbar.setMaximum(child.getSize().y);
            
        }
        
    }

    public ADrawableObject getContents() {
        
        return contents;
        
    }
    
    public boolean capturesMouse() {
        
        return true;
        
    }

    public void animationFinished() {
        
        if (selectedEntry >= 0 && selectedEntry < entries.size()) {
            
            scrollToChild(entries.get(selectedEntry));
            
        }
        
    }
    
}
