/**
 * Validate one phone row
 *
 * @param object node Parent node, needs to localize events
 * @return {}
 */
var PhoneValidator = function(node) {
    var that = this;

    that._node = node;
    that._errorStr = '';
    that._state = null;
    that._errors = {
        tooLong    : 'Длина телефона не может превышать 10 символов. Возможно, вы имели ввиду ',
        codeNeeded : 'Вы не ввели код города, пожалуйста, введите телефон с кодом города',
        strangeCode: 'Проверьте, не ошиблись ли вы в наборе кода города',
        tooShort   : 'Номер телефона слишком короткий для этого региона. Проверьте, не забыли ли вы какую-нибудь цифру?'
    }
    that._codes = [
        38341, 38343, 38373, 39145, 39161, 39151, 39131, 383, 39169, 39197, 3919,
        39145, 39132, 38514, 38557, 38453, 38456, 3822, 3823, 3842, 3843, 3812,
        3852, 3854, 3952, 3955, 3953, 3452, 495, 812, 343, 383, 391,
        3842, 3843, 38453, 38456, 3852, 3854, 38514, 38557
    ];
    // Joined codes of cities, prepared for regexp
    that._joinedCodes = that._codes.join('|');

    /**
     * Validates only one input digit
     * Prevent typing alphabetical characters and other
     */
    that._validateDigit = function(e) {
        // Only digits, brackets, spaces, hyphen and control characters allowed
        return !!String.fromCharCode(e.which).match(/[\x00-\x2C0-9 \(\)+-]/);
    }

    /**
     * Validate whole number
     */
    that._validateNumber = function(e) {
        // Replace all characters, that could be a phone number
        // this.val(this.val().replace(/[^0-9 \(\)+-]+/g, ''));

        // Trimmed phone
        var phoneString = this.val().replace(/(^\s+|\s+$)/, '');
        // Phone in number format
        var phoneNumber = phoneString.replace(/[\D]/g, '');
        var isFederal   = phoneNumber.match(/^(7|8)/);

        that._state = 'Error';

        // Impossible phone (now only for Russia +7)
        if(
            phoneNumber.length > 11 ||
            phoneNumber.length > 10 && !isFederal
        ) {
            that._suggestPhone(phoneNumber);
        } else if(phoneNumber.length < 8) {
            that._errorStr = that._errors.codeNeeded;
        } else if(phoneNumber.length < 10) {
            that._errorStr = that._errors.tooShort;
        // Number without code
        } else {
            currentCode = phoneNumber.match(
                new RegExp(
                    '^[78]?(' + that._joinedCodes + ')'
                )
            );

            if(currentCode || isFederal && phoneNumber.length == 11) {
                that._errorStr = null;
                that._state = null;
            // Phone has unknown code
            } else {
                that._state = 'Warning';
                that._errorStr = that._errors.strangeCode;
            }
        }

        that._removeErrorField();

        if(that._errorStr) {
            node.find('.phoneErrorContent')
                .removeClass('phoneErrorHidden')
                .html(that._errorStr);
            node.find('.phoneNumberValue').addClass('phoneInput' + that._state);
        }
    }

    that._suggestPhone = function(phoneNumber) {
        var formats = {
            federal: /^(7|8)(\d{3})(\d{3})(\d{2})(\d{2})/,
            city   : /(\d{3})(\d{3})(\d{2})(\d{2})/
        };
        var possible = null, currentCode = null, firstPartSize = 0;

        // Maybe its a federal with spare numbers at the end?
        if(possible = phoneNumber.match(formats.federal)) {
            that._errorStr =
                that._errors.tooLong +
                possible[1] + ' ' + possible[2] + ' ' +
                possible[3] + '-' + possible[4] + '-' + possible[5] +
                '?';
        } else {
            currentCode = phoneNumber.match(
                new RegExp('^(' + that._joinedCodes + ')')
            );
            // Or maybe it a city phone?
            if(currentCode) {
                currentCode = currentCode[1];
                firstPartSize = 6 - currentCode.length;
                possible = phoneNumber.match(
                    new RegExp(
                        currentCode +
                        '(\\d{' + firstPartSize + '})(\\d{2})(\\d{2})'
                    )
                )
                that._errorStr =
                    that._errors.tooLong +
                    '(' + currentCode + ') ' +
                    possible[1] + '-' + possible[2] + '-' + possible[3] +
                    '?';
            // Pff, strange phone...
            } else if(possible = phoneNumber.match(formats.city)) {
                that._errorStr =
                    that._errors.tooLong +
                    '(' + possible[1] + ') ' +
                    possible[2] + '-' + possible[3] + '-' + possible[4] +
                    '?';
            }
        }
    }

    /**
     * Hides error field and removes all highlights
     */
    that._removeErrorField = function() {
        node.find('.phoneErrorContent')
            .addClass('phoneErrorHidden')
            .html('');

        node.find('.phoneNumberValue')
            .removeClass('phoneInputError')
            .removeClass('phoneInputWarning');
    }

    that._eventBinder = new EventBinder(
        that._node, {
            phoneNumberValue: {
                keypress: {
                    callback: that._validateDigit
                },
                keyup: {
                    callback: that._validateNumber,
                    timeout: 700
                }
            }
        }
    );
    that._eventBinder.bind();
    that._removeErrorField();

    return {};
}

$(
    function() {
        mainBinder = new ValidatorBinder(
            {
                list    : '.phonesList',
                addLink : '.addNewPhoneLink',
                delLink : '.removePhoneLink'
            },
            "phoneRow"
        );

        mainBinder.bind();

        if(!mainBinder.cnt()) {
            mainBinder.add();
        }

        codesList = new PopupList(
            {
                list: '.listContentWrapper',
                elements: '.listContentWrapper a',
                link: '.codesLink',
                sub: '.regionListSub'
            }, {
                hidden: 'regionListHidden',
                opened: 'regionListMoreOpened',
                closed: 'regionListMoreClosed',
                cornerBL: 'cornedBL',
                cornerBR: 'cornedBR'
            }
        );
    }
);
