﻿/// <reference name="MicrosoftAjax.js"/>
/// <reference assembly="Pacem.Web.Extensions" name="Pacem.Web.Extensions.Tween.Tween.js" />
/// <reference assembly="Pacem.Web.Extensions" name="Pacem.Web.Extensions.DragDrop.DragBehavior.js" />
Type.registerNamespace("Pacem.UI");

Pacem.UI.ContentSlider = function(element) {
    Pacem.UI.ContentSlider.initializeBase(this, [element]);
    // fields
    this._itemsPerView = 1;
    this._bounds = null;
    this._contentsBounds = null;
    this._content = null;
    this._delta = 0;
    this._tween = null;
    this._moveHandler = null;
    this._rollOutHandler = null;
    this._resizeHandler = null;
    this._motionFinishedHandler = null;
    this._motionChangedHandler = null;
    this._motionStartedHandler = null;
    this._previousPosition = 0.0;
    this._prop = "marginLeft";
    //
    this._timer = null;
    this._interval = 0.0;
    this._hoverSpeed = 1.0;
    this._duration = .5;
    this._tickHandler = null;
    this._autoPlay = false;
    this._easingFunc = null;
}

Pacem.UI.ContentSlider.prototype = {
    initialize: function() {
        Pacem.UI.ContentSlider.callBaseMethod(this, 'initialize');
        // initualize
        var el = this.get_element();
        //var bounds = Sys.UI.DomElement.getBounds(realContent); // crashes on firefox & opera (?)
        //el.scrollLeft = bounds.width;
        //
        this._moveHandler = Function.createDelegate(this, this._onMove);
        this._rollOutHandler = Function.createDelegate(this, this._onMouseOut);
        this._resizeHandler = Function.createDelegate(this, this._onResize);
        this._motionFinishedHandler = Function.createDelegate(this, this._motionFinished);
        this._motionStartedHandler = Function.createDelegate(this, this._motionStarted);
        this._motionChangedHandler = Function.createDelegate(this, this._motionChanged);
        $addHandler(window, "resize", this._resizeHandler);
        $addHandler(el, "mousemove", this._moveHandler);
        $addHandler(el, "mouseout", this._rollOutHandler);
        //
        this._ensureStructure();
        //
        this._timer = new Sys.Timer();
        this._tickHandler = Function.createDelegate(this, this._doScrollTimer);
        this._timer.add_tick(this._tickHandler);
        this._updateTimer();
    },
    dispose: function() {
        this._timer.set_enabled(false);
        this._timer.remove_tick(this._tickHandler);
        this._tickHandler = null;
        //
        $removeHandler(window, "resize", this._resizeHandler);
        $removeHandler(this.get_element(), "mousemove", this._moveHandler);
        $removeHandler(this.get_element(), "mouseout", this._rollOutHandler);
        this._rollOutHandler = null;
        this._moveHandler = null;
        this._resizeHandler = null;
        this._motionFinishedHandler = null;
        this._motionStartedHandler = null;
        this._motionChangedHandler = null;
        //
        Pacem.UI.ContentSlider.callBaseMethod(this, 'dispose');
    },
    // methods
    _cloneNode: function(el) {
        return el.cloneNode(true);
        // to be "reprised"
        /*if (Sys.Browser.agent === Sys.Browser.InternetExplorer) {
        return el.cloneNode(true);
        }
        else {
        var el2 = el.cloneNode(true);
        try {
        for (var child in el)
        if (!el2[child])
        el2[child] = el[child];
        } catch (e) {  }
        el2._events = el._events;
        return el2;
        }*/
    },
    _ensureStructure: function() {
        var el = this.get_element();
        var bucket = document.createElement('div');
        Sys.UI.DomElement.setVisible(bucket, false);
        for (var j = 0; j < el.childNodes.length; j++) {
            var el_j = el.childNodes[j];
            if (el_j != bucket && el_j.tagName)
                bucket.appendChild(this._cloneNode(el_j));
        }
        var l = el.childNodes.length - 1;
        for (var j = l; j >= 0; j--) {
            el.removeChild(el.childNodes[j]);
        }
        this._content = document.createElement('table');
        var tbody = document.createElement('tbody');
        this._content.cellPadding =
        this._content.cellSpacing = 0;
        var tr = document.createElement('tr');
        tbody.appendChild(tr);
        this._content.appendChild(tbody);
        var loops = 2;
        for (var i = 0; i < loops; i++) {
            for (var j = 0; j < bucket.childNodes.length; j++) {
                var el_j = bucket.childNodes[j];
                if (el_j != bucket && el_j.tagName) /* check [for browsers other than IE] */{
                    var td = document.createElement('td');
                    var clone = this._cloneNode(el_j);
                    clone.id = String.format("{0}_{1}", clone.id, i);
                    td.appendChild(clone);
                    tr.appendChild(td);
                }
            }
        }
        //this._content.style.position = 'absolute'; // not necessary
        el.appendChild(this._content);
    },
    _ensureBounds: function() {
        if (!this._bounds || !this._bounds.width || this._bounds.width <= 0
            || !this._contentsBounds || !this._contentsBounds.width || this._contentsBounds.width <= 0)
            this._refreshBounds();
    },
    _refreshBounds: function() {
        this._bounds = Sys.UI.DomElement.getBounds(this.get_element());
        if (this._content)
            this._contentsBounds = Sys.UI.DomElement.getBounds(this._content);
    },
    _onResize: function(evt) {
        this._bounds = null;
    },
    _isInBounds: function(point, bounds) {
        var actualPos = point;
        if (!bounds || !bounds.width) return false;
        return bounds.x <= actualPos.x && bounds.y <= actualPos.y
            && bounds.x + bounds.width >= actualPos.x && bounds.y + bounds.height >= actualPos.y
    },
    _onMouseOut: function(evt) {
        // check if it's really outside!
        // (gets thrown also if "mouseout" fires on a nested element)
        var point = Pacem$UI$getMouseCoords(evt);
        var bounds = this._bounds;
        if (!this._isInBounds(point, bounds)) {
            this._delta = Number.NaN;
            this.raiseScrollStop(Sys.EventArgs.Empty);
            this._timer.set_enabled(this._autoPlay);
        }
    },
    _onMove: function(evt) {
        this._ensureBounds();
        var actualPos = Pacem$UI$getMouseCoords(evt);
        var bounds = this._bounds;
        if (this._isInBounds(actualPos, bounds)) {
            this._timer.set_enabled(false);
            this._delta = bounds.x + bounds.width / 2 - actualPos.x;
            this._doScroll();
        } else {
            this._delta = Number.NaN;
            this.raiseScrollStop(Sys.EventArgs.Empty);
            this._timer.set_enabled(this._autoPlay);
        }
    },
    _motionFinished: function(sender, args) {
        var threshold = this._contentsBounds.width / 2;
        if (this._timer.get_enabled() && sender.get_finish() < -threshold) {
            var val = parseInt(sender.get_object()[sender.get_property()]) + threshold;
            sender.get_object()[sender.get_property()] = String.format("{0}px", val);
        }
        this._tween.dispose();
        this._tween = null;
        if (!this._timer.get_enabled())
            this._doScroll();
        else if (this._interval <= .0)
            this._doScrollTimer(this._timer, Sys.EventArgs.Empty);
    },
    _motionStarted: function(sender, args) {
        this._previousPosition = sender.get_start();
    },
    _motionChanged: function(sender, args) {
        var curr = args.get_currentPosition();
        this.raiseScroll(new Pacem.UI.ScrollEventArgs(curr - this._previousPosition));
        this._previousPosition = curr;
    },
    _tweenPosition: function(start, finish, duration) {
        var prop = this._prop;
        var unit = Pacem.UI.Unit.pixels;
        var easingFunc = this._easingFunc;
        this._tween = $create(Pacem.UI.Tween,
                    { 'isCssProperty': true, 'property': prop, 'easingFunc': easingFunc, 'unit': unit, 'start': start, 'finish': finish, 'duration': duration },
                    { 'motionFinished': this._motionFinishedHandler, 'motionChanged': this._motionChangedHandler, 'motionStarted': this._motionStartedHandler }
                    , null, this._content);
    },
    _doScrollTimer: function(sender, args) {
        if (!this._tween /*|| this._tween.get_status() != Pacem.UI.TweenStatus.playing*/) {
            this._ensureBounds();
            var bounds = this._bounds;
            var contentsSize = this._contentsBounds;
            var obj = this._content.style;
            var start = parseInt(obj[this._prop]);
            if (isNaN(start)) start = 0;
            var finish = start - (bounds.width / this.get_itemsPerView());
            if (finish < -contentsSize.width / 2) {
                start += contentsSize.width / 2;
                finish += contentsSize.width / 2;
            }
            var duration = this._duration;
            this._tweenPosition(start, finish, duration);
        }
    },
    _doScroll: function() {
        //this.set_inBounds(!isNaN(this._delta));
        if (!this._tween /*|| this._tween.get_status() != Pacem.UI.TweenStatus.playing*/) {
            this._ensureBounds();
            var bounds = this._bounds;
            if (!isNaN(this._delta)) {
                if (Math.abs(this._delta) > bounds.width / (2 * this._itemsPerView)) {
                    var obj = this._content.style;
                    var start = parseInt(obj[this._prop]);
                    if (isNaN(start)) start = 0;
                    var finish = start + (bounds.width / this.get_itemsPerView()) * ((Math.abs(this._delta)) / this._delta);
                    var contentsSize = this._contentsBounds;
                    // looping effect
                    if (finish > 0) {
                        start -= contentsSize.width / 2;
                        finish -= contentsSize.width / 2;
                    }
                    if (finish < -contentsSize.width / 2) {
                        start += contentsSize.width / 2;
                        finish += contentsSize.width / 2;
                    }
                    var duration = this._duration * bounds.width / (2.0 * this._hoverSpeed * Math.abs(this._delta));
                    this._tweenPosition(start, finish, duration);
                }
            }
        }
    },
    scrollTo: function(itemIndex) {
        if (this._tween) {
            this._tween.dispose();
            this._tween = null;
        }
        this._ensureBounds();
        var contentsSize = this._contentsBounds;
        var obj = this._content.style;
        var start = parseInt(obj[this._prop]);
        if (isNaN(start)) start = 0.0;
        var slice = this._bounds.width / this.get_itemsPerView()
        var finish = -itemIndex * slice;
        // looping effect
        if (finish > 0) {
            finish -= contentsSize.width / 2;
        } else if (finish < -contentsSize.width / 2) {
            finish += contentsSize.width / 2;
        }
        var duration = Math.min(this._duration * 1.25, this._duration * Math.abs(finish - start) / slice);
        this._tweenPosition(start, finish, duration);

    },
    _updateTimer: function() {
        if (this._timer) {
            this._timer.set_interval(this._interval + (this._duration * 1000.0));
            this._timer.set_enabled(this._autoPlay);
        }
    },
    // properties
    get_itemsPerView: function() {
        return this._itemsPerView;
    },
    set_itemsPerView: function(value) {
        if (value <= 0) throw Error.argumentOutOfRange("value", value, "Value must be strictly greater than 0.");
        this._itemsPerView = value;
    },
    get_autoPlay: function() {
        return this._autoPlay;
    },
    set_autoPlay: function(value) {
        this._autoPlay = value;
        this._updateTimer();
    },
    get_easingFunc: function() {
        return this._easingFunc;
    },
    set_easingFunc: function(value) {
        this._easingFunc = value;
    },
    get_hoverSpeed: function() {
        return this._hoverSpeed;
    },
    set_hoverSpeed: function(value) {
        this._hoverSpeed = value;
    },
    get_interval: function() {
        return this._interval / 1000.0;
    },
    set_interval: function(value) {
        if (value <= 0) throw Error.argumentOutOfRange("value", value, "Value must be strictly greater than 0.");
        this._interval = value * 1000.0;
        this._updateTimer();
    },
    get_duration: function() {
        return this._duration;
    },
    set_duration: function(value) {
        this._duration = value;
        this._updateTimer();
    },
    // events
    add_scroll: function(handler) {
        this.get_events().addHandler('scroll', handler);
    },
    remove_scroll: function(handler) {
        this.get_events().removeHandler('scroll', handler);
    },
    raiseScroll: function(eventArgs) {
        var handler = this.get_events().getHandler('scroll');
        if (handler) {
            handler(this, eventArgs);
        }
    },
    add_scrollStop: function(handler) {
        this.get_events().addHandler('scrollStop', handler);
    },
    remove_scrollStop: function(handler) {
        this.get_events().removeHandler('scrollStop', handler);
    },
    raiseScrollStop: function(eventArgs) {
        var handler = this.get_events().getHandler('scrollStop');
        if (handler) {
            handler(this, eventArgs);
        }
    }
}
Pacem.UI.ContentSlider.registerClass('Pacem.UI.ContentSlider', Sys.UI.Behavior);
// event args
Pacem.UI.ScrollEventArgs = function(scrollDelta) {
    Pacem.UI.ScrollEventArgs.initializeBase(this);
    this._delta = scrollDelta;
}
Pacem.UI.ScrollEventArgs.prototype = {
    get_delta: function() {
        return this._delta;
    }
}
Pacem.UI.ScrollEventArgs.registerClass('Pacem.UI.ScrollEventArgs', Sys.EventArgs);

if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();

if(typeof(Sys)!=='undefined')Sys.Application.notifyScriptLoaded();