/*******************************************************************************
* 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 21-Nov-2004
 *
 */
package uk.ac.ic.doc.kevlar.gui.internal.widgets.tab;

import java.io.FileNotFoundException;

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

import uk.ac.ic.doc.kevlar.Kevlar;
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.caches.FontCache;
import uk.ac.ic.doc.kevlar.gui.internal.caches.ImageCache;
import uk.ac.ic.doc.kevlar.gui.internal.caches.Utils;
import uk.ac.ic.doc.kevlar.gui.internal.widgets.IClickListener;
import uk.ac.ic.doc.kevlar.gui.internal.widgets.INewDataListener;

/**
 * @author Daniel Burke
 *  
 */
public class Tab<T extends ADrawableObject> extends AMouseListenerObject implements IClickListener, INewDataListener {

	
	
    private static String SMALL_TAB_SKIN = "smallTab";
    private static String SMALL_TAB_NEW_DATA_SKIN = "smallTabNewData";
    private static String LARGE_TAB_SKIN = "largeTab";
    


    
    private static final int BUTTON_PADDING = 4;
    private static final int NAME_LEFT_PAD = 8;
    private static final int BUTTON_RIGHT_PAD = 8;
    //private static final int NAME_PADDING = 6;
    //private static final int TRIM_AMOUNT = 8;
    
    private static final int smallTabLeftWidth;
    private static final int smallTabRightWidth;
    private static final int smallTabHeight;
    private static final int largeTabLeftWidth;
    private static final int largeTabRightWidth;
    public static final int largeTabHeight;
    public static final int depthDifference;
    
    private static final int removeButtonWidth;
    private static final int removeButtonHeight;
    

    
    
    static
    {
        int smallTabLeftW = 0;
        int smallTabRightW = 0;
        int smallTabH = 0;
        int largeTabLeftW = 0;
        int largeTabRightW = 0;
        int largeTabH = 0;
        int removeButtonW = 0;
        int removeButtonH = 0;
        
        try
        {
            smallTabLeftW = ImageCache.get(SMALL_TAB_SKIN + Utils.LEFT).getImageData().width;
            smallTabRightW = ImageCache.get(SMALL_TAB_SKIN + Utils.RIGHT).getImageData().width;
            smallTabH = ImageCache.get(SMALL_TAB_SKIN + Utils.MIDDLE).getImageData().height;
            largeTabLeftW = ImageCache.get(LARGE_TAB_SKIN + Utils.LEFT).getImageData().width;
            largeTabRightW = ImageCache.get(LARGE_TAB_SKIN + Utils.RIGHT).getImageData().width;
            largeTabH = ImageCache.get(LARGE_TAB_SKIN + Utils.MIDDLE).getImageData().height;
            removeButtonW = ImageCache.get(TabRemoveButton.TAB_REMOVE_BUTTON_SKIN + Utils.NORMAL).getImageData().width;
            removeButtonH = ImageCache.get(TabRemoveButton.TAB_REMOVE_BUTTON_SKIN + Utils.NORMAL).getImageData().height;
        }
        catch(FileNotFoundException fnfe)
        {
            if(Kevlar.DEBUG)
            {
                fnfe.printStackTrace();
            }
        }
        
        smallTabLeftWidth = smallTabLeftW;
        smallTabRightWidth = smallTabRightW;
        smallTabHeight = smallTabH;
        largeTabLeftWidth = largeTabLeftW;
        largeTabRightWidth = largeTabRightW;
        largeTabHeight = largeTabH;   
        removeButtonWidth = removeButtonW;
        removeButtonHeight = removeButtonH;
        depthDifference = largeTabHeight - smallTabHeight;
    }

	public void mouseRelease(Point position, int mouseButton) {
		if(mouseButton == Utils.LEFT_MOUSE_BUTTON)
		{
			container.setSelected(this);
		}
		else if(mouseButton == Utils.MIDDLE_MOUSE_BUTTON)
		{
			container.removeTab(this);
		}
		
	}
    
    private String name;
    private int nameWidth = 0;
    private int nameHeight = -1;
    private int distanceFromSelected = 0;
    private int tabIndex = 0;
    private boolean newData = false;
    
    private T contents;
    private TabContainer<T> container = null;
    private TabRemoveButton removeButton = new TabRemoveButton();
    

    public Tab(String name, T contents) {
        this.name = name;
        this.contents = contents;
        
        removeButton.addListener(this);
        
        addChild(removeButton);
    }

    synchronized TabContainer<T> getContainer()
	{
    	return container;
	}
    
    public synchronized String getName() {
        return name;
    }
    
    public synchronized T getContents() {
        return contents;
    }

