/*
 * Copyright (c) 2009, Takeyuki Nagao
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the
 * following conditions are met:
 * 
 *  * Redistributions of source code must retain the above
 *    copyright notice, this list of conditions and the
 *    following disclaimer.
 *  * Redistributions in binary form must reproduce the above
 *    copyright notice, this list of conditions and the
 *    following disclaimer in the documentation and/or other
 *    materials provided with the distribution.
 *    
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGE.
 */

package jp.sourceforge.dvibrowser.dvicore.gui.swing;

import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;

import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
import javax.swing.SwingUtilities;
import javax.swing.event.MouseInputAdapter;

// TODO: support logging
public class DragToScroll
extends MouseInputAdapter
{
  // Should we make them weak-references?
  private final JScrollPane jsp;
	private final JScrollBar hsb, vsb;
	// TODO: Handle property change by sp.setXXXScrollBar().

  public DragToScroll(JScrollPane jsp) {
	  this.jsp = jsp;
		hsb = jsp.getHorizontalScrollBar();
		vsb = jsp.getVerticalScrollBar();
	}

	public JScrollPane scrollPane() { return jsp; }

	public void add(Component c) {
	  if (c == null) return;
		addComponent(c);
		if (c instanceof Container) {
		  Component [] cs = ((Container) c).getComponents();
			for (int i=0; i<cs.length; i++) {
		    add(cs[i]);
			}
		}
	}

	private void addComponent(Component c) {
		c.addMouseMotionListener(this);
		c.addMouseListener(this);
	}

	public void remove(Component c) {
	  if (c == null) return;
		if (c instanceof Container) {
		  Component [] cs = ((Container) c).getComponents();
			for (int i=0; i<cs.length; i++) {
		    remove(cs[i]);
			}
		}
		removeComponent(c);
	}

	private void removeComponent(Component c) {
	  if (c == null) return;
		c.removeMouseMotionListener(this);
		c.removeMouseListener(this);
	}

	public void mouseClicked(MouseEvent e)
	{
	  debug("mouseClicked");
	}

	public void mouseEntered(MouseEvent e)
	{
	  debug("mouseEntered");
	}
	public void mouseExited(MouseEvent e)
	{
	  debug("mouseExited");
	}
	private int saveX, saveY;
	private void savePoint(int x, int y) {
	  saveX = x;
		saveY = y;
	}

	public void mousePressed(MouseEvent e)
	{
	  debug("mousePressed");
	  Cursor cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
	  Component c = (Component) e.getSource();
	  c.setCursor(cursor);
	  
	  if (!e.isPopupTrigger()) {
			Point p = e.getPoint();
		  SwingUtilities.convertPointToScreen(p, e.getComponent());
		  savePoint(p.x, p.y);
		}
	}
	public void mouseReleased(MouseEvent e)
	{
	  debug("mouseReleased");
    Component c = (Component) e.getSource();
    c.setCursor(null);
	}

	public void mouseDragged(MouseEvent e)
	{
		if (!e.isPopupTrigger()) {
		  Component c = e.getComponent();
  	  debug(e.getSource() + ": mouseDragged");
			Point p = e.getPoint();
		  SwingUtilities.convertPointToScreen(p, c);
  		int dx = p.x - saveX;
  		int dy = p.y - saveY;
  
  		debug("(dx,dy)=(" + dx + "," + dy + ")");
  
      savePoint(p.x, p.y);

			if (dy == 0) {
  		  hsb.setValue(hsb.getValue() - dx);
			} else if (dx == 0) {
  		  vsb.setValue(vsb.getValue() - dy);
			} else {
 		    JViewport jv = jsp.getViewport();
 			  jv.scrollRectToVisible(
			    new Rectangle(-dx, -dy, jv.getWidth(), jv.getHeight())
			  );
			}
		}
	}

	public void mouseMoved(MouseEvent e)
	{
	  debug("mouseMoved");
	}

	private static void debug(String str) {
//	  System.out.println(str);
	}
}
