// Copyright (c) 2011 Denis Nedelyaev

(function(cb) {
    var $window = $(window), $document = $(document);
    var dialog = $('<div/>').addClass('dialog overlay');
    var form = $('<form/>').attr('action', '').appendTo(dialog);

    var input = $('<input/>').attr('id', 'prompt-input');
    var label = $('<label/>').attr('for', input.attr('id'));
    $('<div/>').addClass('input').append(label, input).appendTo(form);
    var error = $('<div/>').addClass('error').appendTo(form);

    var okButton = $('<input/>').attr('type', 'submit').val('OK');
    var cancelButton = $('<input/>').attr('type', 'button').val('Отмена').click(function() {
        dialog.detach();
        var tempcb = cb;
        cb = null;
        tempcb && tempcb(null);
        return false;
    });
    $('<div/>').addClass('buttons').append(okButton, cancelButton).appendTo(form);

    form.submit(function() {
        dialog.detach();
        var tempcb = cb;
        cb = null;
        tempcb && tempcb(input.val());
        return false;
    });

    $document.keyup(function(e) {
        switch (e.which) {
        case 13:
            form.submit();
            return false;
        case 27:
            cancelButton.click();
            return false;
        }
    });

    $.prompt = function(coords, text, value, callback, errorText) {
        label.text(text + ':');
        input.val(value || '');
        errorText ? error.text(errorText).show() : error.hide();
        cb = callback;

        dialog.appendTo(document.body);
        form.offset({ top: coords.top - form.height() / 2, left: coords.left - form.width() / 2 });
        input.focus();
    };
})();

(function(popups, cur) {
    $(document).on('click.close-popup', function() {
        $(cur).stop(true).detach();
    });

    $.fn.ajaxPopup = function(url, popupClass) {
        var key = url + ' ' + popupClass;
        function enter() {
            popups[key].stop(true)
        }
        function leave() {
            popups[key].stop(true).delay('slow').queue(function() {
                popups[key].detach().dequeue(); cur = undefined
            })
        }
        this.each(function() {
            $(this).hover(function(e) {
                key in popups || (popups[key] = $('<div/>').addClass(popupClass).css('position', 'absolute').hover(enter, leave).text('Загрузка информации...')).load(url);
                enter();
                cur !== this && popups[key].delay('slow').queue(function() {
                    $(cur = this).css('left', (e.pageX + 8) + 'px').css('top', (e.pageY + 8) + 'px').appendTo(document.body).dequeue()
                });
            }, leave)
        })
    }
})({});

