/*
 GOBEHEMOTH, All rights reserverd.
 Developed by sedgar: sedgar@gobehemoth.com
*/

var Controls = {};

var UpdateExtender = new Class({ 
	
	Implements: [Options], 
	
	options: {
		indicatorSrc: 'assets/templates/metalic/images/loader32x32.gif', // image url which should be displayed on async updation
		panelId: null, // panel which should be async updated
		containerId: null, // container in center of which indicator should be displayed
		baseUrl: '',
    },
	
    initialize: function (options) {
        this.setOptions(options);
        this.initIndicator();
    },

    initIndicator: function() {
        if (this.options.panelId) {
            this.indicator = new Image();
            this.indicator.src = this.options.baseUrl + this.options.indicatorSrc;
            this.indicator.style.display = 'none';
            this.indicator.style.position = 'absolute';
            this.indicator.style.zIndex = '9999';
            //$(this.options.panelId).appendChild(this.indicator);
            $(this.indicator).appendTo(this.options.panelId);
        } else {
            throw 'Async panel indicator initialization failed, panel Id is undefined.';
        }
    },

    show: function(senderObj) {
        this._setIndicatorPosition();
        //ToDo: show disabled panel
        Element.show(this.indicator);
    },

    hide: function(senderObj) {
        Element.hide(this.indicator);
        //ToDo: hide disabled panel
    },

    _setIndicatorPosition: function() {
        //var position = Position.cumulativeOffset(this.options.containerId);
        try {
        	var panel = $(this.options.panelId).css('position', 'relative');
        	/*if ($(this.options.panelId)) {
            	Position.relativize(this.options.panelId);
            }*/
        } catch (e) {
            //alert($(this.options.panelId) + " Position.relativize: " + e.message);
        }

        var element = this.options.containerId ? $(this.options.containerId) : $(this.options.panelId);
        //var dim = $(element).getDimensions();
        var dim = {height: element.height(), width: element.width};

        var x = dim.height / 2
        var y = dim.width / 2;

        this.indicator.style.left = y + 'px';
        this.indicator.style.top = x + 'px';
    }
});

var TakeGunControl = new Class({

	Extends: WebService,
	
    initialize: function (options) {
    	this.parent(options);
        this.options.submitParams['action'] = 'getControl';
        this.button = null;

		this.onClickHandler = jQuery.proxy(this.onClick, this);
		this.onDomReadyHandler = jQuery.proxy(this.onReady, this);

		this.initButtons();
		if (!this.isButtonAvailable()) {
		    $(document).ready(this.onDomReadyHandler);
	    }
    },
    
    initButtons: function() {
        if (this.options.buttonIds) {
            this.button = $(this.options.buttonIds);
        } else if (this.options.buttonId) {
            this.button = $(this.options.buttonId);
        }
        
        if (this.isButtonAvailable()) {
            this.button.click(this.onClickHandler);
        }
    },
    
    enableButton: function() {
    	if (this.button) {
	    	this.button.removeAttr('disabled');
	    	this.button.animate({opacity:1}, 1000);
    	}
    },
    
    disableButton: function() {
    	if (this.button) {
	    	this.button.attr('disabled', 'disabled');
	    	this.button.animate({opacity:0.10}, 500);
    	}
    },
    
    /*visible: function(visible) {
    	// this.options.panelId
    	if (this.button) {
        	this.visibleElement(this.button, visible);
        }
    },*/
    
    request: function(sender) {
    	if (this.isGinAvailable()) {
    		this.disableButton();
    		this.onRequest();
    	}
    },
    
    isGinAvailable: function() {
        return Application.gunControl 
            && (Application.gunControl.currentGunMode == Application.gunControl.gunModes.available 
                || Application.gunControl.currentGunMode == Application.gunControl.gunModes.locked
                );
    },
    
    isButtonAvailable: function() {
        return this.button != null && this.button.length > 0;
    },
    
    onReady: function(eventObj) {
        this.initButtons();
    },
    
    onClick: function(eventObj) {
        this.request(eventObj.target);
        eventObj.stopPropagation();
        eventObj.preventDefault()
        return false;
    },
    
    onResponseReceived: function(responseObj) {
        if (responseObj.success) {
            if ($.isArray(responseObj.users)) {
                // update queue
                Application.usersQueue.parseUsersData(responseObj.users);
                //this.visible(false);
            }
            
            if (responseObj.available) {
                //this.visible(false);
                return;
            }
        } else {
            this.showResponseErrors(responseObj);
        }
        
        //this.visible(true);
    },
    
    onFailed: function(transport) {
        this.enableButton();
        Application.gunControl.setGunState();
    }
});

