// JavaScript Document

var BlackJackApp = Class.extend({

    BANNER_SRC: './img/banner.jpg',
    PANDA_SRC: './img/panda.gif',
    
    CARDS_IMGS_PATH: './img/cards/',
    REM_CARDS_IMGS_PATH: '/img/cards/',
    CARDS_FILES_EXT: 'png',
    BLANK_CARD_FNAME: 'blank',
    BACK_CARD_FNAME: 'back',

    STEPS_IDS: ['number', 'check', 'enter', 
                'card', 'approve', 'score', 
                'group', 'operation', 'confirm'],
                
    MARKS_ELMS_IDS: ['number-accepted', 'account-accepted', 'card-accepted', 
                     'confirm-action', 'group-act-result' ],
                     
    ACTIONS_ELMS: {
            'number-act':  { alignment: 'left',   
                             controlledElms: ['lepro-number'] },
            'check-act':   { alignment: 'middle', 
                             controlledElms: [] },
            'enter-act-1': { alignment: 'right',  
                             controlledElms: ['login-button'] },
            'enter-act-2': { alignment: 'right',
                             controlledElms: ['password', 're-password', 'user-captcha', 
                                            'email', 'logincode', 'enter-button'],
                             hide: true },
            'enter-act-3': { alignment: 'right',
                             controlledElms: ['enter-cont-button'],
                             hide: true },
            'card-act':    { alignment: 'left',
                             controlledElms: [] },
            'approve-act-1': { alignment: 'middle',
                               controlledElms: [/* 'card-code', 'card-scode', 
                                                */'check-profile-button'] },
            'approve-act-2': { alignment: 'middle',
                             controlledElms: ['recheck-profile-button'],
                             hide: true },
            'score-act':   { alignment: 'right',
                             controlledElms: [] },
            'group-act': { alignment: 'left',
                           controlledElms: ['group-name'] },                            
            'operation-act': { alignment: 'middle',
                               controlledElms: [] },
            'confirm-act-1': { alignment: 'right',
                               controlledElms: ['action-type', 'confirm-act-button'] },                             
            'confirm-act-2':  { alignment: 'right',
                                controlledElms: ['group-code', 'code-entered', 'reenter-gname'],
                                hide: true },
            'confirm-act-3':  { alignment: 'right',
                                controlledElms: ['return-to-gname'],
                                hide: true },                                
            'modes-switch':{ alignment: 'centered',
                             controlledElms: ['21-mode-switch'] },
            'tables':      { alignment: 'centered',
                             controlledElms: [] }                            
        },
        
    DIRTY_OFFSET: 5000000, 
    
    APP_URL_PATH: 'http://blackjack.crzcrz.net',
    APP_TITLE: 'Leprosorium Black Jack',
    
    PROFILE_CARD_HTML_V1: '<a href="%site%"><img src="%img%" alt="%title%" title="%name%"></a>',
    PROFILE_CARD_HTML_V2: '[<a href="%site%">%html%</a>] <a href="%site%">%name%</a>',

    construct:
        function() {
             this._steps = null;
             this._marks = null;
             this._actions = null; 
             
             this._currentUserId = null;
             this._currentUserCard = null;
             this._currentUserInfo = null;
             
             this._groupsInfo = null;
             this._groupAction = null;
             
             this._infoBlockMode = null;        
             
             this._statsManager = new LBJStatsLoader(null);             
        },
        
    /* construction */
        
    initializeElems:
        function() {
            // steps arrows elems
            this._steps = {};
            for (var stepIdx in this.STEPS_IDS) {
                var nextId = parseInt(stepIdx) + 1; 
                if (this.STEPS_IDS[nextId]) {
                    var newStep = new Step(this.STEPS_IDS[stepIdx], this.STEPS_IDS[nextId], false);
                    this._steps[newStep.elementId] = newStep;  
                }
            }
            // marks instances
            this._marks = {};
            for (var markIdx in this.MARKS_ELMS_IDS) {
                var markId = this.MARKS_ELMS_IDS[markIdx];
                this._marks[markId] = new Mark(markId, false, true);
            }
            
            // actions blocks
            this._actions = {};
            for (var actionId in this.ACTIONS_ELMS) {
                var action = this.ACTIONS_ELMS[actionId];
                this._actions[actionId] = new ActBlock(actionId, 
                        action.alignment, action.controlledElms,
                        null/* means 'prepared'*/, 
                        (action.hide && (action.hide == true)) ? action.hide : false);
            }
            
            this._loadingElm = document.getElementById('loading-process');
            
            // login block elements
            this._lnumberField = document.getElementById('lepro-number');
            this._loginButton = document.getElementById('login-button');
            this._resInfoField = document.getElementById('number-found');
            this._buttonLabelElm = document.getElementById('login-button-label');
            // enter block elements
            this._captchaElm = document.getElementById('captcha');
            this._loginCodeElm = document.getElementById('logincode');
            this._captchaEnlarged = false;
            // cards block elements
            this._cardImageElm = document.getElementById('card-img');
            // approve block elements
            this._cardCodeElm = document.getElementById('card-code'); 
            this._cardSCodeElm = document.getElementById('card-scode');
            // score block elements
            this._scoreElm = document.getElementById('score-num');
            // group block elements
            this._gnameField = document.getElementById('group-name');
            this._confirmButton = document.getElementById('confirm-act-button');
            this._gresActField = document.getElementById('group-act-label');            
            this._cbuttonLabelElm = document.getElementById('confirm-button-label');
            this._actionTypeField = document.getElementById('action-type');
            this._gcodeField = document.getElementById('group-code');
            // info caller elements
            this._infoRadios = document.getElementsByName('info-type');
            this._infoValueField = document.getElementById('info-for');
            this._infoImg = document.getElementById('info-type-img');
            
            this._applyBanner('heading-logo');
            this._initLoadingElm();
            
            this._prepareFirstActions(); 
            
            this._statsManager.initializeInfoElems('info-content', 'floating-info');           
        },
        
    _applyBanner:
        function(bannerElmId) {
            var bannerElm = document.getElementById(bannerElmId);
            if (bannerElm) bannerElm.src = this.BANNER_SRC;
        },
        
    _initLoadingElm:
        function() {
            if (this._loadingElm) {
                this._loadingElm.src = this.PANDA_SRC;
                this._loadingElm.className = 'hidden';
                this._statsManager.setLoadingDisplayElm(this._loadingElm);
            }            
        },
        
    _prepareFirstActions:
        function() {
            this._marks['number-accepted'].makeDeny();
            this._actions['tables'].setClassName('stats');
        },
        
    /* helpers */
        
    _showLoadingIcon:
        function() {
             if (this._loadingElm) this._loadingElm.className = '';
        },
        
    _hideLoadingIcon:
        function() {
             if (this._loadingElm) this._loadingElm.className = 'hidden';
        },        
        
    getMark:
        function(markId) {
            return this._marks[markId];
        },
        
    switchStep:
        function(stepFrom, stepTo, doSwitchOn) {
            this._steps[stepFrom + '-to-' + stepTo].switchState(doSwitchOn);
        },        
        
    _wrapWithClass:
        function(text, className) {
            return '<span class="' + className + '">' + text + '</span>';
        },
        
    _actInput:
        function(inputElmId, doEnable) {
            var inputElm = document.getElementById(inputElmId);
            if (inputElm) {
                inputElm.style.display = doEnable ? '' : 'none';
                // inputElm.className = 'inactive hidden';
                inputElm.disabled = true;
                var cursor = inputElm;
                for (var i = 0; i <= 2; i++) { // maximum 2 elements before (text and tag)
                    var psbLabel = cursor.previousSibling;
                    if ((psbLabel.nodeType == 1) && 
                        (psbLabel.tagName.toLowerCase() == 'label') && 
                        (psbLabel.htmlFor == inputElmId)) {
                        // psbLabel.className = 'hidden';
                        psbLabel.style.display = doEnable ? 'block' : 'none';
                    } else cursor = psbLabel;
                }
            }
        },
        
    _disableInput:
        function(inputElmId) {
            this._actInput(inputElmId, false);
        },
        
    _enableInfoReceiverForm:
        function() {
            var idsList = ['info-for', 'info-type-username', 'info-type-user', 'info-type-group', 'get-info-for'];
            for (idIdx in idsList) {
                var elm = document.getElementById(idsList[idIdx]); 
                if (elm) elm.disabled = false;
            }
        },        
        
    _showBlankCard:
        function() {
            this._cardImageElm.src = this.CARDS_IMGS_PATH + 
                            this.BLANK_CARD_FNAME + '.' + this.CARDS_FILES_EXT;
        },
        
    _showCardBack:
        function() {
            this._cardImageElm.src = this.CARDS_IMGS_PATH + 
                            this.BACK_CARD_FNAME + '.' + this.CARDS_FILES_EXT;
        },
        
    _generateCardProfileCode:
        function(cardData, shortVersion) {
            var replacements = {
                    'site':  this.APP_URL_PATH,
                    'img':   this.APP_URL_PATH + this.REM_CARDS_IMGS_PATH + cardData.file,
                    'title': this.APP_TITLE,
                    'name':  cardData.name,
                    'html':  cardData.html
                }
            return projectionalReplace(
                shortVersion ? this.PROFILE_CARD_HTML_V2 : this.PROFILE_CARD_HTML_V1, 
                replacements);            
        },
        
    _installCaptcha: 
        function(loginCode) {
            if (loginCode == '') {
                // alert('already logged in to site, hiding captcha');
                this._captchaElm.style.display = 'none';
                this._disableInput('user-captcha');
            } else {
                // alert('not yet logged in to site, configuring captcha');
                var prevAlt = this._captchaElm.alt;
                var prevTitle = this._captchaElm.title;
                this._showLoadingIcon(); showInfo('RC1726: Загружаем капчу, терпение!');
                this._captchaElm.alt = 'Загружаем капчу';
                this._captchaElm.title = 'Загружаем капчу';
                // this._captchaElm.src = 'http://leprosorium.ru/captchaa/' + loginCode;
                this._captchaElm.src = './r/c?lc=' + loginCode;
                this._loginCodeElm.disabled = false;
                this._loginCodeElm.value = loginCode;
                this._captchaElm.alt = prevAlt;
                this._captchaElm.title = prevTitle;
                this._hideLoadingIcon();
            }        
        },
        
    enlargeCaptcha:
        function() {
            this._captchaEnlarged = !this._captchaEnlarged;
            this._captchaElm.className = this._captchaEnlarged ? 'enlarged' : '';
        },
        
    _isCorrectResponse:
        function(response) {
            return ((response != '') && (response != ':(') && (response != '":("'));
        },
        
    _getRadiosValue:
        function(radioGroup) {
            if (radioGroup) {
                for(var radioId=0; radioId < radioGroup.length; radioId++) {
                    if (radioGroup[radioId].checked) return radioGroup[radioId].value;
                }                
            }
            return null;
        },
        
    _loadInInfoBox:
        function(infoType, infoValue) {
            var radioBtn = document.getElementById('info-type-' + infoType);
            if (radioBtn) radioBtn.checked = true;
            if (this._infoValueField) this._infoValueField.value = infoValue; 
            this.tryToGetInfo(infoType, infoValue);
        },                                       
        
    /* responces checking */
        
    _checkLoginResponse:
        function(response) {
            if (response == '-1') {
                showError('Какбе не удаётся подключиться к базе :(');
                return false;
            } else if (response == '-2') {
                showInfo('Введите, пожалуйста, число, не надо хулиганить!');
                return false;                
            } else return true;
        },
        
    _checkEnterResponse:
        function(response) {
            var errorText = '';
            switch (response) {
                case "-1": errorText = 'Пароль пустой или имеет подозрительный формат'; break;
                case "-2": errorText = 'Повторный пароль пустой или имеет подозрительный формат'; break;
                case "-3": errorText = 'E-mail имеет подозрительный формат'; break;
                case "-4": errorText = 'Капча была введена невнимательно или произошла внутренняя ошибка'; break;
                case "-5": errorText = '404: Ваш аккаунт not found! (или капча опознана вами неверно)'; break;
                case "-6": errorText = 'Ошибка в механизме регистрации/опознавания пользователя'; break;
                case "-7": errorText = 'Ошибка в механизме регистрации/опознавания пользователя'; break;
                case "-8": errorText = 'Данные о пользователе не доступны :('; break;
                case "-9": errorText = 'Какой-то не тот пароль'; break;
                case "-10": errorText = 'Исходный пароль не похож на повторный и наоборот'; break;
                default: return '';
            }
            showInfo(errorText, 10000);
            return errorText;
        }, 
        
    _checkActPerformedResponse:
        function(response) {
            var errorText = '';
            switch (response) {
                case "-1": errorText = 'Ошибка сессии: ваш логин как-то не подтверждён'; break;
                case "-2": errorText = 'Отосланные данные выглядят подозрительно'; break;
                case "-3": errorText = 'База данных банально отвалилась'; break;
                case "-4": errorText = 'Залогиненный пользователь потерялся в базе данных'; break;
                case "-5": errorText = 'Код, к сожалению, не совпадает'; break;
                case "-6": errorText = 'Действие запрещено правилами игры'; break;
                case "-7": errorText = 'Вы - последний пользователь в группе. Выхода нет.'; break;
                case "-8": errorText = 'Код действия не опознан'; break;
                case "-9": errorText = 'Владельцам джокеров создавать группы запрещено'; break;
                case "-10": errorText = 'Вы уже создали свою группу'; break;
                case "-11": errorText = 'Вы уже состоите в группе с одним из участников этой группы'; break;
                case "-12": errorText = 'Необходимое количество очков (%screquired%; текущее: %curscore%) для вступления в %newgnum%-ю группу не достигнуто'; break;
                default: return '';
            }
            showInfo(errorText, 10000);
            return errorText;
        },         
        
    /* public functions */                  
        
    allowToLogin:
        function(doAllow) {
            this.switchStep('check', 'enter', doAllow);
            if (doAllow) {
                this._actions['enter-act-1'].activate();
                this._actions['card-act'].deactivate(); // TODO: may be after login?
            } else {
                this._actions['enter-act-1'].deactivate();
                this._showBlankCard(); // TODO: may be after login?
                this._actions['card-act'].prepare(); // TODO: may be after login?
            }
        },
        
    allowToActGroup:
        function(doAllow) {            
            this.switchStep('group', 'operation', true);
            this.switchStep('operation', 'confirm', doAllow);
            this._actions['operation-act'].show();
            this._actions['operation-act'].activate();            
            if (doAllow) {
                this._actions['confirm-act-1'].activate();
            } else {
                this._actions['confirm-act-1'].deactivate();
            }
        }, 
        
    checkUser:
        function(number) {
            var number = number || this._lnumberField.value;
            var rif = this._resInfoField;
            var ble = this._buttonLabelElm;
            var loginMark = this._marks ? this._marks["number-accepted"] : null;
            if (number == "") {
                rif.innerHTML = 'Введите что-нибудь, ' + this._wrapWithClass('%username%', 'username-unknown');
                ble.innerHTML = 'Войти: ';
                this.allowToLogin(false);
                if (loginMark) loginMark.makeDeny();
                return;
            }
            if (allUsers) {
                if (allUsers[number]) {
                    rif.innerHTML = 'Вы, похоже, ' + this._wrapWithClass(allUsers[number], 'username');
                    ble.innerHTML = 'Это я, войти: ';
                    this.allowToLogin(true);
                    if (loginMark) loginMark.makeAccept();        
                } else {
                    rif.innerHTML = 'Мы вас не знаем, ' + this._wrapWithClass('%username%', 'username-unknown');
                    ble.innerHTML = 'Войти, чтобы знали: ';
                    this.allowToLogin(true);
                    if (loginMark) loginMark.makeUnknown();
                }
            } else {
                showInfo('Данные ещё не загружены');
                rif.innerHTML = 'Мы вас, кажется, не знаем, ' + this._wrapWithClass('%username%', 'username-unknown');
                ble.innerHTML = 'Я всё же попробую: ';
                this.allowToLogin(true);
                if (loginMark) loginMark.makeUnknown();
            }
        },
        
    checkGroup:
        function(groupName) {
            var number = number || this._gnameField.value;
            var gaf = this._gresActField;
            var cble = this._cbuttonLabelElm;
            var atf = this._actionTypeField;
            var actionMark = this._marks ? this._marks["confirm-action"] : null;            
            if (number == "") {
                if (this._groupsInfo.created) {
                    gaf.innerHTML = 'Вы уже создали группу';
                    cble.innerHTML = 'Запрещено: ';
                    atf.value = 'error';
                    if (actionMark) actionMark.makeDeny();
                    this.allowToActGroup(false);
                } else {
                    gaf.innerHTML = 'Создать группу';
                    cble.innerHTML = 'Создать: ';
                    atf.value = 'create';
                    if (actionMark) actionMark.makeCreate();
                    this.allowToActGroup(true);                
                }
                return;
            }
            if (this._groupsInfo) {
                if (parseInt(number) > this._groupsInfo.total) {
                    gaf.innerHTML = 'Нет такой группы';
                    cble.innerHTML = 'Что делать?: ';
                    atf.value = 'error';
                    if (actionMark) actionMark.makeDeny();
                    this.allowToActGroup(false);
                    return;
                } else {
                    if (inArray(this._groupsInfo.groups, parseInt(number))) {
                        var leavingAllowed = this._groupsInfo.lallow;
                        gaf.innerHTML = leavingAllowed ? 'Покинуть группу' : 'Нельзя покинуть';
                        cble.innerHTML = leavingAllowed ? 'Покинуть: ' : 'Сегодня запрещено покидать группы';
                        atf.value = leavingAllowed ? 'leave' : 'try-leave';
                        if (actionMark) {
                            if (leavingAllowed) {
                                actionMark.makeLeave();
                            } else {
                                actionMark.makeDeny();
                            }
                        }
                        this.allowToActGroup(leavingAllowed);
                        return;
                    } else {
                        gaf.innerHTML = 'Вступить в группу';
                        cble.innerHTML = 'Вступить: ';
                        atf.value = 'join';
                        if (actionMark) actionMark.makeJoin();
                        this.allowToActGroup(true);
                        return;                    
                    }
                } 
            } else showError('Данные о группах почему-то не загрузились');
        },        
        
    loginOrRegisterUser:
        function(loginCode, isRegistered) {
            this._actions['number-act'].deactivate();
            this._actions['enter-act-1'].deactivate();
            this._actions['enter-act-1'].hide();
            var passHelpSpan = document.getElementById('pass-help-label');
            if (isRegistered) {                
                if (passHelpSpan) passHelpSpan.style.display = 'none';
                this._disableInput('re-password');
                this._disableInput('email');
            } else {
                if (passHelpSpan) passHelpSpan.style.display = '';
            }          
            this._installCaptcha(loginCode);
            this._actions['enter-act-2'].show();
            this._actions['enter-act-2'].activate();
        },
        
    showEnterResult:
        function(userInfo, error) {
            var acceptMark = this._marks ? this._marks["account-accepted"] : null;
            if (acceptMark) acceptMark.setSmall(true);            
            this._actions['enter-act-2'].deactivate();
            this._actions['enter-act-2'].hide();
            this._actions['enter-act-3'].show();
            this._actions['enter-act-3'].activate();
            var resultSpan = document.getElementById('enter-err-result');
            var infoDiv = document.getElementById('user-info');
            var acceptButton = document.getElementById('enter-cont-button');
            var acceptLabel = document.getElementById('enter-cont-label');
            if (acceptMark) {
                acceptMark.show();
                acceptMark.activate();
            }
            if (error == '') {
                this._showCardBack();          
                acceptMark.makeAccept();
                resultSpan.className = '';
                resultSpan.innerHTML = 'Проверка аккаунта пройдена';
                acceptButton.className = 'hidden';
                acceptButton.disabled = true;
                acceptLabel.innerHTML = '';
                this._currentUserId = userInfo['userId'];
                this._currentUserCard = userInfo['card'];
                this._currentUserInfo = userInfo;
                userInfo['userId'] = 
                    (userInfo['userId'] < this.DIRTY_OFFSET) ? 
                     userInfo['userId'] : 
                    (userInfo['userId'] - this.DIRTY_OFFSET);   
                this.showUserInfo(infoDiv, userInfo);
                //infoSpan.innerHTML = userInfo;               
                this.showCard(this._currentUserCard);                
            } else {
                acceptMark.makeDeny();
                resultSpan.className = 'error';
                resultSpan.innerHTML = 'Ошибка: ' + error; 
                acceptButton.disabled = false;
                acceptLabel.innerHTML = 'Повторить вход: ';
            }            
        },
        
    showActPerformResult:
        function(groupInfo, error) {
            var resultMark = this._marks ? this._marks["group-act-result"] : null;
            if (resultMark) resultMark.setSmall(true);
            this._actions['confirm-act-2'].deactivate();
            this._actions['confirm-act-2'].hide();
            this._actions['confirm-act-3'].show();
            this._actions['confirm-act-3'].activate();
            var resultSpan = document.getElementById('confirm-err-result');
            var infoDiv = document.getElementById('group-info');
            var returnButton = document.getElementById('return-to-gname');
            returnButton.disabled = false;
            //var returnLabel = document.getElementById('return-gname-label');
            if (resultMark) {
                resultMark.show();
                resultMark.activate();
            }
            if (error == '') {          
                resultMark.makeAccept();
                resultSpan.className = '';
                resultSpan.innerHTML = 'Действие выполнено удачно';
                //returnButton.className = 'hidden';
                //returnButton.disabled = true;
                //returnLabel.innerHTML = '';
                this.showGroupInfo(infoDiv, groupInfo);
                this._load                              
            } else {
                resultMark.makeDeny();
                infoDiv.innerHTML = '';
                resultSpan.className = 'error';
                this._groupsInfo["screquired"] = this._groupsInfo.groupscnt * 0.7;
                this._groupsInfo["newgnum"] = this._groupsInfo.groupscnt + 1;                
                resultSpan.innerHTML = 'Ошибка: ' + projectionalReplace(error, this._groupsInfo); 
                //returnButton.disabled = false;
                //returnLabel.innerHTML = 'Повторить вход: ';
            }
        },
        
    showCard:
        function(cardData) {
            this._actions['check-act'].deactivate();
            this.switchStep('enter', 'card', true);            
            this._actions['card-act'].activate();                          
            var loginMark = this._marks ? this._marks["number-accepted"] : null; 
            loginMark.makeInactive(); 
            this._actions['approve-act-1'].prepare();
            this._showLoadingIcon(); showInfo('RC1727: Загружаем карту');
            var cardPath = this.CARDS_IMGS_PATH + cardData.file;            
            this._cardImageElm.src = cardPath;
            /* if (this._cardCodeElm) this._cardCodeElm.value = 
                        this._generateCardProfileCode(cardData);
               if (this._cardSCodeElm) this._cardSCodeElm.value = 
                        this._generateCardProfileCode(cardData, true); */
            if (this._cardCodeElm) this._cardCodeElm.innerHTML = 
                        htmlentities(this._generateCardProfileCode(cardData));
            if (this._cardSCodeElm) this._cardSCodeElm.innerHTML = 
                        htmlentities(this._generateCardProfileCode(cardData, true));             
            this.switchStep('card', 'approve', true);
            /* this._cardCodeElm.readOnly = true;
               this._cardSCodeElm.readOnly = true;
               this._cardCodeElm.wrap = false;
               this._cardSCodeElm.wrap = false; */           
            this._actions['approve-act-1'].activate();            
            //this._actions['score-act'].prepare();
            this._actions['score-act'].deactivate();         
            this._hideLoadingIcon();
        },
        
    showUserInfo:
        function(userInfoElm, userInfo) {
            var infoLabels = {
                'userId':   'id',
                'userName': 'username',
                'karma':    'карма',
                'voice':    'голос',
                'rating':   'рейтинг'  
            };
            for(infoField in infoLabels) {
                var infoLabel = document.createElement('strong');
                infoLabel.appendChild(document.createTextNode(infoLabels[infoField] + ': '));
                userInfoElm.appendChild(infoLabel);
                userInfoElm.appendChild(document.createTextNode(userInfo[infoField]));
                userInfoElm.appendChild(document.createElement('br'));
            }            
        },
        
    showGroupInfo:
        function(groupInfoElm, groupInfo) {
            groupInfoElm.innerHTML = '';
            var infoLabels = {
                'name':   'id',
                'score':  'сумма',
                'ucount': 'пользователей'
            };
            for(infoField in infoLabels) {                
                var infoLabel = document.createElement('strong');
                infoLabel.appendChild(document.createTextNode(infoLabels[infoField] + ': '));
                groupInfoElm.appendChild(infoLabel);
                groupInfoElm.appendChild(document.createTextNode(groupInfo[infoField]));
                groupInfoElm.appendChild(document.createElement('br'));
            }
        },
        
    _showInfoBox:
        function(objData) {
            if (this._infoBlockMode && objData) {
            	// TODO: this._statsManager.updateInfoCard();
                var boxData = null;
                var infoBoxClass = '';
                if ((this._infoBlockMode == 'user') || (this._infoBlockMode == 'username')) {
                    boxData = this._statsManager.packUserInfo(objData);
                    boxData.moreFields['pos'] = objData.pos;
                    infoBoxClass = this._statsManager.getUserInfoClass(objData);
                    if (this._infoImg) this._infoImg.src = './img/type-user.png';
                }
                if (this._infoBlockMode == 'group') {
                	boxData = this._statsManager.packGroupInfo(objData);
                	boxData.moreFields['pos'] = objData.pos;
                	infoBoxClass = this._statsManager.getGroupInfoClass(objData);
                	if (this._infoImg) this._infoImg.src = './img/type-group.png';
                }
                var infoCardElm = this._statsManager.getInfoCardElm();                
                if (boxData && infoCardElm) {
                	infoCardElm.innerHTML = '';
                	infoCardElm.className = infoBoxClass;
                	this._statsManager.attachDataFields(infoCardElm, boxData);
                }                 
            }
        },
        
    retryEnter:
        function() {
            this._actions['enter-act-3'].deactivate();
            this._actions['enter-act-3'].hide();
            this._actions['enter-act-1'].show();
            this._actions['enter-act-1'].deactivate();
            this._actions['number-act'].activate();
            this._actions['check-act'].activate();
            
            var loginMark = this._marks ? this._marks["number-accepted"] : null;
            if (loginMark) {
                loginMark.show();
                loginMark.activate();
            }
            
            this.switchStep('number', 'check', true);
            this.switchStep('check', 'enter', false);
            
            this.checkUser();
        },
        
    retryCheck:
        function() {
            this._actions['approve-act-1'].activate();
            this._actions['approve-act-2'].deactivate();                                     
            this._actions['approve-act-2'].hide();
            this._actions['approve-act-1'].show();
        },                 
        
    initializeLoginStage:
        function() {
            var loginMark = this._marks ? this._marks["number-accepted"] : null;
            if (loginMark) {
                loginMark.show();
                loginMark.activate();
            }
            
            this._actions['number-act'].activate();
            this._actions['check-act'].activate();
            this._actions['enter-act-1'].deactivate();
            
            this.switchStep('number', 'check', true);            
        },
        
    activateGroupsActions:
        function() {
            var cardAccMark = this._marks ? this._marks['card-accepted'] : null;
            var actionMark = this._marks ? this._marks['confirm-action'] : null;
            // if (cardAccMark) cardAccMark.makeInactive();
            if (actionMark) {
                actionMark.show();            
                actionMark.activate();                
                actionMark.makeUnknown();
            }
            //this._actions['approve-act-2'].deactivate();
            this._actions['score-act'].activate();
            this._actions['group-act'].activate();
            this.switchStep('score', 'group', true);
            var actionMark = this._marks ? this._marks['confirm-action'] : null;
            
            this.allowToActGroup(true);
            this.checkGroup();
            this._loadStats(this._currentUserId);
            this._enableInfoReceiverForm();
            this._loadInInfoBox('user', this._currentUserId);
        }, 
        
    reEnterGname:
        function() {
            this._groupAction = null;
            this.switchStep('operation', 'confirm', false);            
            this._marks['card-accepted'].makeAccept();
            this._actions['approve-act-2'].activate();            
            this._actions['score-act'].activate();
            this._actions['operation-act'].activate();
            this._actions['confirm-act-3'].deactivate();
            this._actions['confirm-act-2'].deactivate();
            this._actions['confirm-act-1'].activate();
            this._actions['confirm-act-3'].hide();                        
            this._actions['confirm-act-2'].hide();            
            this._actions['confirm-act-1'].show(); 
            this._actions['group-act'].activate();
            this.checkGroup();           
        },
        
    updateGroups:
        function() {
            this._actions['confirm-act-3'].deactivate();
            this._actions['confirm-act-3'].hide();
            this._actions['confirm-act-1'].activate();
            this._actions['confirm-act-1'].show();
            this._groupAction = null;
            this._loadGroupsInfo();            
        },                  
        
    /* ajax loaders */
        
    tryLogin:
        function() {
            var userId = this._lnumberField ? this._lnumberField.value : null;            
            if (userId) {                
                this._showLoadingIcon(); showInfo('RC1724: Запускаем процесс логина');
                var gotUserData = createMethodReference(this, "onLoginDataReceived"); 
                makeRequest('./r/l', 'userId=' + urlEncode(userId), gotUserData);
            } else {
                showInfo('Так-то, попытка логина не удалась!');
            }
        },
        
    tryEnter:
        function() {
            var actElms = this._actions['enter-act-2'].getControlledElms();
            if (actElms) {
                if (actElms['password'].value != '') {
                    this._showLoadingIcon(); showInfo('RC1725: Запускаем процесс входа');
                    var gotEnterResult = createMethodReference(this, "onEnterResultReceived"); 
                    makeRequest('./r/e', 
                        'pwd='     + urlEncode(actElms['password'].value) + '&' +
                        're-pwd='  + urlEncode(actElms['re-password'].value) + '&' +
                        'email='   + urlEncode(actElms['email'].value) + '&' +
                        'captcha=' + urlEncode(actElms['user-captcha'].value) + '&' +
                        'lcode='   + urlEncode(actElms['logincode'].value), 
                        gotEnterResult, true); // POST
                } else showInfo('Какбе необходимо ввести хотя бы пароль');
            }
        },
        
    tryRegister:
        function() {
            this._showLoadingIcon(); showInfo('RC1726: Проверяем страницу профиля');
            var gotR10nResult = createMethodReference(this, "onR10nResultReceived");
            makeRequest('./r/r', null, gotR10nResult);
        },
        
    _loadGroupsInfo:
        function() {
            this._showLoadingIcon(); showInfo('RC1727: Загружаем данные групп');
            var gotGroupsInfoResult = createMethodReference(this, "onGroupsInfoReceived");
            makeRequest('./r/gi', 'uid=' + this._currentUserId, gotGroupsInfoResult);
        },
        
    _loadJustGroupsInfo:
        function() {
            this._showLoadingIcon(); showInfo('RC1727: Загружаем данные групп');
            var gotGroupsInfoResult = createMethodReference(this, "updateGroupsInfo");
            makeRequest('./r/gi', 'uid=' + this._currentUserId, gotGroupsInfoResult);
        },         
        
    tryGroupAction:
        function() {
            this._showLoadingIcon(); showInfo('RC1728: Получение утверждения на действие над группой');
            var gotActConfirmResult = createMethodReference(this, "onGroupActConfirmed");
            makeRequest('./r/ga', 
                'uid=' + this._currentUserId +
                '&act=' + (this._actionTypeField ? urlEncode(this._actionTypeField.value) : '') +
                '&gid=' + (this._gnameField ? urlEncode(this._gnameField.value) : '')
                , gotActConfirmResult, true); // POST
        }, 
                
    useGroupCode:
        function() {
            this._showLoadingIcon(); showInfo('RC1729: Обрабатываем код');
            var gotGroupActionResult = createMethodReference(this, "onGroupActPerformed");
            makeRequest('./r/gp', 
                'uid=' + this._currentUserId + 
                '&gid=' + this._groupAction.groupId +
                '&act=' + this._groupAction.acode +
                '&code=' + (this._gcodeField ? urlEncode(this._gcodeField.value) : '')
                , gotGroupActionResult, true);
        }, 
        
    tryToGetInfo:
        function(mode, value) {
            var mode = mode || this._getRadiosValue(this._infoRadios); 
            var value = value || (this._infoValueField ? this._infoValueField.value : null);
            if (mode && value) {
                this._infoBlockMode = mode; 
                this._showLoadingIcon(); showInfo('RC1780: Загрузка запрошенной информации');
                var gotInformationBlock = createMethodReference(this, "onInfoBlockReceived");
                makeRequest('./r/li', 'mode=' + mode + '&value=' + value, gotInformationBlock, true);
            } else if (value != '') alert('Не выходит получить такую информацию');
        },                       
        
    _loadStats:
        function(curentUser) {
            this._statsManager.setCurrentUser(curentUser);
            this._statsManager.setUserClickHandler(createMethodReference(this, "_onStatsUserClick"));
            this._statsManager.setGroupClickHandler(createMethodReference(this, "_onStatsGroupClick"));
            this._statsManager.setGroupJoinClickHandler(createMethodReference(this, "_onStatsGroupJoin"));
            this._statsManager.setGroupLeaveClickHandler(createMethodReference(this, "_onStatsGroupLeave"));
            this._statsManager.setStatsUpdatedHandler(createMethodReference(this, "_onStatsUpdated"));
            this._statsManager.loadUserStats('user-groups');
            this._statsManager.loadGroupsStats('all-groups');
            this._statsManager.loadUsersStats('all-users');
            this._actions['tables'].activate();
            // this._actions['tables'].show();         
        },                                     
        
    /* ajax receivers */    
        
    onLoginDataReceived:
        function(request, response) {
            this._hideLoadingIcon();          
            if (this._checkLoginResponse(response)) {
                //this._showBlankCard();
                //this._actions['card-act'].prepare();                            
                var decodedData = JSON.parse(response); 
                var loginCode = decodedData.srvlogged ? '' : decodedData.logincode;
                this.loginOrRegisterUser(loginCode, (decodedData.userid.slice(0,1) != '?'));
            };
        },
        
    onEnterResultReceived:
        function(request, response) {
            this._hideLoadingIcon();            
            this.showEnterResult(JSON.parse(response), this._checkEnterResponse(response));
        },
        
    onR10nResultReceived:
        function(request, response) {
            this._hideLoadingIcon();
            var error = '';
            if (response == -1) error = 'Страница пользователя не нашлась. Не ждите, ведутся работы.';
            if (response == -2) error = 'Прошло более 20 минут с момента регистрации, перезайдите.';
            // if (!/^\d+$/.test(response)) error = 'Получен некорретный ответ от сервера';            
            if (response == false) error = 'Код не найден в профиле, убедитесь в корректности ваших действий.';
            var resultSpan = document.getElementById('approve-err-result');
            var retryButton = document.getElementById('recheck-profile-button');
            var retryEnterButton = document.getElementById('enter-cont-button');
            this._marks['account-accepted'].makeInactive();
            retryEnterButton.style.display = 'none';
            var cardAcceptMark = this._marks ? this._marks['card-accepted'] : null;
            if (cardAcceptMark) {
                cardAcceptMark.show();
                cardAcceptMark.activate();
            }
            this._marks['card-accepted'].activate();             
            this._actions['enter-act-3'].deactivate();
            this._actions['approve-act-2'].prepare();
            if (error == '') {
                resultSpan.className = '';
                resultSpan.innerHTML = 'Код был успешно найден в профиле';
                this._actions['card-act'].deactivate();                
                if (cardAcceptMark) cardAcceptMark.makeAccept();
                retryButton.disabled = true;
                retryButton.style.display = 'none';                             
                this._actions['approve-act-2'].activate();                         
                this._actions['approve-act-1'].hide();
                this._actions['approve-act-2'].show();                
                if (this._scoreElm) this._scoreElm.innerHTML = response;
                this.switchStep('approve', 'score', true);
                this._loadGroupsInfo();               
            } else {
                showInfo(error);
                resultSpan.className = 'error';
                resultSpan.innerHTML = 'Ошибка: ' + error;
                this._actions['score-act'].deactivate();                 
                this._actions['card-act'].activate();
                if (cardAcceptMark) cardAcceptMark.makeDeny(); 
                retryButton.disabled = false;
                retryButton.style.display = '';                 
                this._actions['approve-act-2'].activate();                         
                this._actions['approve-act-1'].hide();
                this._actions['approve-act-2'].show();
            }            
        }, 
        
    onGroupsInfoReceived:
        function(request, response) {
            this._hideLoadingIcon();
            this._groupsInfo = JSON.parse(response);
            this.activateGroupsActions();         
        },
        
    onGroupActConfirmed:
        function(request, response) {
            this._hideLoadingIcon();
            if (this._isCorrectResponse(response)) {
                if ((parseInt(response[0]) == 0) || (response[2] == 'e')) {
                    showInfo('Попытка совершаемого действия не соответствует правилам!');
                    alert('Попытка совершаемого действия не соответствует правилам: Покидать группы сегодня не позволено, или номер группы превышает существующее количество, или же вы (уже | ещё не) состоите в группе!');
                    return;
                } 
                this._groupAction = ''; // to block modification by groups table click
                var emptyCodeLabel = document.getElementById('empty-code-label');
                var groupCodeLabel = document.getElementById('group-code-label');
                var lettersCodeLabel = document.getElementById('letters-code-label');
                var yarrButton = document.getElementById('code-entered');
                var returnButton = document.getElementById('reenter-gname');
                var actionAllowed = (parseInt(response[0]) == 1);
                var groupProtected = (parseInt(response[1]) == 1); 
                this._actions['group-act'].deactivate();
                this._marks['card-accepted'].makeInactive();
                this._actions['approve-act-2'].deactivate();
                this._actions['score-act'].deactivate();
                this._actions['confirm-act-2'].activate();                        
                this._actions['confirm-act-1'].hide();
                this._actions['confirm-act-3'].hide();
                if (emptyCodeLabel) emptyCodeLabel.style.display = ((response[2] == 'c') ? 'block' : 'none');
                // if (groupCodeLabel && this._gcodeField && lettersCodeLabel && yarrButton && returnButton) {
                if (groupProtected || (response[2] == 'c')) {                	
                    groupCodeLabel.style.display = 'block';
                    lettersCodeLabel.style.display = 'block';
                    this._gcodeField.style.display = 'inline';
                    yarrButton.value = 'YARR! ->';
                    yarrButton.title = 'Save code';
                    // yarrButton.style.border = '1px solid #000';
                    // returnButton.style.border = '1px solid #000';
                } else {
                    groupCodeLabel.style.display = 'none';
                    lettersCodeLabel.style.display = 'none';
                    this._gcodeField.style.display = 'none';
                    yarrButton.value = 'Подтвердить ->';
                    yarrButton.title = 'Approve';
              	    // yarrButton.style.border = '1px solid #090';
                    // returnButton.style.border = '1px solid #900';
                }
                this._actions['confirm-act-2'].show();
                var groupIdEntered = (this._gnameField.value != '') ? parseInt(this._gnameField.value) : ''; 
                this._groupAction = {
                    groupId: groupIdEntered,
                    allowed: actionAllowed,
                    gprotected: groupProtected,
                    acode: response[2]
                }
                this._loadInInfoBox('group', groupIdEntered);
            } else {
                this._groupAction = null;
                showError('Данные, сформированные в запросе некорретны или затерялся текущий пользователь');
                alert('Данные, сформированные в запросе некорретны или затерялся текущий пользователь затерялся');                
            };
        }, 
        
    onGroupActPerformed: 
        function(request, response) {     
            this._hideLoadingIcon(); 
            this.showActPerformResult(JSON.parse(response), this._checkActPerformedResponse(response));            
        },
        
    onInfoBlockReceived:
        function(request, response) {     
            this._hideLoadingIcon(); 
            if (response != ':(') {
                this._showInfoBox(JSON.parse(response));
                //alert(response);
            } else {
                alert('Таковые данные не найдены');
            }    
        }, 
        
    updateGroupsInfo:
        function(request, response) {
            this._hideLoadingIcon();
            this._groupsInfo = JSON.parse(response);         
        },        
        
    /* tables events handlers */ 
        
    _onStatsUserClick:
        function(userData) {
            //console.log(userData.uname);
            this._loadInInfoBox('user', userData.uid);
            return false;
        },
                     
    _onStatsGroupClick:
        function(groupData) {
            if ((this._groupAction == null) && this._gnameField) this._gnameField.value = groupData.name;
            // TODO: if (this._gnameField && this._gnameField.disabled != false) this._gnameField.value = groupData.name;
            this.checkGroup();
            this._loadInInfoBox('group', groupData.name);
            //console.log(groupData.name);
            return false;
        },
        
    _onStatsGroupJoin:
        function(groupData) {
            //console.log('joining', groupData.name);
            return false;
        },
        
    _onStatsGroupLeave:
        function(groupData) {
            //console.log('leaving', groupData.name);
            return false;
        },
        
    _onStatsUpdated:
        function() {
        	this._loadJustGroupsInfo();
        }

});
