/**
 * 
 * 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 OWNER 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.
 * Copyright © 2009 Mindoo GmbH
 *
 * @author Tammo Riedinger
 *
 */
package com.mindoo.ec09.legacy;

import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;

import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.KeyStroke;

public class ScaledComponent extends JComponent {
	private static final long serialVersionUID = 5637103175127596682L;
	public static final String ACTION_ZOOM_IN="zoom_in";
	public static final String ACTION_ZOOM_OUT="zoom_out";
	
	private double m_scale=1;
	
	public ScaledComponent() {
		getActionMap().put(ACTION_ZOOM_IN, new AbstractAction() {
			private static final long serialVersionUID = 6071994526283021043L;

			public void actionPerformed(ActionEvent evt) {
				setScale(getScale()+0.2d);
			}
		});
		getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, InputEvent.CTRL_MASK), ACTION_ZOOM_IN);

		getActionMap().put(ACTION_ZOOM_OUT, new AbstractAction() {
			private static final long serialVersionUID = -5407836842013543661L;

			public void actionPerformed(ActionEvent evt) {
				setScale(getScale()-0.2d);
			}
		});
		getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, InputEvent.CTRL_MASK), ACTION_ZOOM_OUT);
	
		setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
		
		addMouseWheelListener(new MouseWheelListener() {
			public void mouseWheelMoved(MouseWheelEvent evt) {
				int notches=evt.getWheelRotation();
				
				double scale=getScale();
				
				scale-=0.1*notches;
				scale=Math.max(scale,0.1);
				
				setScale(scale);
				evt.consume();
			}
		});
		
		addMouseMotionListener(new MouseMotionListener() {
			private Point m_startingPoint;
			
			public void mouseDragged(MouseEvent evt) {
				if (m_startingPoint!=null) {
					double factor=1.5d;

					Dimension distance=new Dimension((int)((m_startingPoint.getX()-evt.getPoint().getX()) / factor),(int)((m_startingPoint.getY()-evt.getPoint().getY()) / factor));
					if (Math.abs(distance.width)>0 || Math.abs(distance.height)>0) {
						Rectangle visRect=getVisibleRect();
						visRect.x+=distance.width;
						visRect.y+=distance.height;
						
						scrollRectToVisible(visRect);

						m_startingPoint=evt.getPoint();
					}
				}
				else
					m_startingPoint=evt.getPoint();
			}

			public void mouseMoved(MouseEvent e) {
				m_startingPoint=null;
			}
		});
	}
	
	public void setScale(double scale) {
		scale=Math.min(200d,Math.max(0.01d, scale));
		
		if (scale!=m_scale) {
			Rectangle visRect=getVisibleRect();
			visRect.x=(int)(((double)(visRect.x) / m_scale) * scale);
			visRect.y=(int)(((double)(visRect.y) / m_scale) * scale);
			visRect.height=(int)(((double)(visRect.height) / m_scale) * scale);
			visRect.width=(int)(((double)(visRect.width) / m_scale) * scale);

			m_scale=scale;
			
			setSize(getPreferredSize());
			
			scrollRectToVisible(visRect);

			repaint();
		}
	}
	
	public double getScale() {
		return m_scale;
	}
	
	private void clear(Graphics g) {
		g.setColor(this.getBackground());

		Dimension size=getSize();

		g.fillRect(0, 0, size.width, size.height);
	}
	
	@Override
	public void paintComponent(Graphics g) {
		clear(g);
		
		Insets insets=getInsets();

		((Graphics2D)g).translate(insets.left, insets.top);
		((Graphics2D)g).scale(m_scale,m_scale);
		
		paintContent(g);
		
		((Graphics2D)g).scale(1/m_scale,1/m_scale);
		((Graphics2D)g).translate(-insets.left, -insets.top);
	}
	
	public void paintContent(Graphics g) { }
	
	public Dimension getContentSize() {
		return super.getPreferredSize();
	}
	
	@Override
	public Dimension getPreferredSize() {
		Insets insets=getInsets();
		Dimension size=new Dimension(insets.left+insets.right+0,insets.top+insets.bottom+0);
			
		Dimension contentSize=getContentSize();
		
		size.width+=(int)(contentSize.getWidth()*m_scale);
		size.height+=(int)(contentSize.getHeight()*m_scale);
			
		return size;
	}
}