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

import java.awt.image.BufferedImage;
import java.io.FileNotFoundException;
import java.io.IOException;

import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Display;

import uk.ac.ic.doc.kevlar.Kevlar;
import uk.ac.ic.doc.kevlar.core.types.imageTypes.ImageTypeImpl;
import uk.ac.ic.doc.kevlar.gui.internal.ADrawableObject;
import uk.ac.ic.doc.kevlar.gui.internal.CanvasManager;
import uk.ac.ic.doc.kevlar.gui.internal.animation.AAnimation;
import uk.ac.ic.doc.kevlar.gui.internal.animation.AnimationListenerEntry;
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.animation.SlideAnimation;
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.dragdrop.ADraggableObject;
import uk.ac.ic.doc.kevlar.gui.internal.toolbar.ToolBarManager;
import uk.ac.ic.doc.kevlar.gui.internal.widgets.IClickListener;
import uk.ac.ic.doc.kevlar.gui.internal.widgets.INewDataListener;
import uk.ac.ic.doc.kevlar.gui.internal.widgets.swing.ConvertSwtAwt;
import uk.ac.ic.doc.kevlar.gui.internal.widgets.tab.ITabListener;
import uk.ac.ic.doc.kevlar.gui.internal.widgets.tab.Tab;
import uk.ac.ic.doc.kevlar.gui.internal.widgets.tab.TabContainer;
import uk.ac.ic.doc.kevlar.gui.internal.workbench.WorkBenchManager;
import uk.ac.ic.doc.kevlar.gui.showers.IShower;
import uk.ac.ic.doc.kevlar.gui.showers.IShowerProvider;
import uk.ac.ic.doc.kevlar.gui.showers.image.ImageShower;
import uk.ac.ic.doc.kevlar.gui.showers.image.ImageShowerProvider;

/**
 * @author Daniel Burke
 * 
 */
