package org.openswing.swing.table.client;

import java.awt.*;
import javax.swing.*;
import javax.swing.plaf.*;
import javax.swing.plaf.metal.*;


/**
 * <p>Title: OpenSwing Framework</p>
 * <p>Description: Vertical scrollbar UI, used inside the pagination vertical scrollbar of the grid control, for Unix/Linux LnF.</p>
 * <p>Copyright: Copyright (C) 2006 Mauro Carniel</p>
 *
 * <p> This file is part of OpenSwing Framework.
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the (LGPL) Lesser General Public
 * License as published by the Free Software Foundation;
 *
 *                GNU LESSER GENERAL PUBLIC LICENSE
 *                 Version 2.1, February 1999
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *       The author may be contacted at:
 *           maurocarniel@tin.it</p>
 *
 * @author Mauro Carniel
 * @version 1.0
 */
public class MetalPaginationVerticalScrollbarUI extends MetalScrollBarUI implements PaginationVerticalScrollbarUI {

  protected JButton nextPgButton;
  protected JButton prevPgButton;


  public MetalPaginationVerticalScrollbarUI() {
    super();
  }


  public static ComponentUI createUI(JComponent c)    {
      return new MetalPaginationVerticalScrollbarUI();
  }

  protected JButton createPageButton(int orientation)  {
    return new PageArrowButton(orientation);
  }


  protected void installDefaults() {
    super.installDefaults();
    nextPgButton = createPageButton(SOUTH);
    prevPgButton = createPageButton(NORTH);
    scrollbar.add(prevPgButton);
    scrollbar.add(nextPgButton);
  }


  protected void layoutVScrollbar(JScrollBar sb) {
      Dimension sbSize = sb.getSize();
      Insets sbInsets = sb.getInsets();

      /*
       * Width and left edge of the buttons and thumb.
       */
      int itemW = sbSize.width - (sbInsets.left + sbInsets.right);
      int itemX = sbInsets.left;

      /* Nominal locations of the buttons, assuming their preferred
       * size will fit.
       */
      int prevPgButtonH = prevPgButton.getPreferredSize().height;
      int prevPgButtonY = sbInsets.top;

      int decrButtonH = decrButton.getPreferredSize().height;
      int decrButtonY = prevPgButtonY+prevPgButtonH;

      int incrButtonH = incrButton.getPreferredSize().height;
      int nextPgButtonH = nextPgButton.getPreferredSize().height;

      int incrButtonY = sbSize.height - (sbInsets.bottom + incrButtonH+nextPgButtonH);
      int nextPgButtonY = sbSize.height - (sbInsets.bottom + nextPgButtonH);



      /* The thumb must fit within the height left over after we
       * subtract the preferredSize of the buttons and the insets.
       */
      int sbInsetsH = sbInsets.top + sbInsets.bottom;
      int sbButtonsH = decrButtonH + incrButtonH +prevPgButtonH +nextPgButtonH;
      float trackH = sbSize.height - (sbInsetsH + sbButtonsH);

      /* Compute the height and origin of the thumb.   The case
       * where the thumb is at the bottom edge is handled specially
       * to avoid numerical problems in computing thumbY.  Enforce
       * the thumbs min/max dimensions.  If the thumb doesn't
       * fit in the track (trackH) we'll hide it later.
       */
      float min = sb.getMinimum();
      float extent = sb.getVisibleAmount();
      float range = sb.getMaximum() - min;
      float value = sb.getValue();

      int thumbH = (range <= 0)
          ? getMaximumThumbSize().height : (int)(trackH * (extent / range));
      thumbH = Math.max(thumbH, getMinimumThumbSize().height);
      thumbH = Math.min(thumbH, getMaximumThumbSize().height);

      int thumbY = incrButtonY - thumbH;
      if (sb.getValue() < (sb.getMaximum() - sb.getVisibleAmount())) {
          float thumbRange = trackH - thumbH;
          thumbY = (int)(0.5f + (thumbRange * ((value - min) / (range - extent))));
          thumbY +=  decrButtonY + decrButtonH;
      }

      /* If the buttons don't fit, allocate half of the available
       * space to each and move the lower one (incrButton) down.
       */
      int sbAvailButtonH = (sbSize.height - sbInsetsH);
      if (sbAvailButtonH < sbButtonsH) {
          incrButtonH = decrButtonH = sbAvailButtonH / 2;
          incrButtonY = sbSize.height - (sbInsets.bottom + incrButtonH);
      }
      prevPgButton.setBounds(itemX, prevPgButtonY, itemW, prevPgButtonH);
      decrButton.setBounds(itemX, decrButtonY, itemW, decrButtonH);
      incrButton.setBounds(itemX, incrButtonY, itemW, incrButtonH);
      nextPgButton.setBounds(itemX, nextPgButtonY, itemW, nextPgButtonH);

      /* Update the trackRect field.
       */
      int itrackY = decrButtonY + decrButtonH;
      int itrackH = incrButtonY - itrackY;
      trackRect.setBounds(itemX, itrackY, itemW, itrackH);

      /* If the thumb isn't going to fit, zero it's bounds.  Otherwise
       * make sure it fits between the buttons.  Note that setting the
       * thumbs bounds will cause a repaint.
       */
      if(thumbH >= (int)trackH)	{
          setThumbBounds(0, 0, 0, 0);
      }
      else {
          if ((thumbY + thumbH) > incrButtonY) {
              thumbY = incrButtonY - thumbH;
          }
          if (thumbY  < (decrButtonY + decrButtonH)) {
              thumbY = decrButtonY + decrButtonH + 1;
          }
          setThumbBounds(itemX, thumbY, itemW, thumbH);
      }
  }

