package cnp.ew.notebook;

import java.awt.*;
import cnp.ew.displayer.*;
import cnp.ew.lightweight.*;

public class CpBasicScrollingNotebookTabsLc extends CpAbstractNotebookTabsLc
{
    static public final int SCROLLED_TABS=2;
    int scrollIndex;

    public CpBasicScrollingNotebookTabsLc(CpTabDisplayable newTabDisplayer)
    {
        super(newTabDisplayer);
    }

    public boolean canDecrementScroll()
    {
        return scrollIndex > 0;
    }

    public boolean canIncrementScroll()
    {
        return scrollIndex < getMaxScrollIndex();
    }

    int getMaxScrollIndex()
    {
        int totalWidth = 0;
        boolean firstTime=true;
        Dimension size = size();

        for (int i=tabs.size() - 1; i >= 0; i--) {
            CpTabLc tab = (CpTabLc)tabs.elementAt(i);
            if (firstTime) {
                totalWidth = tab.maxExpansion().left + tab.maxExpansion().right;
                firstTime = false;
            }
            totalWidth += tab.preferredSize().width - tab.horizontalOverlap();
            if (totalWidth > size().width) {
                return i + 1;
            }
        }
        return 0;
    }

    /**
     * Make sure that as many tabs are visible as possible.  In other words, if we are scrolled out, and the
     * size of the container changes, we will need to change the scroll index.
     */
    void scrollIfNecessary()
    {
        int maxScrollIndex = getMaxScrollIndex();
        if (maxScrollIndex < scrollIndex) {
            scrollIndex = maxScrollIndex;
            notifyObservers(SCROLLED_TABS);
        }
    }


    public void incrementScrollIndex()
    {
        setScrollIndex(scrollIndex + 1);
    }

    void setScrollIndex(int newIndex)
    {
        int tempIndex = Math.max(0, Math.min(getMaxScrollIndex(), newIndex));
        if (tempIndex != scrollIndex) {
            scrollIndex = tempIndex;
            layout();
            repaint();
            notifyObservers(SCROLLED_TABS);
        }
    }

    public void decrementScrollIndex()
    {
        setScrollIndex(scrollIndex - 1);
    }

    void selectedTabChanged(boolean wasClick)
    {
        // TBD: Need to change this from dealing with clicks to dealing
        // with not being valid. Removing this test causes an infinite loop.
        if (wasClick) {
            keepSelectionFullyVisible();
        }
        layout();
    }

    void updateZOrder()
    {
        for (int i=0; i < tabs.size(); i++) {
            CpTabLc tab = (CpTabLc)tabs.elementAt(i);
            tab.sendToBack();
        }
        selectedTab.bringToFront();
    }


    void keepSelectionFullyVisible()
    {
        if (selectedTab == null) {
            return;
        }

        int selectedTabIndex = getSelectedTabIndex();
        int [] widths = new int[selectedTabIndex - scrollIndex + 1];
        int totalWidth = 0;
        int containerWidth = size().width;

        for (int i = scrollIndex; i <= selectedTabIndex; i++) {
            CpTabLc tab = (CpTabLc)tabs.elementAt(i);
            if (i == selectedTabIndex) {
                widths[i - scrollIndex] = tab.preferredSize().width + tab.maxExpansion().left + tab.maxExpansion().right;
            } else {
                widths[i - scrollIndex] = tab.preferredSize().width - tab.horizontalOverlap();
            }
            totalWidth += widths[i - scrollIndex];
        }
        int scrollOffset = 0;
        while (totalWidth > containerWidth) {
            totalWidth -= widths[scrollOffset];
            scrollOffset++;
        }

        while (scrollOffset + scrollIndex > selectedTabIndex) {
            scrollOffset--;
        }

        if (scrollOffset != 0) {
            scrollIndex = scrollIndex + scrollOffset;
            notifyObservers(SCROLLED_TABS);
        }
    }


    // TBD: THIS IS NOT THE WAY TO DO THIS...
    boolean isValid()
    {
        return bounds().width >=0 && bounds().height >= 0;
    }


    public void layout()
    {
        int startX=0, startY=0;
        boolean firstTime = true;
        int tabHeight=0;
        CpTabLc tab;
        int width;

    // We sometimes get layout messages before we have a valid rectangle (e.g. when
    // the selection changes before we're fully built).  Since we know we'll get a layout
    // when we do have a valid rectangle, we can ignore these.
        if (!isValid()) {
            return;
        }

        scrollIfNecessary();

        updateZOrder();

        for (int i = scrollIndex; i < tabs.size(); i++) {
            tab = (CpTabLc)tabs.elementAt(i);
            if (firstTime) {
                Insets maxExpansion = tab.maxExpansion();
                startX = maxExpansion.left;
                startY = maxExpansion.top;
                tabHeight = bounds().height - maxExpansion.top - maxExpansion.bottom;
                firstTime = false;
            }
            width = tab.preferredSize().width;
            Insets expansion = tab.expansion();
            tab.reshape(
                startX - expansion.left,
                startY - expansion.top,
                width + expansion.left + expansion.right,
                tabHeight + expansion.top + expansion.bottom
            );

            startX += width - tab.horizontalOverlap();
        }

        // hide those that aren't visible
        for (int i = 0; i < scrollIndex; i++) {
            tab = (CpTabLc)tabs.elementAt(i);
            tab.reshape(-10000, -10000, 0, 0);
        }
    }

/*
    public void paint(Graphics g, Rectangle clipRect)
    {
        Rectangle bounds;
        Dimension size = size();

        g.setColor(Color.lightGray);
        g.fillRect(0, 0, size().width, size.height);

        g.setColor(Color.white);
        the one shift pixel horizontally is to line up with 3-D
        // notebook pages.
        g.drawLine(1, size.height - 1, size.width - 1, size.height - 1);
    }
    */


    public Dimension preferredSize()
    {
        int width=0;
        boolean firstTime=true;
        int maxPreferredHeight=0, extraHeight=0;
        for (int i=0; i < tabs.size(); i++) {
            CpTabLc tab = (CpTabLc)tabs.elementAt(i);

            if (firstTime) {
                Insets maxExpansion = tab.maxExpansion();
                width = maxExpansion.left + maxExpansion.right;
                extraHeight = maxExpansion.top + maxExpansion.bottom;
                firstTime = false;
            }
            width += tab.preferredSize().width - tab.horizontalOverlap();
            maxPreferredHeight = Math.max(maxPreferredHeight, tab.preferredSize().height);
        }
        return new Dimension(width, maxPreferredHeight + extraHeight);
    }

    void tabAdded()
    {
    }

}

