﻿// Namespace declaration ...
if (!window.RHPConsulting)
    window.RHPConsulting = {};
    
RHPConsulting.ImageSurfaceExtender = function(parentCanvas, index, width, height) {

    // event collection variables ...
    this._selectedHandlers = new Array();
    this._mouseEnterHandlers = new Array();
    this._mouseLeaveHandlers = new Array();
    
    // variables ...
    this._index = index;
    this._lastPosition = null;
    this._rotatingScaling = false;
    this._dragging = false;

    // variables required to hold reference to created objects ...
    this._canvasParent = parentCanvas;
    
    // xaml ...
    var _xaml = "<Canvas x:Name='CanvasSurfaceMain_$1' Width='576' Height='432' Visibility='Collapsed' "
                 + "  xmlns='http://schemas.microsoft.com/client/2007' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>"
                 + "   <Canvas.Resources>"
		         + "    <Storyboard x:Name='Tumble_$1'>"
		         + " 	<DoubleAnimationUsingKeyFrames BeginTime='00:00:00' Storyboard.TargetName='CanvasRotateTransform_$1' Storyboard.TargetProperty='Angle'>"
		         + " 		<SplineDoubleKeyFrame KeyTime='00:00:00.2000000' Value='-12.012'/>"
		         + " 		<SplineDoubleKeyFrame KeyTime='00:00:00.3000000' Value='10.646'/>"
		         + " 		<SplineDoubleKeyFrame KeyTime='00:00:00.5000000' Value='-6.463'/>"
		         + " 		<SplineDoubleKeyFrame KeyTime='00:00:00.6000000' Value='0'/>"
		         + " 	</DoubleAnimationUsingKeyFrames>"
		         + " 	<DoubleAnimationUsingKeyFrames BeginTime='00:00:00' Storyboard.TargetName='CanvasScaleTransform_$1' Storyboard.TargetProperty='ScaleX'>"
		         + " 		<SplineDoubleKeyFrame KeyTime='00:00:00.3000000' Value='1.2'/>"
		         + " 		<SplineDoubleKeyFrame KeyTime='00:00:00.5000000' Value='0.85'/>"
		         + " 		<SplineDoubleKeyFrame KeyTime='00:00:00.6000000' Value='1'/>"
		         + " 	</DoubleAnimationUsingKeyFrames>"
		         + " 	<DoubleAnimationUsingKeyFrames BeginTime='00:00:00' Storyboard.TargetName='CanvasScaleTransform_$1' Storyboard.TargetProperty='ScaleY'>"
		         + " 		<SplineDoubleKeyFrame KeyTime='00:00:00.3000000' Value='1.2'/>"
		         + " 		<SplineDoubleKeyFrame KeyTime='00:00:00.5000000' Value='0.85'/>"
		         + " 		<SplineDoubleKeyFrame KeyTime='00:00:00.6000000' Value='1'/>"
		         + " 	</DoubleAnimationUsingKeyFrames>"
		         + "    </Storyboard>"
	             + "   </Canvas.Resources>"
                 + "   <Canvas.RenderTransform>"
                 + "     <TransformGroup>"
                 + "       <RotateTransform x:Name='CanvasRotateTransform_$1' CenterX='298' CenterY='216' Angle='0' />"
                 + "       <ScaleTransform x:Name='CanvasScaleTransform_$1' CenterX='298' CenterY='216' ScaleX='1' ScaleY='1'/>"
                 + "       <TranslateTransform x:Name='CanvasTranslateTransform_$1' />"
                 + "     </TransformGroup> "
                 + "   </Canvas.RenderTransform>"
                 + "   <Rectangle Width='576' Height='432' Fill='White' Stroke='White' RadiusX='5' RadiusY='5' x:Name='RectangleBackground_$1'></Rectangle>"
                 + "   <Rectangle Width='566' Height='422' Canvas.Top='10' Canvas.Left='10' Stroke='Gainsboro' x:Name='RectangleImage_$1'>"
                 + "     <Rectangle.Fill>"
                 + "       <ImageBrush x:Name='Image_$1' Stretch='Fill'></ImageBrush>"
                 + "     </Rectangle.Fill>"
                 + "   </Rectangle>"
                 + "   <Canvas x:Name='CanvasAllControls_$1' Visibility='Collapsed' Opacity='0.4' Cursor='Hand'>"
                 + "     <Canvas x:Name='CanvasRotateScaleControls_$1'>"
                 + "       <Rectangle Width='30' Height='30' Canvas.Top='0'   Canvas.Left='0'   Fill='Green' Stroke='Black' RadiusX='3' RadiusY='3'></Rectangle> "
                 + "       <Rectangle Width='30' Height='30' Canvas.Top='0'   Canvas.Left='566' Fill='Green' Stroke='Black' RadiusX='3' RadiusY='3'></Rectangle> "
                 + "       <Rectangle Width='30' Height='30' Canvas.Top='422' Canvas.Left='0'   Fill='Green' Stroke='Black' RadiusX='3' RadiusY='3'></Rectangle> "
                 + "       <Rectangle Width='30' Height='30' Canvas.Top='422' Canvas.Left='566' Fill='Green' Stroke='Black' RadiusX='3' RadiusY='3'></Rectangle> "
                 + "     </Canvas>"
                 + "     <Canvas x:Name='CanvasTranslateControls_$1'>"
                 + "       <Rectangle Width='100' Height='100' Canvas.Top='206' Canvas.Left='288' Fill='Green' Stroke='Black' RadiusX='3' RadiusY='3'></Rectangle>"
                 + "     </Canvas>"
                 + "   </Canvas>"
                 + "</Canvas>"
                 
    // replace elements in xaml with index value ...
    while (_xaml.indexOf("$1") != -1) 
    { _xaml = _xaml.replace("$1",this._index); }
    
    // create from xaml, and add to parent canvas ...
    var _host = this._canvasParent.getHost();
    var _image = _host.content.createFromXaml(_xaml);
    this._canvasParent.children.add(_image);

    // get element references ...
    this._canvasElement = this._canvasParent.findName("CanvasSurfaceMain_$1".replace("$1",this._index));
    this._canvasAllControls = this._canvasParent.findName("CanvasAllControls_$1".replace("$1",this._index));
    this._canvasRotateScaleControls = this._canvasParent.findName("CanvasRotateScaleControls_$1".replace("$1",this._index));
    this._canvasTranslateControls = this._canvasParent.findName("CanvasTranslateControls_$1".replace("$1",this._index));
    this._canvasRotateTransform = this._canvasParent.findName("CanvasRotateTransform_$1".replace("$1",this._index));
    this._canvasScaleTransform = this._canvasParent.findName("CanvasScaleTransform_$1".replace("$1",this._index));
    this._canvasTranslateTransform = this._canvasParent.findName("CanvasTranslateTransform_$1".replace("$1",this._index));
    this._imageElement = this._canvasParent.findName("Image_$1".replace("$1",this._index));
    
    // wire up events (element) ...
    this._canvasElement.addEventListener("MouseMove", Silverlight.createDelegate(this, this._handleMouseMove));
    this._canvasElement.addEventListener("MouseLeftButtonUp", Silverlight.createDelegate(this, this._handleMouseLeftButtonUp));
    this._canvasElement.addEventListener("MouseEnter", Silverlight.createDelegate(this, this._handleMouseEnter));
    this._canvasElement.addEventListener("MouseLeave", Silverlight.createDelegate(this, this._handleMouseLeave));        
    
    // wire up events (rotate controls) ...
    this._canvasRotateScaleControls.addEventListener("MouseLeftButtonDown", Silverlight.createDelegate(this, this._handleMouseLeftButtonDown));
    // wire up events (translate "dragging" controls) ...
    this._canvasTranslateControls.addEventListener("MouseLeftButtonDown", Silverlight.createDelegate(this, this._handleMouseLeftButtonDown));
    
    // set width, height ...
    this.set_Size(width,height);
}
RHPConsulting.ImageSurfaceExtender.prototype = {

    // event definition ...
    addEventListener : function(eventName, handler) {
        var handlers = this._get_EventArrayReference(eventName);
        var length   = handlers.push(handler); 
        return (length -1);       
    },
    removeEventListener : function(eventName, token) {
        var handlers  = this._get_EventArrayReference(eventName)
        handlers.splice(token,1); 
    },
    // Events - Private Methods ...
    _raiseEvent : function(eventName, sender, args, ext) {
        var handlers = this._get_EventArrayReference(eventName);
        for(var index in handlers) { handlers[index](sender,args,ext); }  
    },
    // Events - Private Properties ...
    _get_EventArrayReference : function(eventName) {
        var handlers = null;
        switch (eventName)
        {
            case "Selected"   : handlers = this._selectedHandlers;      break;
            case "MouseEnter" : handlers = this._mouseEnterHandlers;    break;
            case "MouseLeave" : handlers = this._mouseLeaveHandlers;    break;
        }
        return handlers;
    },
    
    // public properties ...
    set_ZIndex : function(index) {
        this._canvasElement["Canvas.ZIndex"] = index;
    },
    get_ZIndex : function(index) {
        this._canvasElement["Canvas.ZIndex"] = index;
    },
    set_Size : function(width,height) {
        
        // main canvas ...
        this._canvasElement.Width = width;
        this._canvasElement.Height = height;
        
        // transforms (rotate) ..
        this._canvasRotateTransform.CenterX = width/2;
        this._canvasRotateTransform.CenterY = height/2;
        // transforms (scale) ..
        this._canvasScaleTransform.CenterX = width/2;
        this._canvasScaleTransform.CenterY = height/2;
        
        // rectangle (holds image) ..
        var _rectangle = this._canvasElement.findName("RectangleImage_$1".replace("$1",this._index));
        _rectangle.Width = width - 20;
        _rectangle.height = height - 20;
        
        // rectangle background ...
        var _rectangleBackground = this._canvasElement.findName("RectangleBackground_$1".replace("$1",this._index));
        _rectangleBackground.Width = width;
        _rectangleBackground.height = height;
        
        // rotate, scale controls ...
        for(var i = 0; i < this._canvasRotateScaleControls.children.count; i++) {
            switch (i) {
                case 0 :
                    // do nothing always 0,0
                    break;
                case 1 :
                    this._canvasRotateScaleControls.children.getItem(i)["Canvas.Left"] = (width  - 30);
                    break;
                case 2 :
                    this._canvasRotateScaleControls.children.getItem(i)["Canvas.Top"]  = (height - 30);
                    break;
                case 3 :
                    this._canvasRotateScaleControls.children.getItem(i)["Canvas.Left"] = (width  - 30);
                    this._canvasRotateScaleControls.children.getItem(i)["Canvas.Top"]  = (height - 30);
                    break;
            }
        }
        
        // translate controls ...
        this._canvasTranslateControls.children.getItem(0)["Canvas.Top"] = ((height - 100) / 2); 
        this._canvasTranslateControls.children.getItem(0)["Canvas.Left"] = ((width - 100) / 2);
        
    },
    get_Size : function() {
        var size = {};
        size.Width = this._canvasElement.Width;
        size.Height = this._canvasElement.Height;
        return size;
    },
    set_ImageSource_Downloader : function(downloader,name) {
        if (name == null) name = "";
        this._imageElement.SetSource(downloader,name);
        
    },
    set_ImageSource_RelativeUrl : function(value) {
      this._imageElement.ImageSource = value;  
    },
    get_Visible : function() {
        return this._canvasElement.Visibility;
    },
    set_Visible : function(value) {
        this._canvasElement.Visibility = value;
    },
    
    // public readonly properties ...
    get_Version : function() {
        return "1.0.0.0";
    },
    get_Trademark : function() {
        return "RHPConsulting.NET";
    },
    get_Author : function() {
        return "Roberto Hernández-Pou";
    },
    get_Index : function() {
        return this._index;
    },
    
    // public methods ...
    RamdomizeTranslateRotate : function() {
    
        // random factor ...
        var _randomScale = Math.random();
         
        // rotate ..
        var _deltaAngle;
        _deltaAngle = (360 * _randomScale);
        this._canvasRotateTransform.Angle = _deltaAngle;
        
        // translate
        var _deltaX = this._canvasParent.Width * _randomScale;
        var _deltaY = this._canvasParent.Height * _randomScale;
        this._canvasTranslateTransform.X = (_deltaX > (this._canvasParent.Width * .8)) ? (_deltaX - (this._canvasParent.Width / 2)): _deltaX;
        this._canvasTranslateTransform.Y = (_deltaY > (this._canvasParent.Height * .8)) ? (_deltaY - (this._canvasParent.Height / 2)): _deltaY;
       
    },
    RandomizeScale : function() {
    
        // random factor ...
        var _randomScale = Math.random();
        
        // scale transformation ..
        var _deltaScale = _randomScale;
        this._canvasScaleTransform.ScaleX *= (_deltaScale < .3) ? (_deltaScale + .3) : (_deltaScale);
        this._canvasScaleTransform.ScaleY *= (_deltaScale < .3) ? (_deltaScale + .3) : (_deltaScale);
    },
    Tumble : function() {
        
        // tumble ...
        var _tumble = this._canvasParent.findName("Tumble_$1".replace("$1",this._index));
        
        // TODO: Crap!!!
//        // set rotating information (-12,10,-12,0) ...
//        var _currentAngle = this._canvasRotateTransform.Angle;
//        _tumble.children.getItem(0).children.getItem(0).Value = _currentAngle - 12;
//        _tumble.children.getItem(0).children.getItem(1).Value = _currentAngle + 12;
//        _tumble.children.getItem(0).children.getItem(2).Value = _currentAngle - 12;
//        _tumble.children.getItem(0).children.getItem(3).Value = _currentAngle;
//       
//        // set scaling information ...
//        var _currentScaleX = this._canvasScaleTransform.ScaleX;
//        var _currentScaleY = this._canvasScaleTransform.ScaleY;
//        _tumble.children.getItem(1).children.getItem(0).Value = _currentScaleX + .15;
//        _tumble.children.getItem(1).children.getItem(1).Value = _currentScaleX  - .15;
//        _tumble.children.getItem(1).children.getItem(2).Value = _currentScaleX ;
//        _tumble.children.getItem(2).children.getItem(0).Value = _currentScaleY + .15;
//        _tumble.children.getItem(2).children.getItem(1).Value = _currentScaleY  - .15;
//        _tumble.children.getItem(2).children.getItem(2).Value = _currentScaleY ;
        
        // start tumbling ...
        _tumble.begin();
    },
    
    
    // event Handlers ...
    _handleMouseEnter : function(sender, args) {
        this._canvasAllControls.Visibility= "Visible";
        // raise events selecting ...
        this._raiseEvent("MouseEnter",this, args);
    },
    _handleMouseLeave : function(sender, args) {
        if (this._rotatingScaling == false && this._dragging == false)
        {
            this._canvasAllControls.Visibility= "Collapsed";
            this._raiseEvent("MouseLeave",this, args);
        }
    },
    _handleMouseMove : function(sender,args) {

        var _position = args.getPosition(null);
            
        if (this._rotatingScaling) {
        
            // calculate center ...
            var _center = {};
            _center.X =  this._canvasRotateTransform.CenterX + this._canvasTranslateTransform.X;
            _center.Y =  this._canvasRotateTransform.CenterY + this._canvasTranslateTransform.Y;
                
            // rotate algorithm ...
            var radiansToDegrees = 360 / (2 * Math.PI);
            var lastAngle = Math.atan2(this._lastPosition.Y - _center.Y, this._lastPosition.X - _center.X) * radiansToDegrees;
            var currentAngle = Math.atan2(_position.Y - _center.Y, _position.X - _center.X) * radiansToDegrees;
            var deltaAngle = currentAngle - lastAngle;
            this._canvasRotateTransform.Angle += deltaAngle;

            // Scale it according to the distance the mouse moved relative to the photo's center
            var lastLength = Math.sqrt(Math.pow(this._lastPosition.Y - _center.Y, 2) + Math.pow(this._lastPosition.X - _center.X, 2));
            var currentLength = Math.sqrt(Math.pow(_position.Y - _center.Y, 2) + Math.pow(_position.X - _center.X, 2));
            var deltaScale = currentLength / lastLength;
            this._canvasScaleTransform.ScaleX *= deltaScale;
            this._canvasScaleTransform.ScaleY *= deltaScale; 
            
        }
        
        if (this._dragging) {
        
            // move ..
            var deltaX = _position.X - this._lastPosition.X;
            var deltaY = _position.Y - this._lastPosition.Y;
            this._canvasTranslateTransform.X += deltaX;
            this._canvasTranslateTransform.Y += deltaY;
            
        }
        
        // reset initial position ...
        this._lastPosition = _position;
       
    },
    _handleMouseLeftButtonDown : function(sender,args) {
        // mark rotation started ...
        switch (sender.Name) {
            case "CanvasRotateScaleControls_$1".replace("$1",this._index) : 
                this._rotatingScaling = true; 
                this._dragging = false;
                break;
            case "CanvasTranslateControls_$1".replace("$1",this._index)   : 
                this._rotatinScaling = false;
                this._dragging = true; 
                break;
        }
        // mark initial position ...
        this._lastPosition = args.getPosition(null);
        // capture mouseevents ...
        sender.captureMouse();
        // raise events selecting ...
        this._raiseEvent("Selected",this, args);
    },
    _handleMouseLeftButtonUp : function(sender,args) {
        // mark rotation ended ...
        this._rotatingScaling = false;
        // mark draggin ended ...
        this._dragging = false;
        // release mouseevents ...
        sender.releaseMouseCapture();
    }
   
}

