﻿var moveDemo = {
    on: fm.websync.utilities.observe,
    channel: '/move',
    container: document.getElementById('demo-move'),
    threshold: 10, // can only get this close to the edge
    client: {},
    images: {},
    drag: {
        id: null,
        x: null,
        y: null
    },
    /* these pointer functions taken from prototype.js (prototypejs.org) */
    pointer: function(event) {
        return { x: pointerX(event), y: pointerY(event) };
    },
    pointerX: function(event) {
        var docElement = document.documentElement,
        body = document.body || { scrollLeft: 0 };

        return event.pageX || (event.clientX +
          (docElement.scrollLeft || body.scrollLeft) -
          (docElement.clientLeft || 0));
    },
    pointerY: function(event) {
        var docElement = document.documentElement,
        body = document.body || { scrollTop: 0 };

        return  event.pageY || (event.clientY +
           (docElement.scrollTop || body.scrollTop) -
           (docElement.clientTop || 0));
    },
    stop: function(event){
        if(event.preventDefault){
            event.preventDefault();
        }else{
            event.returnValue = false;
        }
        if(event.stopPropagation){
            event.stopPropagation();
        }else{
            event.cancelBubble = true;
        }
    },
    offset: function(element){
        var x = 0, y = 0;
        do {
          y += element.offsetTop  || 0;
          x += element.offsetLeft || 0;
          element = element.offsetParent;
        } while (element);
        return { x: x, y: y };
    },
    move: function(id, x, y, animate) {
        // move image
        var image = moveDemo.images[id];
        var img = image.img;
        if(animate){
            var anim = new Animator().addSubject(new CSSStyleSubject(img, "left: " + x + "px; top: " + y + "px")).play();
        }else{
            img.style.left = x + 'px';
            img.style.top = y + 'px';
        }
        image.x = x;
        image.y = y;
    },
    order: function(orders) {
        // order images
        for (var i = 0; i < orders.length; i++)
            moveDemo.images[orders[i].id].img.style.zIndex = orders[i].z;
    },
    process: function(data) {
        // process action
        switch (data.action) {
            case 'add-image':
                var img = document.createElement('img');
                img.setAttribute('id', data.id);
                img.setAttribute('src', data.src);
                img.setAttribute('width', '200');
                img.setAttribute('class', 'demo-image');
                img.style.position = 'absolute';
                if(data.z < 1000){
                    data.z = data.z + 1000;
                }
                img.style.zIndex = data.z || 0;
                img.style.left = data.x + 'px';
                img.style.top = data.y + 'px';
                
                moveDemo.container.appendChild(img);
                moveDemo.images[data.id] = { img: img, x: data.x, y: data.y, z: data.z, timer: null };
                moveDemo.on(img, 'mousedown', function(evt) {
                    // update current drag info
                    var drag = moveDemo.drag;
                    drag.id = img.getAttribute('id');
                    drag.x = moveDemo.pointerX(evt);
                    drag.y = moveDemo.pointerY(evt);
                    
                    // get new ordering
                    var orders = [];
                    for (var id in moveDemo.images) {
                        orders.push({ id: id, z: moveDemo.images[id].img.style.zIndex });
                    }
                    orders.sort(function(a, b) {
                        return (a.z - b.z);
                    });
                    var inc = 1;
                    for (var i = 0; i < orders.length; i++) {
                        var order = orders[i];
                        if (order.id == drag.id) {
                            order.z = orders.length;
                            inc = 0;
                        } else {
                            order.z = i + inc;
                        }
                    }
                    
                    // order images
                    moveDemo.order(orders);
                    
                    // publish changes
                    client.publish({
                        channel: moveDemo.channel,
                        data: {
                            id: drag.id,
                            action: 'order-image',
                            orders: orders
                        }
                    });
                    
                    // prevent default drag/select operation
                    moveDemo.stop(evt);
                });
                moveDemo.on(document, 'mouseup', function(evt) {
                    var drag = moveDemo.drag;
                    // validate that we should do anything
                    if(!drag || !drag.id){ return; }
                    
                    var id = drag.id;
                    var image = moveDemo.images[id];
                    var x = image.x + (moveDemo.pointerX(evt) - drag.x);
                    var y = image.y + (moveDemo.pointerY(evt) - drag.y);
                    client.publish({
                        // save out location changes
                        channel: moveDemo.channel,
                        data: {
                            action: 'move-image',
                            id: drag.id,
                            x: x,
                            y: y
                        }
                    });
                    
                    // nullify current drag info
                    drag.id = null;
                    drag.x = null;
                    drag.y = null;
                    moveDemo.stop(evt);
                });
                moveDemo.on(document.body, 'mousemove', function(evt) {
                    var drag = moveDemo.drag;
                    if (drag && drag.id) {
                        // get new coords
                        var id = drag.id;
                        var image = moveDemo.images[id];
                        var x = image.x + (moveDemo.pointerX(evt) - drag.x);
                        var y = image.y + (moveDemo.pointerY(evt) - drag.y);
                        var el = document.getElementById(img.id);
                        
                        // x-coord limits
                        if(x < moveDemo.threshold){
                            x = moveDemo.threshold;
                        }
                        if(x + el.offsetWidth > moveDemo.container.offsetWidth - moveDemo.threshold){
                            x = moveDemo.container.offsetWidth - moveDemo.threshold - el.offsetWidth;
                        }
                        
                        // y-coord limits
                        if(y < moveDemo.threshold){
                            y = moveDemo.threshold;
                        }
                        // some extra padding is getting in the way here, so we tack on +5
                        if(y + el.offsetHeight > moveDemo.container.offsetHeight - moveDemo.threshold + 5) {
                            y = moveDemo.container.offsetHeight - moveDemo.threshold - el.offsetHeight + 5;
                        }
                        
                        // for the next round of calculations
                        drag.x = moveDemo.pointerX(evt);
                        drag.y = moveDemo.pointerY(evt);
                        
                        // move image
                        moveDemo.move(id, x, y);
                        
                        moveDemo.stop(evt);
                    }
                });
                break;
            case 'move-image':
                moveDemo.move(data.id, data.x, data.y, true);
                break;
            case 'order-image':
                moveDemo.order(data.orders);
                break;
        }
    }
};

client.connect({
    onSuccess: function(o) {
        moveDemo.client.id = o.clientId;
        
        // subscribe to a personal channel
        client.subscribe({
            channel: moveDemo.channel + '/' + moveDemo.client.id,
            onReceive: function(o) {
                moveDemo.process(o.data);
            }
        });
        
        // subscribe to the move channel
        client.subscribe({
            channel: moveDemo.channel,
            onReceive: function(o) {
                moveDemo.process(o.data);
            }
        });
        
        // get the inital data
        var util = fm.websync.utilities;
        util.xhr('/move-init','',function(responseText, xhr){
            var result = util.json.parse(responseText);
            for(var i = 0; i < result.length;i++){
                moveDemo.process(result[i]);
            }
            moveDemo.container.style.display = '';
        });
    }
});