$.initAjaxLinks = function(context) {
    $('a.userinfo', context).each(function() {
        var href = $(this).attr('href'), url = href.replace(/^users\.php\?m=details&id=(\d+)$/, 'popup.php?type=user&id=$1');
        url !== href && $(this).ajaxPopup(url, 'popup userinfo');
    });
    $('a.forumtopic', context).each(function() {
        var href = $(this).attr('href'), url = href.replace(/^forums\.php\?m=posts&q=(\d+)/, 'popup.php?type=forumtopic&id=$1');
        url !== href && $(this).ajaxPopup(url, 'popup forumtopic');
    });
    $('a.forumpost', context).each(function() {
        var href = $(this).attr('href'), url = href.replace(/^forums\.php\?m=posts&p=(\d+)#\1$/, 'popup.php?type=forumpost&id=$1');
        url !== href && $(this).ajaxPopup(url, 'popup forumpost');
    });
};

(function($, selector) {
    var methods = {
        getSelectionRange: function() {
            var val = this.value, start, end;

            start = end = val.length; // fallback

            if (this != document.activeElement && 'onbeforedeactivate' in document) { // IE, text field is not active
                var range = $.data(this, 'textFieldEdit');
                if (range) {
                    start = range.start;
                    end   = range.end;
                }
            }
            else if ('selectionStart' in this) {
                start = this.selectionStart;
                end   = this.selectionEnd;
            }
            else if (this.createTextRange) { // IE < 9, text field is active
                var selRange = document.selection.createRange();
                var textRange = this.createTextRange();

                if (!textRange.inRange(selRange)) {
                    textRange = selRange.duplicate();
                    textRange.moveToElementText(this);
                }

                start = 0;
                while (textRange.compareEndPoints('StartToStart', selRange) < 0) {
                    // TextRange move treats \n\r as one char
                    start += val.substr(start, 2) == '\r\n' ? 2 : 1;
                    textRange.moveStart('character');
                }

                end = start;
                while (textRange.compareEndPoints('StartToEnd', selRange) < 0) {
                    // TextRange move treats \n\r as one char
                    end += val.substr(end, 2) == '\r\n' ? 2 : 1;
                    textRange.moveStart('character');
                }
            }

            return { start: start, end: end };
        },

        setSelectionRange: function(start, end) {
            if (this != document.activeElement && 'onactivate' in document) { // IE, text field is not active
                $.data(this, 'textFieldEdit', { start: start, end: end });
            }
            else if ('selectionStart' in this) {
                this.selectionStart = start;
                this.selectionEnd = end;
            }
            else if (this.createTextRange) { // IE < 9, text field is active
                var text = this.createTextRange();
                // TextRange move treats \n\r as one char
                text.move('character', this.value.slice(0, start).replace(/\r\n/g, '\n').length);
                text.moveEnd('character', this.value.slice(start, end).replace(/\r\n/g, '\n').length);
                text.select();
            }
        },

        getSelection: function() {
            var range = methods.getSelectionRange.call(this);
            return this.value.slice(range.start, range.end);
        },

        editSelection: function(replace, prepend, append) {
            var scrollTop  = this.scrollTop;
            var scrollLeft = this.scrollLeft;

            var range = methods.getSelectionRange.call(this);
            var start = range.start;
            var end   = range.end;

            var left   = this.value.slice(0, start) + (prepend || '');
            var middle = typeof replace == 'string' ? replace : this.value.slice(start, end);
            var right  = (append || '') + this.value.slice(end);

            // Browser may normazile (textarea) or remove (input) newlines at value assign,
            // so we base calculation of the bounds on factual results of value assignment.
            var clone = this.cloneNode(false);
            clone.value  = left;
            start = clone.value.length;
            clone.value += middle;
            end   = clone.value.length;
            clone.value += right;
            this.value = clone.value; // here edit is one operation, so with one undo we can cancel whole edit (in some browsers with)

            methods.setSelectionRange.call(this, start, end);

            this.scrollTop  = scrollTop;
            this.scrollLeft = scrollLeft;
        }
    };

    $.fn.textFieldEdit = function(method) {
        var args = Array.prototype.slice.call(arguments, 1), res;

        this.filter(selector).each(function() {
            res = methods[method].apply(this, args);
            if (typeof res != 'undefined') {
                return false;
            }
        });

        return typeof res == 'undefined' ? this : res;
    };

    // Help IE remember selection range after focus change
    $(document).on({
        beforedeactivate: function() {
            $.data(this, 'textFieldEdit', methods.getSelectionRange.call(this));
        },
        activate: function() {
            var range = $.data(this, 'textFieldEdit');
            if (range) {
                methods.setSelectionRange.call(this, range.start, range.end);
            }
        }
    }, selector);
})(jQuery, 'textarea, input[type=text]');

(function($) {
    $.fn.textFieldMarkup = function(markup, focus) {
        markup = $.extend(true, {}, markup);

        if (!markup.hasOwnProperty('params')) {
            markup.params = [];
        }
        else if ($.isPlainObject(markup.params)) {
            var params = [];
            for (var name in markup.params) {
                var param = markup.params[name];

                if (!$.isPlainObject(param)) {
                    param = { value: param };
                }

                param.name = name;
                params.push(param);
            }

            markup.params = params;
        }

        this.filter('textarea, input[type=text]').each(function() {
            var textarea = this, $textarea = $(this), cancel, paramValues = {};

            paramValues.selection = $textarea.textFieldEdit('getSelection');

            var coords = $textarea.offset();
            coords.top += $textarea.height() / 2;
            coords.left += $textarea.width() / 2;

            collectParams(0);

            function collectParams(index) {
                if (index < markup.params.length) {
                    var param = markup.params[index];

                    if (param.hasOwnProperty('value')) {
                        paramValues[param.name] = param.value;

                        collectParams(index + 1);
                    }
                    else {
                        var text = param.text;
                        var defaultValue = param.defaultValue || '';

                        paramPrompt();
                    }
                }
                else {
                    doMarkup();
                }

                function paramPrompt(errorText) {
                    $.prompt(coords, param.label, defaultValue, function(value) {
                        if (value !== null) {
                            var valid = true;

                            if (!param.hasOwnProperty('validation')) {
                            }
                            else if (param.validation instanceof RegExp) {
                                valid = param.validation.test(value);
                            }
                            else if ($.isFunction(param.validation)) {
                                valid = param.validation.call(textarea, value, paramValues, markup);
                            }

                            if (valid) {
                                paramValues[param.name] = value;

                                collectParams(index + 1);
                            }
                            else {
                                paramPrompt(param.hasOwnProperty('errorText') ? param.errorText : false);
                            }
                        }
                        else {
                            // TODO: call oncancel callback
                        }
                    }, errorText);
                }
            }

            function doMarkup() {
                var prependText     = prepare(markup.openWith);
                var appendText      = prepare(markup.closeWith);
                var replaceText     = prepare(markup.replaceWith);
                var placeholderText = prepare(markup.placeHolder);

                if (cancel) {
                    // TODO: call oncancel callback
                    return;
                }

                if (typeof replaceText != 'string' && !paramValues.selection) {
                    replaceText = placeholderText;
                }

                $textarea.textFieldEdit('editSelection', replaceText, prependText, appendText);

                if (focus) {
                    $textarea.focus();
                }

                // TODO: call onsuccess callback
            }

            function prepare(text) {
                if (cancel) {
                    return false;
                }

                if ($.isFunction(text)) {
                    text = text(paramValues, markup);
                }

                if (text === false) {
                    cancel = true;
                }

                return text && text.replace(/\{\{|\{(\w+)}/g, function(s, name) {
                    return s == '{{' ? '{' : paramValues.hasOwnProperty(name) ? paramValues[name] : s;
                });
            }
        });

        return this;
    };
})(jQuery);

(function($) {
	$.fn.markupEditor = function(buttons) {
        return this.filter('textarea').each(function() {
			var textarea = $(this);

            textarea.wrap($('<div/>').addClass('markup-editor'));
            buildMenu(buttons).addClass('header').insertBefore(textarea);

            // recursively build menus
            function buildMenu(buttons) {
                var ul = $('<ul/>');

                $.each(buttons, function(index, button) {
                    var li = $('<li/>').appendTo(ul);

                    if ($.isPlainObject(button)) {
                        if (button.hasOwnProperty('className')) {
                            li.addClass(button.className);
                        }

                        var a = $('<a/>').appendTo(li);

                        var name = button.name || '';

                        if (button.hasOwnProperty('icon')) {
                            $('<img/>').attr('src', button.icon).attr('alt', name).attr('title', name).appendTo(a);
                        }
                        else {
                            a.text(name);
                        }

                        a.click(function() {
                            if (button.hasOwnProperty('markup')) {
                                textarea.textFieldMarkup(button.markup, true);
                            }
                            return false;
                        });

                        if (button.hasOwnProperty('submenu')) {
                            var submenu = buildMenu(button.submenu).hide().appendTo(li);

                            a.addClass('submenu');

                            li.hover(function() { submenu.show() }, function() { submenu.hide() });
                        }
                    }
                    else {
                        li.addClass('separator');
                    }
                });

                return ul;
            }
		});
	};

	$.fn.removeMarkupEditor = function() {
		return this.filter('.markup-editor textarea').each(function() {
            $(this).closest('.markup-editor').replaceWith(this);
        });
	};
})(jQuery);

$.fn.editor = function() {
    var token = $('meta[name=token]').attr('content'), buttons = [
        {name:'Жирный', icon:'images/icons/font_bold.png', markup: { openWith:'[b]', closeWith:'[/b]'}},
        {name:'Курсив', icon:'images/icons/font_italic.png', markup: { openWith:'[i]', closeWith:'[/i]'}},
        {name:'Подчеркнутый', icon:'images/icons/text_underline.png', markup: { openWith:'[u]', closeWith:'[/u]'}},
        {name:'Зачеркнутый', icon:'images/icons/text_strike.png', markup: { openWith:'[s]', closeWith:'[/s]'}},
        {name:'Подстрочный', icon:'images/icons/text_sub.png', markup: { openWith:'[sub]', closeWith:'[/sub]'}},
        {name:'Надстрочный', icon:'images/icons/text_sup.png', markup: { openWith:'[sup]', closeWith:'[/sup]'}},
        {name:'Цвет', className:'color', icon:'images/icons/color.png', submenu: [
            {name:'Черный', className:'black', markup: { openWith:'[color=black]', closeWith:'[/color]' }},
            {name:'Серый', className:'gray', markup: { openWith:'[color=gray]', closeWith:'[/color]' }},
            {name:'Серебряный', className:'silver', markup: { openWith:'[color=silver]', closeWith:'[/color]' }},
            {name:'Белый', className:'white', markup: { openWith:'[color=white]', closeWith:'[/color]' }},
            {name:'Тёмно-бордовый', className:'maroon', markup: { openWith:'[color=maroon]', closeWith:'[/color]' }},
            {name:'Красный', className:'red', markup: { openWith:'[color=red]', closeWith:'[/color]' }},
            {name:'Оранжевый', className:'orange', markup: { openWith:'[color=orange]', closeWith:'[/color]' }},
            {name:'Жёлтый', className:'yellow', markup: { openWith:'[color=yellow]', closeWith:'[/color]' }},
            {name:'Оливковый', className:'olive', markup: { openWith:'[color=olive]', closeWith:'[/color]' }},
            {name:'Зелёный', className:'green', markup: { openWith:'[color=green]', closeWith:'[/color]' }},
            {name:'Лайм', className:'lime', markup: { openWith:'[color=lime]', closeWith:'[/color]' }},
            {name:'Морская волна', className:'aqua', markup: { openWith:'[color=aqua]', closeWith:'[/color]' }},
            {name:'Зеленовато-голубой', className:'teal', markup: { openWith:'[color=teal]', closeWith:'[/color]' }},
            {name:'Синий', className:'blue', markup: { openWith:'[color=blue]', closeWith:'[/color]' }},
            {name:'Тёмно-синий', className:'navy', markup: { openWith:'[color=navy]', closeWith:'[/color]' }},
            {name:'Пурпурный', className:'purple', markup: { openWith:'[color=purple]', closeWith:'[/color]' }},
            {name:'Фуксия', className:'fuchsia', markup: { openWith:'[color=fuchsia]', closeWith:'[/color]' }}
        ]},
        'separator',
        {name:'Выровнить влево', icon:'images/icons/text_left.png', markup: { openWith:'[left]', closeWith:'[/left]'}},
        {name:'Выровнить по центру', icon:'images/icons/text_center.png', markup: { openWith:'[center]', closeWith:'[/center]'}},
        {name:'Выровнить вправо', icon:'images/icons/text_right.png', markup: { openWith:'[right]', closeWith:'[/right]'}},
        'separator',
        {name:'Ссылка', icon:'images/icons/link.png', markup: { params: { url: { label:'Адрес', defaultValue:'http://' } }, openWith:'[url={url}]', closeWith:'[/url]', placeHolder:'Текст Вашей ссылки...'}},
        {name:'Ссылка на тему форума', icon:'images/icons/topic_link.png', markup: { params: { topicnid: { label:'Номер темы', validation: /^[0-9]+$/, errorText: 'Номер должен состоять из цифр!' } }, openWith: '[topic={topicnid}]', closeWith: '[/topic]', placeHolder: 'Тема № {topicnid}'}},
        {name:'Ссылка на сообщение форума', icon:'images/icons/post_link.png', markup: { params: { postid: { label:'Номер сообщения', validation: /^[0-9]+$/, errorText: 'Номер должен состоять из цифр!' } }, openWith: '[post={postid}]', closeWith: '[/post]', placeHolder: 'Сообщение № {postid}'}},
        'separator',
        {name:'Изображение', icon:'images/icons/picture.png', markup: { params: { url: { label:'Адрес', defaultValue:'http://' } }, replaceWith:'{selection}[img]{url}[/img]'}},
        {name:'Смайлик', className:'emoticons', icon:'images/emoticons/smile.gif', markup: { replaceWith:'{selection}:)' }, submenu: [
            {name:'Улыбка', icon:'images/emoticons/smile.gif', className:'button-emoticon-smile', markup: { replaceWith:'{selection}:)' }},
            {name:'Печаль', icon:'images/emoticons/sad.gif', className:'button-emoticon-sad', markup: { replaceWith:'{selection}:(' }},
            {name:'Смех', icon:'images/emoticons/grin.gif', className:'button-emoticon-grin', markup: { replaceWith:'{selection}:D' }},
            {name:'Подмигнуть', icon:'images/emoticons/wink.gif', className:'button-emoticon-wink', markup: { replaceWith:'{selection};)' }},
            {name:'Язык', icon:'images/emoticons/razz.gif', className:'button-emoticon-razz', markup: { replaceWith:'{selection}:p' }},
            {name:'Да', icon:'images/emoticons/yes.gif', className:'button-emoticon-yes', markup: { replaceWith:'{selection}:yes' }},
            {name:'Нет', icon:'images/emoticons/no.gif', className:'button-emoticon-no', markup: { replaceWith:'{selection}:no' }},
            {name:'Растерянность', icon:'images/emoticons/confused.gif', className:'button-emoticon-confused', markup: { replaceWith:'{selection}:confused' }},
            {name:'Поклонение', icon:'images/emoticons/worship.gif', className:'button-emoticon-worship', markup: { replaceWith:'{selection}:worship' }},
            {name:'Любовь', icon:'images/emoticons/love.gif', className:'button-emoticon-love', markup: { replaceWith:'{selection}:love' }},
            {name:'Злой', icon:'images/emoticons/evil.gif', className:'button-emoticon-evil', markup: { replaceWith:'{selection}:evil' }},
            {name:'Чёрт!', icon:'images/emoticons/damn.gif', className:'button-emoticon-damn', markup: { replaceWith:'{selection}:damn' }},
            {name:'Насвистывание', icon:'images/emoticons/whistle.gif', className:'button-emoticon-whistle', markup: { replaceWith:'{selection}:whistle' }},
            {name:'Крутой', icon:'images/emoticons/cool.gif', className:'button-emoticon-cool', markup: { replaceWith:'{selection}:cool' }},
            {name:'Усталость', icon:'images/emoticons/tired.gif', className:'button-emoticon-tired', markup: { replaceWith:'{selection}:tired' }}
        ]},
        'separator',
        {name:'Цитата', icon:'images/icons/quote.png', markup: { params: { author: { label:'Автор' } }, openWith: function(params) { return params.author ? '[quote={author}]' : '[quote]' }, closeWith:'[/quote]', placeHolder:'Текст Вашей цитаты...'}},
        {name:'Скрыть', icon:'images/icons/spoiler.png', markup: { openWith:'[spoiler]', closeWith:'[/spoiler]'}},
        {name:'Код', icon:'images/icons/code.png', markup: { openWith:'[code]', closeWith:'[/code]'}}
    ];

    this.each(function() {
        var textarea = $(this);

        textarea.markupEditor(buttons);

        var editorTab = textarea.closest('.markup-editor');
        editorTab.parent().addClass('editor-container');

        var editorButton = $('<li/>').text('Редактирование').addClass('selected');
        var previewButton = $('<li/>').text('Предпросмотр');

        $('<ul/>').addClass('tabs').append(editorButton, previewButton).insertBefore(editorTab);

        editorTab.wrap($('<div/>').addClass('tab-container'));

        var previewTab = $('<div/>').addClass('editor-preview post-contents').hide().insertAfter(editorTab);

        editorButton.click(function() {
            previewButton.removeClass('selected');
            previewTab.hide();
            editorTab.show();
            editorButton.addClass('selected');
        });
        previewButton.click(function() {
            previewTab.load('parser.php', { data: textarea.val(), x: token }, function() { $.initAjaxLinks(previewTab) });
            previewTab.height(editorTab.height());
            editorButton.removeClass('selected');
            editorTab.hide();
            previewTab.show();
            previewButton.addClass('selected');
        });
    });
};

$(function() {
    $.initAjaxLinks();
    $('textarea.editor').editor();

    var w = window, d = document, p = d.location.protocol;

    w._gaq = w._gaq || [];
    w._gaq.push(['_setAccount', 'UA-22346958-1']);
    w._gaq.push(['_trackPageview']);

    var c = 'yandex_metrika_callbacks';
    (w[c] = w[c] || []).push(function() {
        try {
            w.yaCounter5432221 = new Ya.Metrika({id: 5432221, clickmap: true, trackLinks: true});
        }
        catch(e) {}
    });

    load(('https:' == p ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js');
    load((p == 'https:' ? 'https:' : 'http:') + '//mc.yandex.ru/metrika/watch.js');

    function load(src) {
        var e = d.createElement('script');
        e.type = 'text/javascript';
        e.async = true;
        e.src = src;
        var s = d.getElementsByTagName('script')[0];
        s.parentNode.insertBefore(e, s);
    }
});

function redirect(url) {
	location.href = url.options[url.selectedIndex].value;
}

function quote(postID, posterID, posterName, text) {
    $('#newmsg').textFieldMarkup({
        params: {
            posterID: posterID,
            posterName: posterName,
            postID: postID,
            text: text
        },
        replaceWith:'{selection}[quote=[user={posterID}]{posterName}[/user] в [post={postID}]№ {postID}[/post]]\n{text}\n[/quote]\n'
    }, true);
}

function fullQuote(postID, posterID, posterName) {
    $.get('quote.php?post=' + postID, function(text) {
        quote(postID, posterID, posterName, text);
    });
}

function cropRangeToNodeContents(range, node) {
    var contentsRange = range.cloneRange();
    contentsRange.selectNodeContents(node);
    if (range.compareBoundaryPoints(Range.END_TO_START, contentsRange) > 0) {
        range.setStart(contentsRange.endContainer, contentsRange.endOffset);
    }
    if (range.compareBoundaryPoints(Range.START_TO_END, contentsRange) < 0) {
        range.setEnd(contentsRange.startContainer, contentsRange.startOffset);
    }
    if (range.compareBoundaryPoints(Range.START_TO_START, contentsRange) < 0) {
        range.setStart(contentsRange.startContainer, contentsRange.startOffset);
    }
    if (range.compareBoundaryPoints(Range.END_TO_END, contentsRange) > 0) {
        range.setEnd(contentsRange.endContainer, contentsRange.endOffset);
    }
    contentsRange.detach();
}

function cropTextRangeToElementText(range, element) {
    var contentsRange = range.duplicate();
    contentsRange.moveToElementText(element);
    if (range.compareEndPoints('StartToEnd', contentsRange) > 0) {
        range.setEndPoint('StartToEnd', contentsRange);
    }
    if (range.compareEndPoints('EndToStart', contentsRange) < 0) {
        range.setEndPoint('EndToStart', contentsRange);
    }
    if (range.compareEndPoints('StartToStart', contentsRange) < 0) {
        range.setEndPoint('StartToStart', contentsRange);
    }
    if (range.compareEndPoints('EndToEnd', contentsRange) > 0) {
        range.setEndPoint('EndToEnd', contentsRange);
    }
}

function quoteSelection(postID, posterID, posterName) {
    var text;
    var node = $(this).closest('.forum-post').find('.post-contents').get(0);
    if (window.getSelection) {
        var sel = window.getSelection();
        if (sel.rangeCount > 0) {
            var selRange = sel.getRangeAt(0);
            cropRangeToNodeContents(selRange, node);
            text = selRange.toString();
        }
    }
    else if (document.selection) {
        var selRange = document.selection.createRange();
        cropTextRangeToElementText(selRange, node);
        text = selRange.text;
    }
    if (text) {
        quote(postID, posterID, posterName, text);
    }
    else {
        $('#newmsg').textFieldMarkup({
            params: {
                posterID: posterID,
                posterName: posterName
            },
            replaceWith:'{selection}[user={posterID}]{posterName}[/user]'
        }, true);
    }
}