  protected void installListeners() {
    super.installListeners();
  }

  protected void uninstallListeners() {
    super.uninstallListeners();
  }

  public JButton getNextPgButton() {
    return nextPgButton;
  }

  public JButton getDecrButton() {
    return decrButton;
  }

  public JButton getIncrButton() {
    return incrButton;
  }

  public JButton getPrevPgButton() {
    return prevPgButton;
  }


  /**
   * <p>Title: OpenSwing Framework</p>
   * <p>Description: Inner class used to render the scrollbar buttons.</p>
   * @author Mauro Carniel
   * @version 1.0
   */
  class PageArrowButton extends MetalScrollButton {

    private Color highlightColor = UIManager.getColor("ScrollBar.highlight");
    private Color shadowColor = UIManager.getColor("ScrollBar.darkShadow");
    private Color arrowColor = MetalLookAndFeel.getControlInfo();


    public PageArrowButton(int direction) {
      super(
        direction,
        incrButton==null?scrollBarWidth:incrButton.getPreferredSize().width,
        true
      );
    }

    public void paint(Graphics g) {
      boolean isPressed = getModel().isPressed();
      int width = getWidth();
      int height = getHeight();
      int w = width;
      int h = height;
      int arrowHeight = (height + 1) / 4;
      int arrowWidth = (height + 1) / 2;

      if (isPressed) {
        g.setColor(MetalLookAndFeel.getControlShadow());
      }
      else {
        g.setColor(getBackground());
      }

      g.fillRect(0, 0, width, height);

      if (getDirection() == NORTH) {
        if (!isFreeStanding) {
          height += 1;
          g.translate(0, -1);
          width += 2;
        }

        g.setColor(arrowColor);
//        int startY = ( (h + 1) - arrowHeight) / 2;
        int startY = ( (h + 1) - arrowHeight) - 3;
        int startX = (w / 2);
        for (int line = 0; line < arrowHeight; line++) {
          g.drawLine(startX - line, startY + line, startX + line + 1,
                     startY + line);
        }

        startY = arrowHeight;
        for (int line = 0; line < arrowHeight; line++) {
          g.drawLine(startX - line, startY + line, startX + line + 1,
                     startY + line);
        }

        g.setColor(highlightColor);

        if (!isPressed) {
          g.drawLine(1, 1, width - 3, 1);
          g.drawLine(1, 1, 1, height - 1);
        }

        g.drawLine(width - 1, 1, width - 1, height - 1);

        g.setColor(shadowColor);
        g.drawLine(0, 0, width - 2, 0);
        g.drawLine(0, 0, 0, height - 1);
        g.drawLine(width - 2, 2, width - 2, height - 1);

        if (!isFreeStanding) {
          height -= 1;
          g.translate(0, 1);
          width -= 2;
        }
      }
      else if (getDirection() == SOUTH) {
        if (!isFreeStanding) {
          height += 1;
          width += 2;
        }

        g.setColor(arrowColor);

//        int startY = ( ( (h + 1) - arrowHeight) / 2) + arrowHeight - 1;
        int startY = ( ( (h + 1) - arrowHeight)) - 2;
        int startX = (w / 2);
        for (int line = 0; line < arrowHeight; line++) {
          g.drawLine(startX - line, startY - line, startX + line + 1,
                     startY - line);
        }

        startY = arrowHeight+2;
        for (int line = 0; line < arrowHeight; line++) {
          g.drawLine(startX - line, startY - line, startX + line + 1,
                     startY - line);
        }

        g.setColor(highlightColor);

        if (!isPressed) {
          g.drawLine(1, 0, width - 3, 0);
          g.drawLine(1, 0, 1, height - 3);
        }

        g.drawLine(1, height - 1, width - 1, height - 1);
        g.drawLine(width - 1, 0, width - 1, height - 1);

        g.setColor(shadowColor);
        g.drawLine(0, 0, 0, height - 2);
        g.drawLine(width - 2, 0, width - 2, height - 2);
        g.drawLine(2, height - 2, width - 2, height - 2);

        if (!isFreeStanding) {
          height -= 1;
          width -= 2;
        }
      }

    }
  }



}