    public synchronized void drawBefore(GC gc, Rectangle redrawArea) {

        String tabSkin = newData ? SMALL_TAB_NEW_DATA_SKIN :  SMALL_TAB_SKIN;
 
        if(distanceFromSelected == 0)
        {
            Utils.drawHorizontalBar(gc, LARGE_TAB_SKIN, new Rectangle(0 - redrawArea.x, 0 - redrawArea.y, getSize().x, getSize().y));
        }
        else if(distanceFromSelected == -1)
        {
            Utils.drawHorizontalBar(gc, tabSkin, new Rectangle(0 - redrawArea.x, 0 - redrawArea.y, getSize().x, getSize().y), true, false);            
        }
        else if(distanceFromSelected == 1)
        {
            Utils.drawHorizontalBar(gc, tabSkin, new Rectangle(0 - redrawArea.x, 0 - redrawArea.y, getSize().x, getSize().y), false, true);            
        }
        else
        {
            Utils.drawHorizontalBar(gc, tabSkin, new Rectangle(0 - redrawArea.x, 0 - redrawArea.y, getSize().x, getSize().y));
        }
        

        int height = distanceFromSelected == 0 ?
                largeTabHeight : smallTabHeight;

        int nameStartOffset = NAME_LEFT_PAD;
        /*int nameStartOffset = NAME_PADDING + ( distanceFromSelected == 0 ?
                largeTabLeftWidth : (distanceFromSelected == 1 ?
                        0 : smallTabLeftWidth));
        /*( distanceFromSelected == 0 ?
                (tabIndex == 0 ? smallTabLeftWidth : 2 * smallTabLeftWidth) : (distanceFromSelected == 1 ?
                     0 : smallTabLeftWidth));  */ 
        
        gc.setFont(FontCache.get("Arial", 10, 0));
        gc.drawText(name, nameStartOffset - redrawArea.x, (height - nameHeight)/2 - redrawArea.y, true);
    }

    synchronized void setTabContainer(TabContainer<T> container) {
        this.container = container;
    }

    synchronized void refreshTabState(GC gc)
    {
    	tabIndex = container.getTabPosition(this);
        if(nameHeight == -1)
        {
            nameWidth = 0;
            for(char c : name.toCharArray())
            {
                nameWidth += gc.getCharWidth(c);
            }
            
            nameWidth += name.length() * 2;  
            nameHeight = gc.getFontMetrics().getHeight();
        }

        if(distanceFromSelected == 0)
        {
            newData = false;
        }
        
        int totalWidth = NAME_LEFT_PAD + nameWidth + BUTTON_PADDING + removeButtonWidth + BUTTON_RIGHT_PAD;
        
        setSize(new Point(totalWidth, (distanceFromSelected == 0 ? largeTabHeight : smallTabHeight)));
        removeButton.setPosition(
                new Point(
                        NAME_LEFT_PAD + nameWidth + BUTTON_PADDING,//(tabIndex == 0 ? smallTabLeftWidth : 2 * smallTabLeftWidth) , 
                        ((distanceFromSelected == 0 ? largeTabHeight : smallTabHeight) - removeButtonHeight)/2));
        
        /*
        if(distanceFromSelected == 0)
        {
            

                //largeTabLeftWidth + largeTabRightWidth + 2*BUTTON_PADDING + removeButtonWidth - TRIM_AMOUNT;
				//(tabIndex == 0 ? smallTabLeftWidth : 2 * smallTabLeftWidth) + 
				//2*smallTabRightWidth + 2*BUTTON_PADDING + removeButtonWidth;
            setSize(new Point(totalWidth, largeTabHeight));
            removeButton.setPosition(
                    new Point(
                            NAME_PADDING + nameWidth + BUTTON_PADDING + largeTabLeftWidth ,//(tabIndex == 0 ? smallTabLeftWidth : 2 * smallTabLeftWidth) , 
                            (largeTabHeight - removeButtonHeight)/2));
            
            newData = false;
        }
        else if(distanceFromSelected == -1)
        {
            
            int totalWidth = NAME_PADDING + nameWidth + smallTabLeftWidth + 2*BUTTON_PADDING + removeButtonWidth - TRIM_AMOUNT;
            setSize(new Point(totalWidth, smallTabHeight));
            removeButton.setPosition(
	            new Point(
	                    NAME_PADDING + nameWidth + smallTabLeftWidth + BUTTON_PADDING, 
	                    (smallTabHeight - removeButtonHeight)/2));            
        }
        else if(distanceFromSelected == 1)
        {
            
            int totalWidth = NAME_PADDING + nameWidth + smallTabRightWidth + 2*BUTTON_PADDING + removeButtonWidth - TRIM_AMOUNT;
            setSize(new Point(totalWidth, smallTabHeight));
            removeButton.setPosition(
    	            new Point(
    	                    NAME_PADDING + nameWidth + BUTTON_PADDING, 
    	                    (smallTabHeight - removeButtonHeight)/2));       
        }
        else
        {
            
            int totalWidth = NAME_PADDING + nameWidth + smallTabLeftWidth + smallTabRightWidth + 2*BUTTON_PADDING + removeButtonWidth - TRIM_AMOUNT;
            setSize(new Point(totalWidth, smallTabHeight));
            removeButton.setPosition(
    	            new Point(
    	                    NAME_PADDING + nameWidth + smallTabLeftWidth + BUTTON_PADDING, 
    	                    (smallTabHeight - removeButtonHeight)/2));    
        }*/
    }
    
    synchronized void setDistanceFromSelected(int distanceFromSelected)
    {
        this.distanceFromSelected = distanceFromSelected;
    }
    
    synchronized int getDistanceFromSelected()
    {
       return distanceFromSelected; 
    }
    
    
    public synchronized boolean capturesMouse() {
        
        return true;
        
    }

	public synchronized void clicked() {
		container.removeTab(this);
	}
	
	public synchronized boolean isRemoved()
	{
		return container == null;
	}
	
	public synchronized void newData()
	{
	    if(distanceFromSelected != 0 && !newData)
	    {
	        newData = true;
	        redraw();
	    }
	}
}
