/* 
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. Use is subject to license terms. 
 * 
 * This file is available and licensed under the following license:
 * 
 * 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.
 *
 *   * Neither the name of Sun Microsystems nor the names of its contributors 
 *     may be used to endorse or promote products derived from this software 
 *     without specific prior written permission.
 * 
 * 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.
 */
package mosaic;

import java.util.Random;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.animation.transition.ParallelTransition;
import javafx.animation.transition.RotateTransition;
import javafx.animation.transition.TranslateTransition;
import javafx.scene.Cursor;
import javafx.scene.CustomNode;
import javafx.scene.Group;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.Node;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.input.MouseEvent;

/**
 * @author Rakesh Menon
 */

def random = new Random();
var anchor = 0;

public class ThumbImage extends CustomNode {
    
    var width = 104.0;
    var height = 79.0;
    
    var fromX = 0.0;
    var fromY = 0.0;
    var toX = 0.0;
    var toY = 0.0;
    var finalR = 0;
    
    var startX = 0.0;
    var startY = 0.0;
    var mouseDragged = false;
    var alignment = 0;
    
    init {
        if(anchor == 3) {
            anchor = 0;
        } else {
            anchor++;
        }
        alignment = anchor;
    }
    
    public var imageView = ImageView {
        x: 2
        y: 2
        fitWidth: bind (width - 4)
        fitHeight: bind (height - 4)
        preserveRatio: true
    };

    var progress = bind imageView.image.progress on replace {
        if(progress >= 90.0) {
            scaleX = 0.5;
            scaleY = 0.5;
            visible = true;
            rotate();
        }
    }

    var imageWidth = bind imageView.image.width on replace {
        if(imageWidth >= 0.0) {
            width = imageWidth;
        }
    }

    var imageHeight = bind imageView.image.height on replace {
        if(imageHeight >= 0.0) {
            height = imageHeight;
        }
    }
    
    public var url : String on replace {
        if(url != null) {
            imageView.image = Image {
                url: "{url}_m.jpg"
                backgroundLoading: true
            }
            visible = false;
        }
    }
    
    var zoomTimeline : Timeline;
    var hoverRotateTransition : RotateTransition;

    override function create() : Node {
        
        cursor = Cursor.HAND;
        blocksMouse = true;
        visible = false;
        
        hoverRotateTransition = RotateTransition {
            duration: 300ms
            node: this
        };

        zoomTimeline = Timeline {
        };
        
        var borderRect = Rectangle {
            width: bind width
            height: bind height
            strokeWidth: 2.0
            stroke: Color.WHITE
            arcWidth: 5
            arcHeight: 5
        }

        rotate();
        
        Group {
            content: [ borderRect, imageView ]
        }
    }
    
    override var onMouseEntered = function(e) {
        
        if(mouseDragged or zoomTimeline.running) { 
            return;
        }
        
        toFront();
        
        hoverRotateTransition.stop();
        hoverRotateTransition.fromAngle = finalR;
        hoverRotateTransition.toAngle = 0;
        hoverRotateTransition.playFromStart();
    }
    
    override var onMouseExited = function(e) {
        
        if(mouseDragged or 
            zoomTimeline.running or
                hoverRotateTransition.running) {
            return;
        }
        
        hoverRotateTransition.fromAngle = 0;
        hoverRotateTransition.toAngle = finalR;
        hoverRotateTransition.playFromStart();

        if((scaleX > 0.5) or (scaleY > 0.5)) {
            initFinalPoint();
            zoomTimeline.playFromStart();
        }
    }
    
    override var onMousePressed = function(e) {
        startX = translateX;
        startY = translateY;
        e.node.rotate = 0;
        mouseDragged = true;
    }
    
    override var onMouseReleased = function(e) {
        mouseDragged = false;
    }
    
    override var onMouseDragged = function(e : MouseEvent) {
        
        translateX = startX + e.dragX;
        translateY = startY + e.dragY;
        
        var scaleFactor = 2.5;
        var halfWidth = Main.width/2.0 - 100;
        var halfheight = Main.height/2.0 - 100;
        
        var imageScaleX = scaleFactor -
            (scaleFactor * (halfWidth - translateX + 1)/halfWidth);
        if(translateX > halfWidth) {
            imageScaleX = scaleFactor -
            (scaleFactor * (halfWidth - (Main.width - translateX - 200) + 1)/halfWidth);
        }
        if(imageScaleX < 0.5) { imageScaleX = 0.5; }
        
        var imageScaleY = scaleFactor -
            (scaleFactor * (halfheight - translateY + 1)/halfheight);
        if(translateY > halfheight) {
            imageScaleY = scaleFactor -
                (scaleFactor * (halfheight - (Main.height - translateY - 200) + 1)/halfheight);
        }
        if(imageScaleY < 0.5) { imageScaleY = 0.5; }
        
        scaleX = java.lang.Math.min(imageScaleX, imageScaleY);
        scaleY = scaleX;
    }

    function initFinalPoint() : Void {
        
        if(alignment == 0) {        // TOP
            fromX = -100;
            fromY = 0;
            toX = random.nextInt(Main.width - 100) - 20;
            toY = 0;
        } else if(alignment == 1) { // RIGHT
            fromX = Main.height - 100;
            fromY = -75;
            toX = Main.width - 150;
            toY = random.nextInt(Main.height - 100) - 10;
        } else if(alignment == 2) { // BOTTOM
            fromX = Main.width;
            fromY = Main.height - 100;
            toX = random.nextInt(Main.width - 100) - 10;
            toY = Main.height - 160;
        } else if(alignment == 3) { // LEFT
            fromX = 0;
            fromY = Main.height - 100;
            toX = -50;
            toY = random.nextInt(Main.height - 200);
        }
    }

    public function rotate() : Void {
        
        initFinalPoint();
        
        var translateTransition = TranslateTransition {
            duration: 2s
            node: this
            fromX: fromX
            toX: toX
            fromY: fromY
            toY: toY
            repeatCount: 1
        };

        zoomTimeline.keyFrames = [
            KeyFrame {
                time: 500ms
                values: [ scaleX => 0.5 tween Interpolator.EASEOUT ]
            },
            KeyFrame {
                time: 500ms
                values: [ scaleY => 0.5 tween Interpolator.EASEOUT ]
            },
            KeyFrame {
                time: 1s
                values: [ translateX => toX tween Interpolator.EASEOUT ]
            },
            KeyFrame {
                time: 1s
                values: [ translateY => toY tween Interpolator.EASEOUT ]
            }
        ];
        
        var rotateTransition : RotateTransition = RotateTransition {
            duration: 1s
            node: this
            byAngle: 360
            repeatCount: 2
            action: function() {
                finalR = random.nextInt(360);
                rotateTransition.node.rotate = finalR;
            }
        };
        
        var parallelTransition = ParallelTransition {
            content: [
                translateTransition,
                rotateTransition
            ]
        };
        parallelTransition.play();
    }

    public function cancel() : Void {
        if(imageView.image != null) {
            imageView.image.cancel();
        }
    }
}