var QueueService = new Class({

    options: {
        panelSlr: null,
        panelQueueSlr: null,
        panelInnerSlr: null,
        panelTimeSlr: null,
        panelOnDeckSlr: null,
        panelDeckUserSlr: null,
        timeSlr: null,
        serviceUrl: null,
        interval: null,
        cssCurrentUser: null,
        cssAltUser: null
    },

	Extends: WebService,
	
    initialize: function (options) {
    	this.parent(options);
        this.options.submitParams['action'] = 'getQueue';
        
        this.queuePanel = $(this.options.panelSlr);
        
        this.timerHandler = null;
		this.itemTpl = "<div class='row ${style}' id='user${id}'><div class='user' title='Added ${added}, available ${shots} shots.'>${fullname}</div></div>"; 
        //this.itemTpl = $.template("<div class='row ${style}' id='user${id}'><div class='user' title='Added ${added}, available ${shots} shots.'>${username}</div></div>"); 
        //this.controlingTime = 30; // seconds
        
        this.timer = new Timer();
        this.timer.onTick = jQuery.proxy(this.onWaitTimeTick, this);
        
        this.startQueueTime = 0;
        this.endQueueTime = 0;
        this.queue = [];
    },
    
    setStartQueueTime: function(time) {
        var time = parseInt(time);
        if (Object.isNumber(time)) {
            this.startQueueTime = time;
        }
    },
    
    setQueue: function(responseObj) {
        if (!responseObj.success && typeof(responseObj.error) == 'string') {
            alert(responseObj.error);
        } else if ($.isArray(responseObj.users) && responseObj.users.length > 0) {
            this.parseUsersData(responseObj.users);
        } else {
            this.clearQueue();
            if (Application.gunControl) {
            	Application.gunControl.setGunState();
            }
        }
    },
    
    setNextUserInfo: function(user) {
        var panel = $(this.options.panelOnDeckSlr);
        var elm = $(this.options.panelDeckUserSlr);
        
        if (panel.length == 0 || elm.length == 0) {
            throw("UserQueue: wrong selector for On Deck panel.");
        }
            
        if (user) {
            if (elm.length) {
                elm.html(this.__getUserName(user));
            }
            
            panel.show(1000);
        } else {
            panel.hide();
        }
    },
    
    setControlledByInfo: function(user) {
        var elm = $(this.options.controlledByPanelId);
        var username = 'nobody';
        
        if (user) {
        	username = typeof(user) == 'string' ? user : user.username;
        }
        
        if(elm.length) {
        	elm.html(username);
        } else {
        	throw("UserQueue: panel with id "+this.options.controlledByPanelId+" is not found.");
        }
    },
    
    start: function() {
    	// interval in seconds
        this.executer = $.timer(this.options.interval * 1000, this.onRequestHandler);
    },
    
    stop: function() {
        this.executer.stop();
    },
    
    parseUsersData: function(itemsObj) {
        var rows = '';
        var waitTime = 0;
        var gunOwner = null;
        var nextGunOwner = null;
        
        if ($.isArray(itemsObj) && itemsObj.length > 0) {
            this.currentUserIndex = -1;
            this.queue = itemsObj;

            waitTime = this.queue[this.queue.length - 1].leftTime;
            gunOwner = this.queue[0];
            if (this.queue.length > 1) {
                nextGunOwner = this.queue[1];
            }
            this.setStartQueueTime(gunOwner.started);
            this.clearQueue();
                    
            for(var i = 0; i < this.queue.length; i++) {
                this.queue[i].style = this.__buildItemStyle(i);
                
                if (Application.userInfo.isCurrentUser(this.queue[i])) {
                    this.queue[i].style += ' ' + this.options.currentUserCssClass;
                    this.currentUserIndex = i;
                    waitTime = this.queue[i].leftTime;
                }
                
                if (!this.queue[i].fullname) {
                    this.queue[i].fullname = this.queue[i].username;
                }
                
                this.addToQueue(this.queue[i]);
                
                // update waiting time by sum of aim time all users in queue
                if (this.currentUserIndex < 0) {
                    //var aimTime = parseInt(this.queue[i].aimTime);
                    //if (Object.isNumber(aimTime)) {
                    //    waitTime += aimTime;
                    //}
                }
            }
        }
        
        if (gunOwner == null || !Application.gunControl.isLockedByUser(gunOwner.id)) {
            Application.gunControl.setGunState(gunOwner);
        }
        
        this.showQueue();
        if(gunOwner.isCurrentUser == '0') {
            this.startWaitTimer(waitTime);
        }
        //this.setControlledByInfo(gunOwner);
        this.setNextUserInfo(nextGunOwner);
    },
    
    removeItemByUserId: function(userId) {
        var element = $('#user' + userId);
        if (element.length > 0) {
            element.remove();
            
            if (this.queue && this.queue.length > 0) {
                this.queue.shift();
                this.parseUsersData(this.queue);
            }
        }
    },
    
    showQueue: function() { 
        var panel = $(this.options.panelQueueSlr);
        if (panel.length) {
            this.queuePanel.show();
            //this.emptyPanel.hide();
            //panel.html(htmlRows);
        }
    },
    
    clearQueue: function() {
        $(this.options.panelQueueSlr).empty();
    },
    
    addToQueue: function(userData) {
        $.tmpl(this.itemTpl, userData).appendTo(this.options.panelQueueSlr);
    },
    
    setWaitTime: function(seconds) {
        if (seconds >= 0) {
            this.waitTime = seconds;
            this.setWaitTimerText(seconds);
        } else {
            this.timer.stop();
            this.waitTime = 0;
            $(this.options.panelTimeSlr).hide();
            
            if (Object.isArray(this.queue) && this.queue.length > 0) {
                // user have gun control?
                if (this.__isUserCanControlling(this.currentUserIndex)) {
                    for(var i = 0; i < this.currentUserIndex; i++) {
                        $('user' + this.queue[i].id).remove();
                        this.queue.shift();
                    }    
                } else {
                    this.queue.shift();
                }

                this.parseUsersData(this.queue);
            }
        }
    },
    
    setWaitTimerText: function(seconds) {        
        var element = $(this.options.timeSlr);
        if (element.length) {
            if (!Object.isNumber(seconds)) {
                milliseconds = 0;
            }
            var timerText = this.timer.getFormattedTime(new Date(seconds * 1000));
            element.html(timerText);
        }
    },
    
    startWaitTimer: function(seconds) {
        if (seconds > 0 && !this.timer.isStarted) {
            // sync endQueueTime value
            //this.endQueueTime = this.startQueueTime + seconds;
            this.timer.start();
            this.waitTime = seconds;
            $(this.options.panelTimeSlr).show();
            this.setWaitTimerText(seconds);
        }
    },
    
    onWaitTimeTick: function(timer) {
        // var dif = this.endQueueTime - this.timer.getCurrentUnixTimeStamp();
        // var waitTime = -1;
        // 
        // if (dif > 0) {
        //     waitTime = dif * 1000;
        // } else {
        // 
        // }

        this.setWaitTime(this.waitTime - 1);
    },
    
    onAimDisable: function() {
        Application.gunControl.disable();
    },
    
    onSuccess: function(responseObj) {
        if (responseObj) {
            this.setQueue(responseObj);
        }
    },
    
    __buildItemStyle: function(index) {
        return index % 2 > 0 ? this.options.altCssClass : "";
    },
    
    __isUserCanControlling: function(index) {
        return index >= 0 && this.queue.length > index && this.queue[index].started - 1 <= this.timer.getCurrentUnixTimeStamp();
    },
    
    __getUserName: function(user) {
        var username = user;
        if (user && typeof(user) == 'object') {
        	username = user.fullname ? user.fullname : user.username;
        }
        
        return username;
    }
    
});

