/*
 * TouchGraph Software License
 *
 *
 * Copyright (c) 2001 Alexander Shapiro. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by
 *        TouchGraph (http://www.touchgraph.com/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The name "TouchGraph" must not be used to endorse or promote
 *    products derived from this software without prior written
 *    permission.  For written permission, please contact
 *    alex@touchgraph.com
 *
 * 5. Products derived from this software may not be called "TouchGraph",
 *    nor may "TouchGraph" appear in their name, without prior written
 *    permission of TouchGraph.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 TOUCHGRAPH OR ITS 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 com.touchgraph.graphlayout.interaction;

import  com.touchgraph.graphlayout.*;

import  java.awt.*;
import  java.awt.event.*;

/** HVRotateDragUI.  A combination of HVScrolling + rotating.
  * The graph is rotated, but the mouse is always kept on the same point
  * on the graph.
  *
  * @author   Alexander Shapiro
  * @version  1.06
  */
public class HVRotateDragUI extends TGAbstractDragUI implements TGPaintListener {

    HVScroll hvScroll;
    RotateScroll rotateScroll;
    Node mouseOverN;
    Node tempNode;

    TGPoint2D lastMousePos;
    double lastAngle;

  // ............

   /** Constructor with TGPanel <tt>tgp</tt>, HVScroll <tt>hvs</tt>
     * and a RotateScroll <tt>rs</tt>.
     */
    public HVRotateDragUI( TGPanel tgp, HVScroll hvs, RotateScroll rs ) {
        super(tgp);
        hvScroll = hvs;
        rotateScroll = rs;
    }

    double graphDist(double x, double y) {
        double adjx=(x-this.tgPanel.getDrawCenter().x);
        double adjy=(y-this.tgPanel.getDrawCenter().y);
        return Math.sqrt(adjx*adjx+adjy*adjy);
    }

    double getMouseAngle(double x, double y) {
        double adjx=(x-this.tgPanel.getDrawCenter().x);
        double adjy=(y-this.tgPanel.getDrawCenter().y);
        double ang = Math.atan(adjy/adjx);
        if (adjx==0)
            if(adjy>0) ang=Math.PI/2;
            else ang=-Math.PI/2;
        if(adjx<0) ang=ang+Math.PI;
        return ang;
    }

    public void preActivate() {
        tgPanel.addPaintListener(this);
    }

    public void preDeactivate() {
        tgPanel.removePaintListener(this);
        tgPanel.repaint();
    }

    public void mousePressed(MouseEvent e) {
        mouseOverN=tgPanel.getMouseOverN();
        if (mouseOverN!=null) {
            lastMousePos = new TGPoint2D(mouseOverN.drawx, mouseOverN.drawy);
            lastAngle = getMouseAngle(mouseOverN.drawx, mouseOverN.drawy);
        } else {
            tempNode=new Node(); //A hack, until lenses are better implemented
                                 //One should keep track of a real position on the graph
                                 //As opposed to having a temporary node do this task.
            tempNode.drawx = e.getX();
            tempNode.drawy = e.getY();
            tgPanel.updatePosFromDraw(tempNode);
            lastMousePos = new TGPoint2D(tempNode.drawx, tempNode.drawy);
            lastAngle = getMouseAngle(tempNode.drawx, tempNode.drawy);
        }
    }

    public void mouseReleased( MouseEvent e ) {}

    public void mouseDragged( MouseEvent e ) {
        double currX = e.getX();
        double currY = e.getY();
        double currDist = graphDist(currX,currY);

        if (mouseOverN!=null)
            lastAngle = getMouseAngle(mouseOverN.drawx, mouseOverN.drawy);
        else
            lastAngle = getMouseAngle(tempNode.drawx, tempNode.drawy);

        double currentAngle = getMouseAngle(currX, currY);
        if(lastAngle>currentAngle+Math.PI) currentAngle+=Math.PI*2; //Avoids bug at x==0
        else if(currentAngle>lastAngle+Math.PI) lastAngle+=Math.PI*2;

        if (currDist>60) rotateScroll.incrementRotateAngle((currentAngle-lastAngle));

        tgPanel.updateDrawPositions(); //Rotate, but don't redraw
        tgPanel.updateGraphSize(); //Just in case.  Mostly effects H+V Scrollbars

        if(tempNode!=null) tgPanel.updateDrawPos(tempNode); //The temporary node is not part of the graph,
                                                            //So it needs to be updated individually
        TGPoint2D lastMousePos;
        if(mouseOverN!=null)
            lastMousePos = new TGPoint2D(mouseOverN.drawx, mouseOverN.drawy);
        else
            lastMousePos = new TGPoint2D(tempNode.drawx, tempNode.drawy);

        TGPoint2D newPos = new TGPoint2D(currX,currY);

        if (!hvScroll.scrolling) hvScroll.scrollAtoB(lastMousePos, newPos); //Scroll the node to the mouse

        this.tgPanel.repaintAfterMove();

        if(tempNode!=null) tgPanel.updateDrawPos(tempNode); //The temporary node is not part of the graph,
                                                            //So it needs to be updated individually
    }

    public void paintFirst( Graphics g ) {
        TGPoint2D drawCenter = tgPanel.getDrawCenter();
        g.setColor(Color.lightGray);
        for(int i=0;i<16;i++) {
            double ang = Math.PI*2*i/16;
            double rayX = 1000*Math.cos(ang);
            double rayY = 1000*Math.sin(ang);
            g.drawLine((int) drawCenter.x, (int) drawCenter.y,
                       (int) (rayX+drawCenter.x),(int) (rayY+drawCenter.y));
            g.drawLine((int) drawCenter.x+1, (int) drawCenter.y,
                       (int) (rayX+drawCenter.x+1),(int) (rayY+drawCenter.y));
            g.drawLine((int) drawCenter.x, (int) drawCenter.y+1,
                       (int) (rayX+drawCenter.x),(int) (rayY+drawCenter.y+1));
            g.drawLine((int) drawCenter.x+1, (int) drawCenter.y+1,
                       (int) (rayX+drawCenter.x+1),(int) (rayY+drawCenter.y+1));
        }


        g.fillOval((int)drawCenter.x-60, (int) drawCenter.y-60, 120,120);
        g.setColor(tgPanel.BACK_COLOR);
        g.fillOval((int)drawCenter.x-58, (int) drawCenter.y-58, 116,116);

    }

    public void paintLast( Graphics g ) {}
    public void paintAfterEdges( Graphics g ) {}

} // end com.touchgraph.graphlayout.interaction.HVRotateDragUI
