﻿Type.registerNamespace("UI");

// Constructor
UI.CounterExtender = function(element) {

    UI.CounterExtender.initializeBase(this, [element]);

    // The counter ID used to store the increments on the server side
    this._counterID = null;
    
    // The total number of digits to display
    this._numberOfDigits = 0;
    
    // Specifies whether to animate the counters or not
    this._animate = true;

    // The digit height in pixels in the digits image
    this._digitHeight = 16;

    // Holds the timer that calls the web service
    this._updateIncrementsTimer = null;

    // Holds the increments array for each second returned from the sever
    this._currentIncrements = null;
    
    // The current second within the increments array
    this._currentSecond = 0;

    // A boolean used to determine if this is the first update of the wheels
    // Used not to animate the wheels on the first update, then it's set to false
    this._firstUpdate = true;

    // Hold the wheels array
    this._wheels = [];
}

UI.CounterExtender.prototype = {
    // Initializes the extender control
    initialize: function() {
        UI.CounterExtender.callBaseMethod(this, 'initialize');

        // Get main div element
        var element = this.get_element();

        // Clear div child elements
        element.innerHTML = "";

        // Add left span
        var spanLeft = document.createElement('span');
        spanLeft.className = "left";
        element.appendChild(spanLeft);

        // Add wheels and digits
        for (var i = 0; i < this._numberOfDigits; i++) {
            // Add wheel
            var spanWheel = document.createElement('span');
            spanWheel.className = "wheel";
            element.appendChild(spanWheel);

            // Add digit to wheel
            var spanDigit = document.createElement('span');
            spanDigit.className = "digit";
            spanWheel.appendChild(spanDigit);

            // Create new wheel object
            var wheel = new UI.Wheel(this, spanDigit, 0);

            // Add wheel to wheels array
            this._wheels[i] = wheel;
        }

        // Add right span
        var spanRight = document.createElement('span');
        spanRight.className = "right";
        element.appendChild(spanRight);

        // Update counter
        this._start();
    },

    _start: function() {
        // Call the webservice and retrieve next minute increments for this counter
        var service = new CAPS.WebSite.Shared.LookupWebService();
        service.GetIncrements(
                this._counterID,
                Function.createDelegate(this, this._onGetIncrementsComplete),
                Function.createDelegate(this, this._onGetIncrementsFailed));
    },

    _onGetIncrementsComplete: function(increments) {
        // Reset the current second
        this._currentSecond = 0;

        // Set the current increments array
        this._currentIncrements = increments;        

        // Start incrementing the counter from the increments array
        this._startIncrementing();
    },

    _onGetIncrementsFailed: function(value) {
        // Do nothing if the webservice call failed
    },

    _startIncrementing: function() {
        // If we reached the end of the increments array, call the webservice to get next minute increments
        if (this._currentSecond >= this._currentIncrements.length) {
            this._start();
            return;
        }

        // Get the increment value from the array for the current second
        var currentValue = this._currentIncrements[this._currentSecond];

        // Get the zero padded string
        var padded = this._padString(currentValue);

        // Update wheels values
        for (var i = 0; i < this._wheels.length; i++) {
            this._wheels[i].setValue(parseInt(padded.charAt(i)));
        }

        // Set the _firstUpdate bool to false so that it animates the wheels on the next update
        this._firstUpdate = false;
        
        // Increment the current second
        this._currentSecond++;

        // Call this function again after 1 second to update the next value
        this._updateIncrementsTimer = window.setTimeout(Function.createDelegate(this, this._startIncrementing), 1000);
    },

    // Left-pad a number with zeros
    _padString: function(num) {
        var str = num + "";
        while (str.length < this._numberOfDigits)
            str = "0" + str;
        return str;
    },

    dispose: function() {

        // Dispose update timer
        if (this._updateIncrementsTimer != null) {
            window.clearTimeout(this._updateIncrementsTimer);
            this._updateIncrementsTimer = null
        }

        UI.CounterExtender.callBaseMethod(this, 'dispose');
    }
}

// Represents a wheel in the counter
UI.Wheel = function(parent, digit, value) {
    // The parent counter
    this.parent = parent;

    // The digit span element
    this.digit = digit;

    // The current top offset of the digit image
    this.currentPosition = this._getPosition(value);

    // The target top offset of the digit image to animate to
    this.targetPosition = this.currentPosition;

    // The animation timer
    this.timer = null;    
}

UI.Wheel.prototype = {
    setValue: function(value) {
        // Get the top offset of the value
        this.targetPosition = this._getPosition(value);

        // Animate the wheels if animation is chosen and it's not the first update
        if (this.parent._animate && !this.parent._firstUpdate) {
            this._animate();
        }
        else {
            // No animation, just set the top offset of the digit to the target value
            this.digit.style.top = this.targetPosition + "px";

            // Set the current position to the target position
            this.currentPosition = this.targetPosition;
        }        
    },

    _animate: function() {
        // Stop the animation timer
        if (this.timer != null)
            window.clearTimeout(this.timer);

        // Check if we reached the target position
        if (this.currentPosition != this.targetPosition) {

            // Check if we reached the end of the wheel (last 9), jump to the first 9
            if (this.currentPosition < this._getPosition(9))
                this.currentPosition += (-1 * this._getPosition(9));
            else
                // Decrement the current position by 1 pixel
                this.currentPosition = this.digit.offsetTop - 1;

            // Set the top offset to the new value
            this.digit.style.top = this.currentPosition + "px";
            
            // Call this function again after 20 seconds, to animate the wheel
            this.timer = window.setTimeout(Function.createDelegate(this, this._animate), 20);
        }
    },

    _getPosition: function(value) {
        // return the top offset based on the value and digit height
        return ((value * -this.parent._digitHeight) - this.parent._digitHeight);
    },

    dispose: function() {
        // Dispose animation timer
        if (this.timer != null) {
            window.clearTimeout(this.timer);
            this.timer = null
        }
    }
}

UI.Wheel.registerClass('UI.Wheel', null, Sys.IDisposable);
UI.CounterExtender.registerClass('UI.CounterExtender', Sys.UI.Behavior);

if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