public class ShowPaneManager extends ADraggableObject implements
        ITabListener<ADrawableObject>, INewDataListener
{

    private static ShowPaneManager singleton;

    private static final int SHOW_PANE_DEFAULT_HEIGHT = 150;

    private static final String SHOW_PANE_TITLE_SKIN = "showPaneTitle";

    private static final String SHOW_PANE_BAR_LEFT_SKIN = "showPaneResizerBarA";

    private static final String SHOW_PANE_BAR_RIGHT_SKIN = "showPaneResizerBarB";
    
    //private static final String SHOW_PANE_LEFT_BORDER_SKIN = "showBorderLeft";
    
    //private static final String SHOW_PANE_RIGHT_BORDER_SKIN = "showBorderRight";
    
    private static final String SHOW_PANE_BOTTOM_BORDER_SKIN = "showBorderBottom";

    private static final int BUFFER = 80;

    private static final int showPaneTitleHeight;

    private static final int showPaneBarHeight;
    
    private static final int showPaneBorderWidth;
    
    private static final int showPaneBottomBarHeight;

    private static final int minimumSize;
    
    private static final Image showPaneBodyImage;
    
    private static final Image showPaneLeftBorderImage;
    
    private static final Image showPaneRightBorderImage;
    
    private static final Image showPaneTabRestImage;

    static
    {
        int showPaneDefaultTitleH = 0;
        int showPaneBarH = 0;
        int showPaneBorderW = 0;
        int showPaneBottomBarH = 0;
        Image showPaneBodyI = null;
        Image showPaneLeftBorderI = null;
        Image showPaneRightBorderI = null;
        Image showPaneTabRestI = null;
        
        try
        {
            showPaneBodyI = ImageCache.get("showPaneBody_top.png");
            showPaneLeftBorderI = ImageCache.get("showBorderLeft_top.png");
            showPaneRightBorderI = ImageCache.get("showBorderRight_top.png");
            showPaneTabRestI = ImageCache.get("showPaneTabRest.png");
            
            showPaneDefaultTitleH = ImageCache.get(
                    SHOW_PANE_TITLE_SKIN + Utils.MIDDLE).getImageData().height;
            showPaneBarH = ImageCache.get(
                    SHOW_PANE_BAR_LEFT_SKIN + Utils.MIDDLE).getImageData().height;
            
            showPaneBorderW = showPaneLeftBorderI.getImageData().width;
            showPaneBottomBarH = ImageCache.get(
                    SHOW_PANE_BOTTOM_BORDER_SKIN + Utils.MIDDLE).getImageData().height;
        }
        catch (FileNotFoundException fnfe)
        {
            if(Kevlar.DEBUG)
            {
                fnfe.printStackTrace();
            }
        }

        showPaneTitleHeight = showPaneDefaultTitleH;
        showPaneBarHeight = showPaneBarH;
        showPaneBorderWidth = showPaneBorderW;
        showPaneBottomBarHeight = showPaneBottomBarH;
        
        showPaneBodyImage = showPaneBodyI;
        showPaneLeftBorderImage = showPaneLeftBorderI;
        showPaneRightBorderImage = showPaneRightBorderI;
        showPaneTabRestImage = showPaneTabRestI;

        minimumSize = showPaneBarHeight + showPaneTitleHeight + 40;
        
    }

    TabContainer<ADrawableObject> tabs;

    private ShowPaneExecutionManager spem;

    private HorizontalShowHideButton showHideButton;

    private boolean expanded = false;

    private int size = SHOW_PANE_DEFAULT_HEIGHT;

    private class ExpandAnimationListener implements IAnimationListener {

        public void animationFinished() {
            
            WorkBenchManager.getSingleton().showPaneResized(area.height);
            tabs.show();
        }
                
    }
    
    private class ContractAnimationListener implements IAnimationListener {

        public void animationFinished() {
            
            tabs.hide();
            
        }
                
    }
    
    private class ShowHideButtonClickHandler implements IClickListener
    {
        public void clicked()
        {
            toggleExpanded();
        }
    }

    public ShowPaneManager()
    {
        spem = new ShowPaneExecutionManager(this);

        setSizeFillBoth(new Point(0, 0));
        setAlignment(false, true);

        showHideButton = new HorizontalShowHideButton();
        addChild(showHideButton);
        showHideButton.addListener(new ShowHideButtonClickHandler());

        tabs = new TabContainer<ADrawableObject>();
        tabs.setPosition(new Point(showPaneBorderWidth, showPaneBarHeight));
        // tabs.setAlignment(false, true);
        tabs.setSizeFillBoth(new Point(showPaneBorderWidth, showPaneBottomBarHeight));
        tabs.hide();
        
        addChild(tabs);

        setPosition(new Point(0, showPaneBarHeight));
        setExpanded(false);
        
        /*
        try
        {
        ImageShower s = (ImageShower)addShower("Test", new ImageShowerProvider());
        BufferedImage b = ConvertSwtAwt.convertToAWT( ImageCache.get("background2.png").getImageData() );
        //s.addObject(new ImageTypeImpl(b));
        //s.addObject(new ImageTypeImpl(b));
        //s.setZoom(0.5);
        }
        catch(IOException e)
        {
            
        }*/
        
        /*
         * TextShower shower = new TextShower();
         * 
         * Tab <ADrawableObject> t = new Tab <ADrawableObject>("Moshi Moshi",
         * new TestColouredSquare(0, 0, 255));
         * 
         * tabs.addTab(new Tab <ADrawableObject>("Default output", shower));
         * tabs.addTab(new Tab <ADrawableObject>("Hello2", new
         * TestColouredSquare(0, 0, 0))); tabs.addTab(new Tab
         * <ADrawableObject>("Hello", new TestColouredSquare(255, 0, 0)));
         * tabs.addTab(new Tab <ADrawableObject>("Goodbye", new
         * TestColouredSquare(0, 255, 0))); tabs.addTab(t); tabs.addTab(new Tab
         * <ADrawableObject>("Jaa, mata", new TestColouredSquare(255, 255, 0)));
         * 
         * t.setNewData();
         * 
         * 
         * shower.addObject(new TextTypeImpl("Hello there\n"));
         * shower.addObject(new TextTypeImpl("Hello there again\n"));
         * shower.addObject(new TextTypeImpl("Hello there2\n"));
         * shower.addObject(new TextTypeImpl("Hello there again2\n"));
         */

    }

    public static ShowPaneManager getSingleton()
    {

        return singleton;

    }

    public static void createSingleton()
    {

        if(singleton == null)
        {
            singleton = new ShowPaneManager();
        }

    }

    private synchronized void updateShowHideButtonPosition()
    {
        Point pos = new Point((getSize().x - showHideButton.getSize().x) / 2, 0);
        showHideButton.setPosition(pos);
    }

    synchronized void toggleExpanded()
    {
        setExpanded(!expanded);
    }

    public void expand() {
        
        setExpanded(true);
        
    }
    
    public void contract() {
        
        setExpanded(false);
        
    }
    
    private synchronized void setExpanded(boolean expanded)
    { 
        this.showHideButton.setAttentionSeeking(false);
        
        showHideButton.setExpanded(expanded);
        this.expanded = expanded;

        if(expanded)
        {
//            setPosition(new Point(0, size));
            AAnimation anim = new SlideAnimation(this, new Point(0, size));
            AnimationListenerEntry listener = new AnimationListenerEntry(new ExpandAnimationListener(), anim);
            AnimationManager.getSingleton().addAnimationListener(listener);
            AnimationManager.getSingleton().addAnimation(anim);
            //tabs.show();
            tabs.hide();

        }
        else
        {
//            setPosition(new Point(0, showPaneBarHeight));
            AAnimation anim = new SlideAnimation(this, new Point(0, showPaneBarHeight));
            AnimationListenerEntry listener = new AnimationListenerEntry(new ContractAnimationListener(), anim);
            AnimationManager.getSingleton().addAnimationListener(listener);
            AnimationManager.getSingleton().addAnimation(anim);

            if (WorkBenchManager.getSingleton() != null) {
                
                WorkBenchManager.getSingleton().showPaneResized(10);
                
            }
            tabs.hide();            
        }
    }
    
    public boolean isExpanded() {
        
        return expanded;
        
    }

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

        Rectangle drawArea = new Rectangle(0 - redrawArea.x, 0 - redrawArea.y,
                getSize().x / 2, showPaneBarHeight);

        Utils.drawHorizontalBar(gc, SHOW_PANE_BAR_LEFT_SKIN, drawArea);

        drawArea.x = getSize().x / 2 - redrawArea.x;
        drawArea.width = getSize().x - getSize().x / 2;

        Utils.drawHorizontalBar(gc, SHOW_PANE_BAR_RIGHT_SKIN, drawArea);

        if(getPosition().y == showPaneBarHeight)
        {
            return;
        }
        // From here on draw stuff that isn't visible when not expanded

        drawArea.x = 0 - redrawArea.x;
        drawArea.y = showPaneBarHeight - redrawArea.y;
        drawArea.width = showPaneBorderWidth;
        drawArea.height = getSize().y - showPaneBarHeight;
        
        Utils.drawImage(gc, showPaneLeftBorderImage, drawArea);
        
        //Utils.drawVerticalBar(gc, SHOW_PANE_LEFT_BORDER_SKIN, drawArea, true, false);
        
        drawArea.x = getSize().x - showPaneBorderWidth - redrawArea.x;;
        
        Utils.drawImage(gc, showPaneRightBorderImage, drawArea);
        //Utils.drawVerticalBar(gc, SHOW_PANE_RIGHT_BORDER_SKIN, drawArea, true, false);
        
        
        drawArea.x = showPaneBorderWidth - redrawArea.x;
        drawArea.y = showPaneBarHeight - redrawArea.y;
        drawArea.width = getSize().x - showPaneBorderWidth * 2;
        drawArea.height = Tab.largeTabHeight + 1;
        
        Utils.drawImage(gc, showPaneTabRestImage, drawArea);
        
        drawArea.y = Tab.largeTabHeight + showPaneBarHeight + 1 - redrawArea.y;
        drawArea.height = getSize().y - Tab.largeTabHeight - showPaneBarHeight - showPaneBottomBarHeight - 1;
        
        Utils.drawImage(gc, showPaneBodyImage, drawArea);
        
        drawArea.x = 0 - redrawArea.x;
        drawArea.y = getSize().y - showPaneBottomBarHeight - redrawArea.y;
        drawArea.width = getSize().x;
        drawArea.height = showPaneBottomBarHeight;
        
        Utils.drawHorizontalBar(gc, SHOW_PANE_BOTTOM_BORDER_SKIN, drawArea);
        /*
        
        gc.setBackground(ColorCache.get(210, 210, 210));
        gc.fillRectangle(
                showPaneBorderWidth - redrawArea.x, 
                showPaneBarHeight - redrawArea.y, 
                getSize().x - showPaneBorderWidth * 2,
                Tab.largeTabHeight);
        gc.setBackground(ColorCache.get(210, 210, 210));
        gc.fillRectangle(
                showPaneBorderWidth - redrawArea.x, 
                showPaneBarHeight - redrawArea.y, 
                getSize().x - showPaneBorderWidth * 2,
                Tab.largeTabHeight);
        */
        

        
        
        /*
        drawArea.x = 0 - redrawArea.x;
        drawArea.y = showPaneBarHeight - redrawArea.y;
        drawArea.width = getSize().x;
        drawArea.height = showPaneTitleHeight;

        Utils.drawHorizontalBar(gc, SHOW_PANE_TITLE_SKIN, drawArea);
        
        
        // gc.setBackground(ColorCache.get(0, 0, 0));

        // gc.fillRectangle(0 - redrawArea.x, 0-redrawArea.y, getSize().x,
        // SHOW_PANE_TITLE_HEIGHT );

        /*gc.setBackground(ColorCache.get(188, 192, 202));
        gc.fillRectangle(0 - redrawArea.x, showPaneTitleHeight
                + showPaneTitleHeight - redrawArea.y, getSize().x,
                SHOW_PANE_DEFAULT_HEIGHT - showPaneTitleHeight);
                *
        
        gc.setForeground(ColorCache.get(255, 255, 255));
        gc.setFont(FontCache.get("Arial", 10, SWT.BOLD));
        gc.drawText("Output", 8 - redrawArea.x, showPaneBarHeight
                - redrawArea.y, true);
        */
    }

    public synchronized void TabRemoved(Tab<ADrawableObject> t)
    {
        //spem.showerOutOfAction(t.getName(), (IShower) t.getContents());
    }

    public synchronized void TabSelected(Tab<ADrawableObject> t)
    {
        /* Do nothing */
    }

    private class AddShower implements Runnable
    {
        String name;

        IShowerProvider provider;

        IShower shower;

        public AddShower(String name, IShowerProvider provider)
        {
            this.name = name;
            this.provider = provider;
        }

        public void run()
        {
            synchronized(ShowPaneManager.this)
            {
	            shower = provider.makeNewShower();
	            shower.addNewDataListener(ShowPaneManager.this);
	            
	            Tab<ADrawableObject> tab = 
	                new Tab<ADrawableObject>(name, (ADrawableObject) shower);
	            shower.addNewDataListener(tab);
	            tabs.addTab(tab);
            }
        }
    }

    IShower addShower(final String name, final IShowerProvider provider)
    {
        AddShower addShower = new AddShower(name, provider);
        Display.getDefault().syncExec(addShower);
        return addShower.shower;
    }

    public synchronized void parentResized(Point size)
    {
        super.parentResized(size);
        updateShowHideButtonPosition();

    }

    public synchronized boolean capturesMouse()
    {
        return true;
    }

    public synchronized void onDrag(Point offset)
    {
        super.onDrag(offset);

        if((offset.x < showHideButton.getPosition().x || offset.x > showHideButton
                .getPosition().x
                + showHideButton.getSize().x)
                && (offset.y < showPaneBarHeight))
        {
            CanvasManager.getSingleton().setDragObject(new BlackResizeBar(),
                    offset);
        }
    }

    public IShower getShowerByDetails(String name,
            IShowerProvider provider)
    {
        
        synchronized(this)
        {
	        for (Tab<ADrawableObject> tab : tabs)
	        {
	            if(tab.getName().equals(name)
	                    && ((IShower) tab.getContents()).getShowerProvider()
	                            .equals(provider))
	            {
	                return (IShower) tab.getContents();
	            }
	        }
        }

        return addShower(name, provider);
    }

    public synchronized void newData()
    {
        if(!showHideButton.isExpanded() && !showHideButton.isAttentionSeeking())
        {
            this.showHideButton.setAttentionSeeking(true);
        }
    }
    
    public void checkSize()
    {
        int maxSize = CanvasManager.getSingleton().getSize().y
    	- ToolBarManager.getSingleton().getSize().y - BUFFER;
	    if(size > showPaneBarHeight && size > maxSize && maxSize > 0)
	    {
            this.size = maxSize;
            if(expanded)
            {
                setExpanded(true);
            }
	    }
    }
    
    public synchronized void setScreenSize(int size)
    {
        int maxSize = CanvasManager.getSingleton().getSize().y
        	- ToolBarManager.getSingleton().getSize().y - BUFFER;
        if(size > maxSize)
        {
            this.size = maxSize;
            setExpanded(true);
        }
        else if(size > minimumSize)
        {
            this.size = size;
            setExpanded(true);
        }
        else
        {
            setExpanded(false);
        }
        
    }
    
    public void moveSelectedTab(int adjustAmount)
    {
        synchronized(tabs)
        {
            int tabCount = tabs.numberOfTabs();
            
            if(tabCount == 0)
            {
                return;
            }
            
            int tabPos = tabs.getTabPosition(tabs.getSelectedTab());
            tabPos += adjustAmount;
            if(tabPos < 0)
            {
                tabPos += tabCount * (tabPos / -tabCount + 1);
            }
            
            tabPos %= tabCount;
            Tab<ADrawableObject> newSelected = tabs.getTabAt(tabPos);
            tabs.setSelected(newSelected);
        }
    }

    public void removeSelectedTab() {
        
        tabs.removeSelectedTab();
        
    }
    
    /*
     * public void mouseRelease(Point position, int mouseButton) {
     * IShowExecutionManager manager =
     * ShowExecutionManagerProvider.getShowExecutionManager();
     * 
     * IShower shower = manager.getShower("Test", "Blah", new
     * InterfaceClass(ITextType.class)); shower.addObject(new TextTypeImpl("wow,
     * it works\n")); }
     */

    /*
     * public ShowPaneExecutionManager getShowPaneExecutionManager() { return
     * spem; }
     * 
     * 
     * private class ShowHandler implements IPipeExecutionListener { HialContext
     * hialContext;
     * 
     * public void objectSent(IType o, long pipeID) { } }
     */
}


