// <script> // this is here for the syntax highlighter

function outsideV(e, additionalMargin) {
    outsideV.w || (outsideV.w = $(window));
    if (!(e instanceof $))
        e = $(e);
    return e.offset().top + e.height() > outsideV.w.height() - (additionalMargin || 0) - 17;
} // outsideV

function quotedString(s) { return '"'+s.replace(/(['"\\])/g, "\\$1")+'"' }

$(function(){
    // make these links into buttons for homogeneity
    $('#actions a').replaceWith(function(){ return "<button onclick='location = "+quotedString(this.getAttribute('href'))+"'>"+this.innerHTML+"</button>"; });
    // selecting functionality
    $('#files .selector').show().change(function(){
        $(this).closest('tr').toggleClass('selected');
        selectedChanged();
    });
    $('.trash-me').detach(); // this was hiding things for those w/o js capabilities
    // infinite upload fields available
    var x = $('input[type=file]');
    x.change(function(){
        if ($(this).data('fired')) return;
        $(this).data('fired',1);
        fileTpl.clone(true).insertAfter(this).css('display','block');
    });
    // we must create an empty "template", by cloning before it's set to a file, because on some browsers (Opera 10) emptying the value run-time is not allowed.
    // this must be done after the above instruction, so we'll clone also the behavior. 
    var fileTpl = x.clone(true).css('display','none');

    var x = $('#upload');
    if  (x.size()) {
        // make it popup by button, so we save some vertical space and avoid some scrollbar
        x.hide(); 
        $('#actions button:first').before(
            $("<button>Upload</button>").click(function(){ 
                $(this).slideUp(); x.fadeIn(); 
            })
        );
        // on submit			
        x.find('form').submit(function(){ 
            if (!$("[name=file]").val()) return false; // no file, no submit
            $(this).hide(); // we don't need the form anymore, make space for the progress bars
            // build the gui
            x.append("<div id='progress'>in progress...</div>");
            x.append($("<button style='float:right'>Cancel</button>").click(function(){
                // stop submit/upload
                if (typeof stop == 'function')
                    stop(); 
                else
                    document.execCommand("Stop");
                $(this).add($("#progress")).remove(); // remove progress indicators and this button too
                $("#upload form").slideDown(); // re-show the form
            }));

            // refresh information
            function updateProgress() {
                var now = new Date();
                if (now-updateProgress.last < updateProgress.refresh*3) return; // until the request is fulfilled, we give it 3 times the refresh time
                updateProgress.last = now;
                $.get('/?mode=section&id=progress&only=up', function(txt) {
                    if (!txt) return;
                    var x = $('#progress');
                    if (!x.size()) return clearInterval(updateProgress.handle);
                    if (txt.indexOf('<li>') >= 0) x.html(txt);
                    updateProgress.last = 0;
                });
            }//updateProgress
            updateProgress.refresh = 3; // choose the time, in seconds
            updateProgress.refresh *= 1000; // javascript wants it in milliseconds
            updateProgress.handle = setInterval(updateProgress, updateProgress.refresh);
            return true;
        });
    }

    // search options appear when it gets focus
    $('#search').focusin(function(evt){
        inSearch = 1;
        if (evt.target.getAttribute('type') == 'submit') return; // the submitter button won't expand the popup, but sets the flag to avoid the popup to be closed
        $("#search .popup").slideDown();
    }).focusout(function(evt){
        inSearch = 0;
        setTimeout(function(){
            if (!inSearch)
                $("#search .popup").fadeOut();
        });
    });
    $('#search form').submit(function(){
        var s = $(this).find('[name=search]').val();
        var a = '';
        var ps = [];
        switch ($('[name=where]:checked').val()) {
            case 'anywhere': 
                a = '/';
            case 'fromhere':
                ps.push('search='+s);
                break;
            case 'here':
                if (s.indexOf('*') < 0) s = '*'+s+'*';
                ps.push('files-filter='+s);
                ps.push('folders-filter='+s);
                break;
        }
        location = a+'?'+ps.join('&');
        return false;
    });
    
    // workaround for those browsers not supporting :first-child selector used in style
    if ($('#files td:first').css('text-align') != 'left')
        $('#files tr td:first-child').css('text-align','left');

    // here we make some changes trying to make the panel fit the window
    var removed = 0;
    var e = $('#panel'); 
    while (outsideV(e)) {
        switch (++removed) {
            case 1: $('#serverinfo').hide(); continue;
            case 2: $('#select').hide(); continue;
            case 3: $('#breadcrumbs a').css({display:'inline',paddingLeft:0}); continue;
            case 4: $('#login').replaceWith($('#login center').prepend('<img src="/~img27">')); continue;
        }
        break; // give up
    }
    if (HFS.paged)
        if (getCookie('paged') == 'no')
            addPagingButton('#actions button:first');
        else
            pageIt();
               
    
    selectedChanged();
    // darn you ie6!
    if (!$.browser.msie || $.browser.version > 6) return;
    $('fieldset').width('250px').after('<br>');
    $('#panel').css('margin-right','1.5em');
    $('a').css('border-width','0');
    setTimeout(pageIt, 500); // at this time the page is not correctly formatted in IE6
});//onload

function ajax(method, data, cb) {
	if (!data)
		data = {};
	data.token = "0.164777449797839";
	return $.post("?mode=section&id=ajax."+method, data, cb||getStdAjaxCB());
}//ajax

function addPagingButton(where) {
    $("<button>Paged list</button>").insertBefore(where || '#files').click(function(){
        $(this).remove();
        pageIt(true);
        delCookie('paged');
    });
}//addPagingButton

function pageIt(anim) {
    var rows = $('#files tr');
    if (!rows.size()) return;
    
    page = 0; // this is global
    var pages = $("<div id='pages'>Page </div>").css('visibility','hidden').insertBefore('#files');
    var pageSize = 0;
    while (!outsideV(rows[pageSize], 20))
        if (++pageSize >= rows.size())
            return pages.remove();
    if (pageSize == 0) return; // this happens when the page is not formatted at this exact time, and the table is misplaced 

    Npages = Math.ceil(HFS.number / pageSize);
    if (Npages == 1)
        return pages.remove();
    $('#files').width($('#files').width()); // hold it still

    var s = '';
    for (var i=1; i <= Npages; i++)
        s += '<span>'+i+'</span> ';
    s = $(s);
    s.appendTo(pages).click(function(){
        page = Number(this.innerHTML)-1;
        $('#files tr:gt(0):visible').hide();
        $('#files tr:gt('+(page*pageSize)+'):lt('+pageSize+')').show();
        pages.find('span').removeClass('selectedPage').filter(':nth('+page+')').addClass('selectedPage');
    });
    s.first().addClass('selectedPage');		
    $('#files tr:gt('+((page+1)*pageSize)+')').hide();
    pages.append($("<button type='button'>No pages</button>").click(function(){
        pages.slideUp(function(){ pages.remove(); });
        $('#files tr:hidden').show();
        addPagingButton();
        setCookie('paged', 'no');
    }));
    pages.css({visibility:'', display:'none'});
    if (anim) pages.slideDown()
    else pages.show();		
}//pageIt

function selectedChanged() {
    $("#selected-number").text( selectedItems().size() ).parent().show();
} // selectedChanged

function getItemName(el) {
    if (typeof el == 'undefined')
        return false;
    // we handle elements, not jquery sets  
    if (el.jquery)
        if (el.size())
            el = el[0];
        else
            return false;
    // take the url, and ignore any #anchor part
    var s = el.getAttribute('href') || el.getAttribute('value');
    s = s.split('#')[0];
    // remove protocol and hostname
    var i = s.indexOf('://');
    if (i > 0)
        s = s.slice(s.indexOf('/',i+3));
    // current folder is specified. Remove it.
    if (s.indexOf(HFS.folder) == 0)
        s = s.slice(HFS.folder.length);
    // folders have a trailing slash that's not truly part of the name
    if (s.slice(-1) == '/')
        s = s.slice(0,-1);
    // it is encoded
    s = (decodeURIComponent || unescape)(s);        
    return s;
} // getItemName

function submit(data, url) {
    var f = $('#files').closest('form');
    if (url) f.attr('action', url);
    f.find('.temp').remove();
    for (var k in data)
        f.append("<input class='temp' type='hidden' name='"+k+"' value='"+data[k]+"' />");
    f.submit();
}//submit

function putMsg(txt, time) {
    if (!time) time = 4000;
    var msgs = $('#msgs');
    msgs.slideDown();
    if (msgs.find('ul li:first').html() == txt)
        clearTimeout(lastTimeoutID);
    else
        msgs.find('ul').prepend("<li>"+txt+"</li>");
    lastTimeoutID = setTimeout("$('#msgs li:last').fadeOut(function(){$(this).detach(); if (!$('#msgs li').size()) $('#msgs').slideUp(); });", time);
}//putMsg

RegExp.escape = function(text) {
    if (!arguments.callee.sRE) {
        var specials = '/.*+?|()[]{}\\'.split('');
        arguments.callee.sRE = new RegExp('(\\' + specials.join('|\\') + ')', 'g');
    }
    return text.replace(arguments.callee.sRE, '\\$1');
}//escape

function include(url, type) {
    $.ajaxSetup({async: false}); // we'll wait.
    if (!type)
        type = /[^.]+$/.exec(url);
    var res;
    if  (type == 'js')
        res = $.getScript(url);
    else res = $.get(url, function(){ 
        if (type == 'css')
            $('head').append('<link rel="stylesheet" href="'+url+'" type="text/css" />');
    });
    $.ajaxSetup({async: true}); // restore it
    return res.responseText;
}//include

function ezprompt(msg, options, cb) {
    // 2 parameters means "options" is missing
    if (arguments.length == 2) {
        cb = options;
        options = {};
    }
    if (!$.prompt) { // load on demand
        include('/?mode=section&id=impromptu.css');
        include('/?mode=section&id=jquery.impromptu.js'); 
    }
    var v;
    if (v = options.type) {
        msg += '<br />';
        if (v == 'textarea')
            msg += '<textarea name="txt" cols="30" rows="8">'+options['default']+'</textarea>';
        else
            msg += '<input name="txt" type="'+v+'"'
                + ((v = options['default']) ? ' value="'+v+'"' : '')
                + ' />';
    }
    $.prompt(msg, {
        opacity: 0.9,
        overlayspeed: 'fast',
        loaded: function(){  
            $('#jqibox').find(':input').keypress(function (e) {
                var c = (e.keyCode || e.which);
                if (options.keypress && options.keypress(c, this, e) === false) return;
                if (c != 13 || this.tagName == 'TEXTAREA') return; // ENTER key is like submit, but not in textarea
                $('.jqibuttons button:first').click();
                return false;
            }).filter(':first').focus()[0].select(); 
        },
        submit: function(val,div,form) {
            var res = cb(options.type ? form.txt : form, $('#jqibox'), options.cbData );
            if (res === false) {
                $('#jqibox').find(':input:first').focus();
                return false;
            }
            return true;
        }, 
        fadeClicked: function() { $('#jqibox').find(':input:first').focus(); }
    });
}//ezprompt

// this is a factory for ajax request handlers
function getStdAjaxCB(what2do) {
    if (!arguments.length)
        what2do = true;
    return function(res){
        res = $.trim(res);

        if (res !== "ok") {
            alert("Error: "+res);
            if (res === 'bad session')
                location.reload();
            return;
        }
        // what2do is a list of actions we are supposed to do if the ajax result is "ok"
        if (typeof what2do == 'undefined') 
            return;            
        if (!$.isArray(what2do))
            what2do = [what2do];
        for (var i=0; i<what2do.length; i++) {
            var w = what2do[i];
            switch (typeof w) {
                case 'function': w(); break; // you specify exactly what to do
                case 'string':
                    switch (w[0]) {
                        case '!': alert(w.substr(1)); break;
                        case '>': location = w.substr(1); break;
                        default: putMsg(w); break;
                    }
                case 'boolean': if (w) location = location; break;
            }
        }
    }
}//getStdAjaxCB
        
function changePwd() {
    ezprompt(this.innerHTML, {type:'password'}, function(s){
        if (s) ajax('changepwd', {'new':s}, getStdAjaxCB([
            "!Password changed, you'll have to login again.", 
            '>~login'
        ]));
    });
}//changePwd

function selectedItems() { return $('#files .selector:checked') }

function selectedFilesAsStr() {
    var a = [];
    selectedItems().each(function(){
        a.push(getItemName(this));
    });
    return a.join(":");
}//selectedFilesAsStr

function setComment() {
    var sel = selectedItems();
    if (!sel.size())
        return putMsg("No file selected");
    var def = sel.closest('tr').find('.comment').html() || '';
    ezprompt(this.innerHTML, {type:'textarea', 'default':def}, function(s){
        if (s == def && sel.size() == 1) return true; // there s no work to do
        ajax('comment', {text:s, files:selectedFilesAsStr()});
    });
}//setComment

function moveClicked() {
    ezprompt("Enter the destination folder", {type:'text'}, function(s){
        ajax('move', {dst:s, files:selectedFilesAsStr()}, function(res){
            var a = res.split(";");
            if (a.length < 2)
                return alert($.trim(res));
            var failed = 0;
            var ok = 0;
            var msg = "";
            for (var i=0; i<a.length-1; i++) {
                var s = $.trim(a[i]);
                if (!s.length) {
                    ok++;
                    continue;
                }
                failed++;
                msg += s+"\n";
            }
            if (failed) 
                msg = "We met the following problems:\n"+msg;
            msg = (ok ? ok+" files were moved.\n" : "No file was moved.\n")+msg;
            alert(msg);
            if (ok) location = location; // reload
        });
    });
}//moveClicked

function selectionMask() {
    ezprompt('Please enter the file mask to select', {'type':'text', 'default':'*'}, function(s){
        if (!s) return false;
        var re = s.match('^/([^/]+)/([a-zA-Z]*)');
        if (re)
            re = new RegExp(re[1], re[2]);
        else {
            var n = s.match(/^(\\*)/)[0].length;
            s = s.substring(n);
            var invert = !!(n % 2); // a leading "\" will invert the logic
            s = RegExp.escape(s).replace(/[?]/g,".");;
            if (s.match(/\\\*/)) {
                s = s.replace(/\\\*/g,".*");
                s = "^ *"+s+" *$";   // in this case let the user decide exactly how it is placed in the string  
            }
            re = new RegExp(s, "i");
        }
        $("#files .selector")
            .filter(function(){ return invert ^ re.test(getItemName(this)); })
            .closest('tr').addClass("selected").find('.selector').attr('checked',true);
        selectedChanged();
    }); 
}//selectionMask

function setCookie(name,value,days) {
	if (days) {
		var date = new Date();
		date.setTime(date.getTime()+(days*24*60*60*1000));
		var expires = "; expires="+date.toGMTString();
	}
	else var expires = "";
	document.cookie = name+"="+value+expires+"; path=/";
} // setCookie

function getCookie(name) {    
    var a = document.cookie.match(new RegExp('(^|;\s*)('+name+'=)([^;]*)'));
    return (a && a[2]) ? a[3] : null;
} // getCookie

function delCookie(name) {
	setCookie(name,"",-1);
} // delCookie

    