var FreeShotService = new Class({

	Extends: WebService,

    initialize: function (options) {
    	this.parent(options);

        this.failedTimeout = 60; // seconds
        this.shotTimeout = null;
        this.options.submitParams['action'] = 'freeShotTime';
        this.options.alertPrefix = 'FreeShotService: ';
        
        this.onStartFreeShotHandler = jQuery.proxy(this.onStartFreeShot, this);
        this.onFinishFreeShotHandler = jQuery.proxy(this.onFinishFreeShot, this);
        this.onGetTimeOfShotHandler = jQuery.proxy(this.onGetTimeOfShot, this);
        this.onFreeShotClickHandler = jQuery.proxy(this.onFreeShotClick, this);
        this.onTickHandler = jQuery.proxy(this.onTick, this);
        
        this.timer = new Timer();
    },
    
    initTakeFreeShotsPanel: function() {
        this.visibleCountDown(false);
        this.visibleTakeFreeShot(true);
    },
    
    initCountDownPanel: function(shotTimeObj) {
        this.visibleTakeFreeShot(false);
        this.enableShotButton(false);
        var startTime = parseInt(shotTimeObj.startTime);
        
        if (Object.isNumber(startTime) && startTime > 0) {
            var result = this.setTimeOfShot(startTime, parseInt(shotTimeObj.leftTime));
            // while script is loaded, time for shooting been expired
            if (!result) {
                // take new
                this.onGetTimeOfShot();
            }
        } else {
            // invalid timeout received, strange, try take new but with timeout
            this.onShotTimeoutExceed();
        }
    },
    
    start: function(availableBonusShots, shotTimeObj) {
        if (Object.isNumber(availableBonusShots) && availableBonusShots > 0) {
            this.setAvailableBonusShots(availableBonusShots);
        } else {
            this.initCountDownPanel(shotTimeObj);
            $(this.options.buttonId).click(this.onFreeShotClickHandler);
        }
    },
    
    setTimeOfShot: function(shotTime, leftServerTime) {
        if (Object.isNumber(shotTime)) {
            this.visibleCountDown(true);
            this.shotTime = shotTime;
            this.startTime = this.timer.getCurrentUnixTimeStamp();
            // seconds to a free shot left
            this.shotTimeout = this.shotTime - this.startTime; 
            
            if (leftServerTime >= 0 && Math.abs(this.shotTimeout - leftServerTime) > 5) {
                // user side time is not synchronized
                this.shotTimeout = leftServerTime - 1;
                this.shotTime = this.startTime + this.shotTimeout;
            }
            
            if (this.shotTimeout > 0) {
                // free shot is not available, set countdown timer
                this.setTimerText(this.shotTimeout);
                this.showInfo(false);
                this.timer.start(this.onTickHandler, 1);
                return true;
            } else if (Math.abs(this.shotTimeout) <= this.options.shotTimeout) {
                // free shot is available for that moment
                this.onStartFreeShot(this.options.shotTimeout - Math.abs(this.shotTimeout));
                return true;
            }
        }
        
        this.onShotTimeoutExceed();
        return false;
    },
    
    setAvailableBonusShots: function(shots) {
        if (shots == 0) {
            this.initCountDownPanel();
            this.getTimeOfShot();
        } else {
            var element = $(this.options.bonusShotsCountId);
            if (element.length > 0) {
                element.html(shots);
                this.visibleTakeFreeShot(true);
            } else {
                this.showAlert('Container for available free shots counter is not found.');
            }
        }
    },
    
    setTimerText: function(timerText) {
        var element = $(this.options.countDownId);
        if (element.length > 0) {
            element.html(timerText);
        } else {
            this.showAlert('Container for free shot timer is not found.');
        }
    },
    
    showInfo: function(message) {
        if (message === false) {
            this.visibleCountDown(true);
            this.visibleElement(this.options.infoPanelId, false);
        } else {
            this.visibleCountDown(false);
            
            var panel = $(this.options.infoPanelId);
            if (panel.length > 0) {
                panel.html(message);
                this.visibleElement(panel, true);
            }
        }
    },
    
    getTimeOfShot: function() {
        this.mode = 'freeShotTime';
        this.options.submitParams['action'] = this.mode;
        this.options.serviceUrl = 'services/free-shoot.html';
        this.showInfo('Please wait...');
        this.onRequest();
    },
    
    takeFreeShot: function() {
        this.mode = 'takeFreeShot';
        this.options.submitParams['action'] = this.mode;
        this.options.serviceUrl = 'services/free-shoot.html';
        $(this.options.bonusShotButtonId).disable();
        this.onRequest();
    },
    
    makeFreeShot: function(sender) {
        if (sender.disabled || !this.enabled) {
            return false;
        }
        this.enabled = false;
        
        this.mode = 'freeshot';
        this.options.submitParams['action'] = this.mode;
        this.options.serviceUrl = 'services/aim.html';
        this.setTimerText('A FEW');
        this.onRequest();
    },

    visibleCountDown: function(visible) {
        this.visibleElement(this.options.countDownPanelId, visible);
    },
    
    visibleTakeFreeShot: function(visible) {
        this.visibleElement(this.options.bonusShotPanelId, visible);
    },
    
    enableShotButton: function(enable) {
        this.enabled = enable;
        var button = $(this.options.buttonId);
        if (enable) {
            button.css('cursor', 'pointer');
            button.removeAttr('disabled');
        } else {
            button.css('cursor', 'wait');
            button.attr('disabled', 'disabled')
        }
        //Application.gunControl.enableShootButton(enable);
    },
    
    /*
    * Event Handlers
    */
    onFreeShotClick: function(evtObj) {
        this.makeFreeShot(evtObj.target);
        evtObj.stopPropagation();
    },
    
    onTick: function() {
        // build display time
        //var currentTime = this.timer.getCurrentUnixTimeStamp();
        //var countDownTime = new Date((this.shotTime - currentTime) * 1000);
        //var timerText = this.timer.getFormattedTime(countDownTime);
        //var dif = this.shotTime - currentTime;
        this.shotTimeout -= 1;
        this.setTimerText(this.shotTimeout);
        
        if (this.shotTimeout <= 0) {
            this.timer.stop();
            this.onStartFreeShot();
        }
    },
    
    onStartFreeShot: function(shotTimeout) {
        if (!Object.isNumber(shotTimeout)) {
            shotTimeout = this.options.shotTimeout;
        } else if (shotTimeout <= 0) {
            this.onFinishFreeShot();
            return;
        }
        this.enableShotButton(true);
        this.visibleCountDown(false);
        this.showInfo('FIRE! (' + shotTimeout + ' sec)');
        
        this.timer.start(this.onFinishFreeShotHandler, shotTimeout);
    },
    
    onFinishFreeShot: function(executer) {
        this.timer.stop();
        this.enableShotButton(false);
        this.getTimeOfShot();
    },
    
    onGetTimeOfShot: function(executer) {
        this.timer.stop();
        this.getTimeOfShot();
    },
    
    onShotTimeoutExceed: function() {
        this.timer.start(this.onGetTimeOfShotHandler, this.failedTimeout);
    },
    
    onResponseReceived: function(responseObj) {
        switch(this.mode) {
            case 'freeShotTime':
                this.onSuccessShotTime(responseObj);
                break;
            case 'takeFreeShot':
                this.onSuccessFreeShotTaken(responseObj);
                break;
            case 'freeshot':
                this.onSuccessFreeShot(responseObj);
                break;
        }
    },

    onSuccessShotTime: function(responseObj) {
        if (!responseObj.success) {
            this.showResponseErrors(responseObj);
        } else if (responseObj.timeData) {
            this.setTimeOfShot(parseInt(responseObj.timeData.startTime), parseInt(responseObj.timeData.leftTime));
        }
    },

    onSuccessFreeShotTaken: function(responseObj) {
        $(this.options.bonusShotButtonId).enable();
        
        if (responseObj.success) {
            if (Object.isNumber(responseObj.freeShots)) {
                this.setAvailableBonusShots(responseObj.freeShots);
            }
            
            if (Object.isNumber(responseObj.shots)) {
                // update shots count placeholders
                Application.userInfo.setShotsCount(responseObj.shots);
            }
        }
        else if (!responseObj.success && $.isArray(responseObj.errors)) {
            this.showAlert(responseObj.errors[0]);
        }
    },
    
    onSuccessFreeShot: function(responseObj) {
        if (!responseObj.success) {
            this.showInfo('Too slow...Joe.');
        } else
        if (Application.userInfo.userId != null) {
            this.showInfo('Nice shot...');
        } else {
            this.showInfo('Nice shot...');
        }
    },
    
    onFailed: function(transport) {
        if (this.mode == 'freeShotTime') {
            this.onShotTimeoutExceed();
        } else if (this.mode == 'takeFreeShot') {
            $(this.options.bonusShotButtonId).enable();
        }
    }
});

