var siteonload = {
    'code' : function () {
        var ineditmode = false;
        
        $('#mode').toggle(function () {
            $(this).addClass('edit-mode').find('a').text('Copy mode');
            ineditmode = true;
        }, function () {
            $(this).removeClass('edit-mode').find('a').text('Read mode');
            ineditmode = false;
        });
        
        var codePermalink = $('a[rel=permalink]');
        if (codePermalink.length) {
            (function () {
                function highlightLines(range, li, clearHighlighted) {
                    var i, match = null, groups = null;
                    range += ""; // to string - just in case
                    if (!li) li = $('div.codeblock li.li1');
                    if (typeof clearHighlighted == 'undefined') clearHighlighted = true;

                    // handles the last single highlighted line being toggled off
                    if (li.data('range') == range && range.match(/^\d+$/)) {
                        // do nothing
                    } else if (clearHighlighted) {
                        li.removeClass('highlighted');
                    }

                    groups = range.split(/,/);
                    i = groups.length;

                    while (i--) {
                        match = groups[i].split(/\-/);
                        if (match.length > 1) {
                            li.slice(match[0]-1, match[1]).addClass('highlighted');
                        } else {
                            li.eq(match[0]-1).toggleClass('highlighted');
                        }
                    }

                    var href = codePermalink.attr('href'), hash = '', last = null;
                    match = [];
                    groups = [];
                    
                    li.each(function (i) {
                        if ($(this).is('.highlighted')) {
                            match.push(i+1);

                            if (last == null) {
                                last = i;
                            } else if (last != i-1) {
                                if (match.length > 1 && match[0] != match[match.length-2]) {
                                    groups.push(match[0] + '-' + match[match.length-2]);
                                } else {
                                    groups.push(match[0]);
                                }
                                match = [(i+1)];
                            }

                            last = i;
                        }
                    });
                    
                    // handles exit case
                    if (last != null) { // nothing was found
                        last++; // inc to make the last val represent a "real" line number
                        if (match.length > 1 && match[0] != last) {
                            groups.push(match[0] + '-' + last);
                        } else {
                            groups.push(last);
                        }

                        hash = '#' + groups.join(',');
                    } else {
                        hash = '';
                    }

                    codePermalink.attr('href', href.replace(/#.*$/, '') + hash);
                    
                    // only change the bottom text link
                    codePermalink.filter('#codePermalink').html(codePermalink.attr('href'));

                    li.data('range', hash.substr(1));
                }

                if (window.location.hash.match(/^#[0-9\-,]+$/)) {
                    highlightLines(window.location.hash.substr(1));
                }

                var start = 0;
                var end = 0;
                var down = false;
                var lis = $('div.codeblock li');
                
                function ordered(s, e) {
                    // required because sometime .sort() comes back in the wrong order...WTF?
                    if (s > e) {
                        return [e, s];
                    } else {
                        return [s, e];
                    }
                }
                
                lis.mousedown(function (ev) {
                    start = $(lis).index(this) + 1;
                    down = true;
                    return ineditmode;
                }).mousemove(function (ev) {
                    if (down) {
                        var new_end = lis.index(this) + 1;
                        
                        if (!ineditmode && new_end != end) {
                            end = new_end;
                            highlightLines((start == end ? start : ordered(start, end).join('-')), lis, !ev.metaKey);
                        }
                    }
                    return true;
                }).mouseup(function (ev) {
                    if (down) {
                        end = lis.index(this) + 1;
                        if (!ineditmode) {
                            if (start == end) {
                                highlightLines(start, lis, !ev.metaKey);
                            } else {
                                highlightLines(ordered(start, end).join('-'), lis, !ev.metaKey);
                            }
                        }
                        down = false;
                    }
                    return ineditmode;
                });
            })();
        }
    },

    'settings' : function () {

        var buddy_icon = $('input#buddyIcon');
        if (buddy_icon.length) {
            var bi_load = function () {
                if (this.value == this.current) {
                    return true;
                }

                var t = this, preview = $('#buddyIconPreview').html('<img src="/images/ajax-loader.gif" height="16" width="16" /> trying to load buddy icon...'), i = new Image();
                clearTimeout(this.timeout);

                if (this.value == '') {
                    preview.html('');
                } else {
                    i.src = this.value;
                    i.height = 32;
                    i.width = 32;
                    i.className = 'buddyIcon';

                    this.timeout = setTimeout(function () {
                        preview.html('Image could not be loaded.');
                        i = null;
                    }, 5000); // 5 second load timeout

                    i.onload = function () {
                        clearTimeout(t.timeout);
                        preview.empty().append(i);
                    };
                    i.onerror = function () {
                        clearTimeout(t.timeout);
                        preview.html('Image could not be loaded.');
                    };
                }
            };

            buddy_icon.keyup(function () {
                var t = this;
                clearTimeout(this.timer);
                this.timer = setTimeout(function () {
                    bi_load.call(t);
                    t.current = t.value;
                }, 250);
            }).change(bi_load);

            $('a.addBadge').click(function () {
                buddy_icon.focus().val(this.rel).keyup();
                return false;
            });
        }

        var validateUsername = $('#validateUsername');
        $('#settings #username').keyup(function () {
            var t = this;
            if (t.value != t.lastValue) {
                if (this.timer) clearTimeout(this.timer);
                validateUsername.removeClass('error').html('<img src="/images/ajax-loader.gif" height="16" width="16" /> checking availability...');
                this.timer = setTimeout(function () {
                    $.ajax({
                        url: '/settings',
                        data: 'action=check_username&username=' + t.value,
                        dataType: 'json',
                        type: 'post',
                        success: function (j) {
                            validateUsername.toggleClassIf(!j.ok, 'error').html(j.msg);
                        }
                    });
                }, 200);
                t.lastValue = t.value;
            }
        });

    },

    'new' : function () {
        // convert the title in to a url
        var newURL = $('#new #url');
        if (newURL) {
            var titleToURL = function () {
                // var v = this.value;
                var t = this;
                clearTimeout(this.timer);
                this.timer = setTimeout(function () {
                    if (t.value != t.title) // ignore hints
                        newURL.val(toURL(t.value)).removeClass('blur').keyup();
                }, 100);
            };

            $('#new #title').keyup(titleToURL).blur(titleToURL);
        }

        // show extra fields in new code snip
        $('#showAdvanced').click(function () {
            var fs = $(this).parents('fieldset');
            $('DIV.advanced', fs).slideToggle(250, function () {
                createCookie('advanced', (this.style.display == 'none' ? 0 : 1), 180, '/');
            });
            return false;
        });

        // validate url on new code snip
        var urlValid = $('#validateURL');
        $('#new #url').keyup(function () {
            var t = this;
            if (t.value != t.lastValue) {
                if (this.timer) clearTimeout(this.timer);
                urlValid.removeClass('error').html('<img src="/images/ajax-loader.gif" height="16" width="16" /> checking availability...');
                this.timer = setTimeout(function () {
                    $.ajax({
                        url: '/new',
                        data: 'action=check_url&url=' + t.value,
                        dataType: 'json',
                        type: 'post',
                        success: function (j) {
                            urlValid.toggleClassIf(!j.ok, 'error').html(j.msg);
                        }
                    });
                }, 200);
                t.lastValue = t.value;
            }
        });

        // autogrow code entry box
        var code = $('#code');
        if (code.length) {
            // tiny bug with width - if you paste a line wider than the max browser width, it
            // causes the box to grow...
            code.after('<div style="position: absolute; top: -100000px; left: -10000px; visibility:hidden;" id="_codeSizer">' + code.val() + '</div>');
            codeSizer = $('#_codeSizer');
            codeSizer.css({'width' : code.css('width')});

            var cssmin = parseInt(code.css('min-height'));
            var cssmax = parseInt(code.css('max-height'));

            // better to create a one off function than a new
            // closure function on each key press
            var resizeCodeBoxReg = [new RegExp(/[ <>]/g), new RegExp(/\n/g)];
            var resizeTimer = null;
            function resizeCodeBox(key, ignorelimit) {
                // all these events change the height of the box
                // so to optimise the times div is resized, we'll only
                // run when these events happen.
                switch (key) {
                    case 224:
                    case 17:
                    case 18: 
                    case 8: 
                    // case 9:
                    case 13: 
                    case 27: {
                        // otherwise it was some kind of control character
                        var src = code.val();
                        var lines = src.split(/\n/).length;

                        code[0].title = lines + ' line' + (lines == 1 ? '' : 's') + ' of code';

                        if (!ignorelimit && lines > 50) {
                            // delay the rendering to allow for repetitive key strokes (like delete)
                            if (resizeTimer) clearTimeout(resizeTimer);
                            resizeTimer = setTimeout(function () {
                                resizeCodeBox(key, true);
                            }, 200);
                        } else {
                            src = src.replace(resizeCodeBoxReg[0], function (m) {
                                var r = '';
                                if (m == ' ') r = '&nbsp;';
                                else if (m == '<') r = '&lt;';
                                else if (m == '>') r = '&gt;';
                                return r;
                            }).replace(resizeCodeBoxReg[1],'<br />&nbsp;');

                            if (src != codeSizer[0].innerHTML) {
                                codeSizer[0].innerHTML = src;
                                var h = codeSizer[0].offsetHeight + 16;
                                if (cssmin < h && h < cssmax) { // most likely clause
                                  code[0].style.height = h + 'px';

                                  // TODO check in IE
                                  code[0].style['overflow-y'] = 'hidden';
                                } else if (h < cssmin) { // taken from default.css
                                    code.css('height', cssmin);
                                } else if (h > cssmax) {
                                    code.css({'height': cssmax, 'overflow-y' : 'auto'});
                                } 
                            }
                        }
                    }
                }
            }

            var cancelLast = false;
            var sizer = function (ev) {
                if (cancelLast) {
                    cancelLast.call();
                    cancelLast = false;
                    return false;
                }
                
                var nl = $.browser.msie ? "\r\n" : "\n";
                                
                // filter out command keys and do nothing
                if ((ev.type == 'keypress' || ev.type == 'keydown') && ev.keyCode == 9) {
                    if ($.browser.msie) {
                        // ::sigh::
                        var r = document.selection.createRange();
                        var sr = r.duplicate();
                        sr.moveToElementText( ev.target );
                        sr.setEndPoint( 'EndToEnd', r );
                        ev.target.selectionStart = sr.text.length - r.text.length;
                        ev.target.selectionEnd = ev.target.selectionStart + r.text.length;
                    }
                    
                    var start = ev.target.selectionStart;
                    var end = ev.target.selectionEnd;
                    
                    var text = ev.target.value;
                    var range = '';
                    var shift = ev.shiftKey;
                    
                    if (ev.type == 'keypress') {
                        range = text.substr(text.lastIndexOf(nl, start), start - text.lastIndexOf(nl, start));
                    }
                    var indentcode = (/^\s*$/.test(range) && text.substr(start, nl.length) != nl && start!=text.length) || start != end;

                    if (indentcode) {
                        
                        // now check if we should indent a selection
                        if (start != end || ev.shiftKey) {
                            // selection                            
                            var start2 = text.lastIndexOf(nl, start);
                            var end2 = text.indexOf(nl, end);
                            
                            if (end2 == -1 && start2 == -1) { // we're one line long
                                start2 = 0;
                                end2 = text.length;
                            }
                            
                            if (start2 != -1) start = start2;
                            if (end2 != -1) end = end2;
                            
                            var lead = text.substr(0, start);
                            var tail = text.substr(end);
                            
                            var selection = text.substr(start, end - start);

                            if (ev.shiftKey) {
                                // strip
                                selection = selection.replace(/^([ ]{0,4}|\t)/gm, '');
                            } else {
                                selection = selection.replace(/^(.)/gm, '    $1');
                            }
                            
                            ev.target.value = lead + selection + tail;
                        } else {
                            // single point
                            ev.target.value = text.substr(0, start) + "    " + text.substr(start);
                        }
                        
                        cancelLast = function () {
                            if ($.browser.msie) {
                                var adjust = text.substr(0, start).split(/\r/).length - 1;
                                var r = code[0].createTextRange();
                                r.collapse(true);
                                
                                if (start == end) {
                                    r.moveStart('character', (start + 4 - adjust));
                                    r.moveEnd('character', 0);
                                } else {
                                    r.moveStart('character', (start - adjust + (shift ? 1 : 5))); // 5?  WTF?
                                    r.moveEnd('character', selection.length - (selection.split(/\r/).length - 1 + (shift ? 1 : 5)));
                                }
                                r.select();
                            } else {
                                if (start == end) {
                                    code[0].setSelectionRange(start + 4, start + 4);
                                } else {
                                    code[0].setSelectionRange(start, start + selection.length);
                                }
                            }
                        };
                        
                        // code.focus();
                        return false;
                    } else {
                        return true;
                    }
                    
                    return false;
                } else if (ev.type == 'keyup') {
                    switch (ev.keyCode) {
                        case 37: // arrow keys
                        case 38:
                        case 39:
                        case 40:
                        case 27: { // esc
                            return true;
                        }
                    }
                } else {
                    return true;
                }
                
                resizeCodeBox(ev.keyCode);
            };

            // can't cancel the default tabbing behaviour :-(
            code.css({'overflow-y' : 'hidden'}).keyup(sizer).keypress(sizer).keydown(sizer);
            
            sizer({ type: 'keyup', keyCode : 224 });  // force a resize on load
        }
    },

    'login' : function () {
        function openIDForm() {
            var label = null;

            if (this.value == '') {
                label = $('#openIDForm #openid').css('background-image', '').removeAttr('class').prev();
                label.text('OpenID:');
                
            } else {
                label = $('#openIDForm #openid').removeAttr('class').addClass(this.value).prev();
                //.css('background-image', 'url(http://www.' + this.options[this.selectedIndex].text + '/favicon.ico)').prev();
                label.text('username:');
            }
        }

        $('#openidProvider').change(openIDForm).keyup(openIDForm).change().find('option').each(function () {
            $(this).css({
                'padding-left' : '24px',
                'background' : 'url(http://www.' + this.text + '/favicon.ico) no-repeat 2px'
            });
        }).filter(':last').css({
            'padding-left' : '24px',
            'background' : 'url(/images/login-methods.gif) no-repeat scroll 0px 0px;'
        });
    },

    'faq' : function () {
        $('#faq div.faqAnswer').hide();
    }
};

$(function () {
    var onloadID = document.body.id;
    if (typeof siteonload[onloadID] == 'function') {
        siteonload[onloadID].call();
    } 

    $('input')
        .filter('.hint')
            .hint()
        .end()
        .filter('.grow')
            .textGrow({ pad: 25, min_limit: 200, max_limit: 615 });

    $('a')
        .filter('.reveal')
            .click(function () {
                $(this.hash).slideToggle();
            })
        .end()
        .filter('.email')
            .each(function () {
                // de-obfuscate email
                var match = this.href.match(/^mailto:([a-z\.@\-_]*)(\?.*)?/i);
                var origEmail = match[1];
                var email = origEmail.replace(/[a-zA-Z]/g, function(c) {
                    return String.fromCharCode((c <= "Z" ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26);
                });
                this.innerHTML = this.innerHTML.replace(origEmail, email);
                this.href = 'mailto:' + email;
                if (match[2]) {
                    this.href += match[2];
                }
            });

    // if we're on a code listing page - allow the lines of code to click through to the detail page
    var codeblock = $('div.codeblock').click(function () {
        var href = $(this).parent().parent().find('h2 a').attr('href');
        if (href) {
            window.location = href;
        }
    }).filter('.preview').css('cursor', 'pointer');


    // tag search from header
    // $('#tagSearch').submit(function () {
    //         window.location = this.action + '/' + $('input', this).val();
    //         return false;
    //     });


    var copyErr = "The code could not be copied.  Please either install flash, or, in Firefox do the following: ";
    copyErr += "Enter 'about:config' in your address bar, right click the list, New -> Boolean,\n\n";
    copyErr += "signed.applets.codebase_principal_support\n\n";
    copyErr += "Then when you try to copy accept the security checks.";

    $('div.todgedCode').each(function () {
        // tab control
        var todgedCode = this;
        var panels = $('DIV.codePanel', this);
        $('UL.codeNav A', this).click(function () {
            if (this.pathname == window.location.pathname) {
                panels.hide();
                $('#' + this.hash.substr(1)).show();
                return false;
            }
        });

        // copy to clipboard
        $('UL.codeData A.copy', this).click(function () {
            var t = this;
            $.ajax({
                url: this.href,
                success: function (s) {
                    if (copy_clip(s)) {
                        var notice = $(t).parents('ul').append('<li style="display: none;" class="error">Code has been copied</li>').find('li:last').fadeIn(700, function () {
                            setTimeout(function () {
                                notice.fadeOut(1000, function () { $(this).remove(); });
                            }, 1000);
                        });
                    } else {
                        alert(copyErr);
                    }
                }
            });
            return false;
        });
    });

    // no more tagging :-(
    // $('#tags').tagSuggest();
});

function toURL(s) {
  return s.replace(/\s+/g, function (m, l) {
      return l != 0 ? '-' : '';
  }).replace(/[\W]/g, function(m,l){ 
      return m.match(/[\-_]/) ? m : '';
  }).toLowerCase();
}