function FileMan() {
    this.config = {
        timer     : 750,
        uploadmax_width : 400,
        wrapper   : 0,
        content   : 0,
        effect    : true,
        image_url : null,
        cgi_url   : null,
        root_path : null,
        regnum    : '',
        work_path : '/'
    };

    this.current = {
        command : null,
        action  : null
    };

    this.height      = {
        contentmessage : $('#contentmessage').outerHeight(),
        wrapperheader  : $('#wrapper-header').outerHeight() + 4,
        wrapperfooter  : $('#wrapper-footer').outerHeight()
    };

/* Field maps */
    this.maps   = { type: 0, icon: 1, name: 2, size: 3, desc: 4, date: 5, owner: 6, perm: 7, sperm: 8, sdate: 9, path: 10, full_path: 11 };

/* Paging variables */
    this.paging = {
        num_hits    : 0,
        current_page: 1,
        size        : '',
        max_hits    : 25,
        sb          : 'name',
        so          : 'asc'
    };

    this.files = new Array(); this.paths = new Array();
    this.hiddens = new Object(); this.cdata = new Object();
    this.parent = '';
    
/* Form object */
    this.form  = $('#wrapper-content form');

/* Screen dimensions */
    this.screen = {
        height : getScreenHeight(),
        width : getScreenWidth()
    };

/* Languages which shows up in status bar */
    this.languages = {
      preferences : 'Preferences',
      setup : 'Setup',
      password : 'Change Password',
      user : 'User Management',
      log : 'Browser Logs',
      env : 'Environment',
      user_add : 'Add a user',
      user_modify : 'Modify a user',
      user_access : 'Change accesses',
      user_permission : 'Change Permissions',
      uncompress : 'Uncompress'
    };

    this.fileEditor = new Object();

    var fm = this;
    this.config.tinyMCE = {
        // General options
        id : 'tinyEditor',
        mode : "textareas",
        theme : "advanced",
        plugins : "style,table,advhr,advimage,advlink,preview,media,searchreplace,fullpage",
        convert_urls : false,
        remove_linebreaks : false,
        setup : function(ed) {
            ed.onChange.add(function(ed, l) {
                if (!fm.fileEditor.beingEdited) fm.fileEditor.beingEdited = true;
            });
        },

        // Theme options
        theme_advanced_buttons1 : "newdocument,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,styleselect,formatselect,fontselect,fontsizeselect",
        theme_advanced_buttons2 : "cut,copy,paste,pastetext,pasteword,|,search,replace,|,bullist,numlist,|,outdent,indent,blockquote,|,undo,redo,|,link,unlink,image,cleanup,help,|,forecolor,backcolor",
        theme_advanced_buttons3 : "tablecontrols,|,hr,removeformat,|,sub,sup,|,charmap,iespell,media,advhr,|,code,preview,|,fullpage",
        theme_advanced_resizing : true,
        theme_advanced_toolbar_location : "top",
        theme_advanced_toolbar_align : "left",
        theme_advanced_statusbar_location : "bottom"
    };
}

/*
    Initial setting variables and actions    
*/
FileMan.prototype.init = function() {
    var fm = this;
    var $modal = $('#modal-dialog');

/* Set up the commands */
    $('#primarynav a[rel]').each(function() {
        $(this).click(function() {
            var action = $(this).attr('rel')
            if ($(this).parent().hasClass('navitem')) {
                if ($('#cmd-' + action).length == 1) {
                    if (action == 'file') {
                        fm.newfile();
                    }
                    else {
                        fm.commandDialog({ command : action });
                    }
                }
            }
            else if (action == 'help') {
                fm.help();
            }
            else if (action == 'about') {
                fm.about();
            }
            else {
                fm.actionForm(action);
            }
            return false;
        });
    });

/* The layout should be resized when window is resized */
    $(window).resize(function() {
        fm.screen = {
            height : getScreenHeight(),
            width : getScreenWidth()
        };       
        if (!$modal.hasClass('hidden')) {
            var mwidth = $modal.width();
            var mleft  = parseInt((fm.screen.width - mwidth) / 2);
            $modal.css('left', mleft + 'px');
        }
        fm.layoutDimensions(fm.screen.height);
    });

/* Set up CD form */
    $('#cdform form').submit(function() {
        fm.cd({ dname : $(this).find('input[name="dname"]').val() });
        $(this).resetForm();
        return false;
    });

    this.form.append('<input type="hidden" id="serial" name="serial" value="" /><input type="hidden" name="ajax" value="1" />').submit(function() {
        var command = fm.current.command || fm.current.action;

/* Handle extra steps if needed for some commands before submit the request */
        fm.form.attr('action', fm.config.cgi_url);
        if (command == 'command') {
            fm.command();
        }
        else if (command == 'upload') {
            fm.upload();
        }
        else if (command.search(/file|edit/) == 0) {
            if (tinyMCE.activeEditor) {
                var editor  = $('textarea[name="editor"]');
                var content = $('#editor_mode').val() == 'html' ? fm.tinyMCEContent() : editor.val();
                tinyMCE.activeEditor.remove();
                editor.val(content);
            }
        }

        $(this).ajaxSubmit({
            dataType : 'json',
            beforeSubmit : function() {
                /* Display waiting image for some commands */
                if (command.search(/search|replace|uncompress|compress|copy|delete|move|download/) == 0) {
                  fm.loading('start');
                }
            },
            success : function(response) {
                fm.loading('end');
                if (response.status == 'ERR_NOAUTH') {
                    fm.login(response.data.html);
                }
                else {
                    fm.commandResponse(response);
                }
            }
        });
        return false;
    });

/* Load files and setting layout */
    this.cd({ load_default : 1 });
    this.layoutDimensions();

/* Set up sorting action for the headers */
    $('.foldertab th a[rel]').each(function() {
        var link = $(this);
        link.click(function() {
            $('.foldertab th a[rel] img').remove();
            if (fm.paging.sb != link.attr('rel')) {
                fm.paging.sb = link.attr('rel');
                fm.paging.so = fm.paging.sb.search(/date|size|perm/) != -1 ? 'desc' : 'asc';
            }
            else {
                fm.paging.so = fm.paging.so == 'asc' ? 'desc' : 'asc';
            }
            fm.sort(fm.files, fm.paging.sb, fm.paging.so);
            fm.page(fm.paging, function(nh) { fm.printFiles(nh); });
            return false;
        });
    });

/* Set Advance search and upload multiple files link */
    this.form.find('a[rel="advance-search"]').click(function() { return fm.advanceSearch(); });
    this.form.find('a[rel="upload-multiple"]').click(function() { return fm.uploadFiles(); });

/* Set action for action drop down */
    $('#fm_action').attr('selectedIndex', 0).change(function() {
        var action = $(this).val();
        if ($('#cmd-' + action).length == 1 || action == '' || action.search(/delete|perl|print/) == 0) {
            fm.actionDialog({ action : action });
        }
        else {
            fm.showMessage({ success : false, message : 'Invalid action: ' + action });
        }
    });

/* Cluetip setup */
    $('.help').cluetip({
        activation : 'click',
        closePosition : 'title',
        closeText: '<img src="' + this.config.image_url + '/icons/close.gif" alt="Close" />',
        width : 400,
        height : 300,
        sticky : true,
        arrows : false
    });

/* Handle showing sub-menus */
    if (this.config.is_ie) {
        $('.primarynav li[class="navitem"]').each(function() {
            var $li = $(this);
            if ($li.find('ul').length == 0) return;
            var $ul = $li.find('ul');
            $li.mouseover(function() {
                $li.addClass('sfhover');
                $li.append('<iframe style="height: '+ ($ul.height() - 5) + 'px"></iframe>');
            });
            $li.mouseout(function() {
                $li.find('iframe').remove();
                $li.removeClass('sfhover');
            });
        });
    }

/* Search Expression option requires 'Search Contents' checked */
    $('#search_exp').click(function() {
        $('#search_content').attr('checked', $(this).attr('checked') ? true : false);
    })

/* Browse buttons */
    $('input[name="button-browse"]').each(function() {
        var button = $(this);
        button.click(function() {
            var command = fm.current.command || fm.current.action;
            fm.browse({
                title : command == 'diff' ? 'Select a text file' : 'Select Directory',
                filter : command == 'diff' ? 2 : 1,
                hidden_query : fm.hiddens.hidden_query,
                id : command + '_input'
            });
        });
    });

/* Setting for chmod command */
    $('#cmd-chmod input[name="chmod_input"]').change(function() {
        var val = $(this).val();
        if (val.length == 0) return;
        if (val.search(/\D/) >= 0) {
            $(this).val('').focus();
            fm.showMessage({ success : false, message : 'Invalid octal notation.'})
            return;
        }        
        var nums = val.split("");
        var invalid = false;
        for (var i=0; i<nums.length; i++) {
            if (nums[i] == 0) continue;
            if (nums[i] > 7) {
                invalid = true;
                break;
            }
        }

        if (invalid) {
            fm.showMessage({ success : false, message : 'Invalid octal notation.'})
            return;
        }
        fm.chmod(val);
    });

/* Logout link */
    $('#loginbar a[rel]').click(function() {
      fm.current.command = 'logout';
      fm.form.find('input[name="cmd"]').val('logout');
      fm.form.submit();
      return false;
    });

/* Format Date */
    this.config.date_format = this.config.date_format;
    Date.firstDayOfWeek     = 7;
    Date.format             = this.config.date_format;

/* Prevent user uses mousewheel on IE */
    document.getElementById('fm_action').onmousewheel = function() { return false; };

/* Setting action for access menu bar. This is only available for user who has multiple access directories */
    $('#uaccess a[rel]').each(function() {
        var link = $(this);
        link.click(function() {
            fm.cd({ dname: '/', a : link.attr('rel') });
            return false;
        });
    });
}

/*
  login method: handles all none authentication actions
  html : should be login form. This happens when session is expired
*/
FileMan.prototype.login = function(html) {
  if (html) $('#home').html(html).addClass('noauth');

  var $contentmessage = $('#contentmessage');

  $('#username').focus();
  $contentmessage.find('.error').oneTime(5000, 'msgtimer', function() { $contentmessage.slideUp('normal'); });

  var fm = this;
  $('a[rel="reset_password"]').click(function() {
    fm.printForm('reset_password', function(response) {
      if (response.success) {
        $('form input[name="cmd"]').val('reset_password');
        var $login = $('#login');
        $login.fadeOut('normal', function() {
          $('#content').append(response.data.html);
          $('#email').focus();
          $('a[rel="login"]').click(function() {
            var $reset = $('#reset_password');
            $reset.fadeOut('normal', function() {
              $login.fadeIn('fast', function() {
                $reset.remove();
                $('#username').focus();
                $('form input[name="cmd"]').val('login');
              });
            });
          });
        });
      }
    });

    return false;
  });

  $('form').ajaxForm({
    dataType : 'json',
    success  : function(response) {
      if (response.success) {
        if (response.data.redirect == 'login') {
            var $reset = $('#reset_password');
            $reset.fadeOut('normal', function() {
                $('#login').fadeIn('normal', function() {
                    $reset.remove();
                    $('form input[name="cmd"]').val('login');
                    $contentmessage.find('div').html(response.message).removeClass().addClass('message');
                    $contentmessage.slideDown('normal', function() { $('#username').focus(); });
                });
            });
            fm.login(response.data.html);
        }
        else {
            $('#wrapper').fadeOut('normal').remove();
            window.location = fm.config.cgi_url + (response.data.notuse_cookie == 1 ? ('?sid=' + response.data.session.id) : '');
        }
      }
      else {
            $contentmessage.find('div').html(response.message).removeClass().addClass('error');
            $contentmessage.slideDown('normal', function() { 
                if ($('#login').is(':hidden')) $('#email').focus();
                else $('#username').focus();
            }).oneTime(5000, 'msgtimer', function() { $contentmessage.slideUp('normal'); });
      }
    }
  });
}

/*
  Handle layout dimensions
  wHeight: Should be window height. This is an optional.
  message_height: Should be message box height. This is an optional
 */
FileMan.prototype.layoutDimensions = function(wHeight) {
    if (typeof(wHeight) == 'undefined' || !wHeight) wHeight = $(window).height();

    var message_height = $('#contentmessage').is(':hidden') ? 0 : ($('#contentmessage').outerHeight() + 2);
    var height         = wHeight - this.height.wrapperheader - this.height.wrapperfooter - 5;
    var shadow_height  = $('#ocwrapper .shadowtop').outerHeight() + $('#ocwrapper .shadowbottom').outerHeight();
    var command_height = $('#contentheader').is(':hidden') ? 0 :  $('#contentheader').outerHeight();

    var wrapper_content_padding = command_height > 0 ? 2 : 18;
    var content_height = height - command_height - message_height - shadow_height - wrapper_content_padding;

    /* Setting height for these objects */
    $('#ocwrapper').css('height', height - command_height + 'px');
    $('#wrapper-content').css('height', height + 'px');
    $('#content').css('height', content_height + 'px');

    this.height.content = $('#content').height();
    this.height.wrapper = height;

    $('#contentheader').css('width', $('#wrapper-content').width() - 20 + 'px');

    /* If command-dialog exists, it needs to get resized as well */
    var $command_dialog = $('#command-dialog');
    if ($command_dialog.length > 0) {
        var $editor = $command_dialog.find('textarea[name="editor"]');
        if ($editor.length > 0) {
          var nwidth  = getScreenWidth() - 45;
          var nheight = getScreenHeight() - 275;
          $editor.css('height', nheight + 'px').css('width', nwidth + 'px');

          if ($editor.is(':hidden') && this.config.tinyMCE) {
              this.config.tinyMCE.width  = nwidth + 'px';
              this.config.tinyMCE.height = nheight - 5 + 'px';
              
              tinyMCE.activeEditor.hide();
              tinyMCE.init(this.config.tinyMCE);
          }
        }

        var toolbar_height = $command_dialog.find('.toolbar').outerHeight() || 0;
        $command_dialog.find('.contentframe').css('height', this.height.content - toolbar_height  + 'px');
    }
    else {
        /* Setting the height for the content frame which is set 'scroll' for overflow-y */
        if ($('.contentframe').length > 0 && !$('.contentframe').hasClass('hide')) {
            this.height.folder  = $('.foldertab:first').height();
            this.height.toolbar = $('.toolbar').outerHeight() + this.height.folder;

            $('.contentframe').css('height', content_height - this.height.toolbar + 'px');

            /* Fixing the width for file table which doesn't work probably on IE7 */
            $('.contentframe table[class="foldertab"]').css('width', $('.foldertab:first').outerWidth() - 18 + 'px');
        }
    }
}

/*
  Handles showing the command panel
  args : should be a hash of parameters
*/
FileMan.prototype.commandDialog = function(args) {
    var fm = this;
    if (this.fileEditor.beingEdited) {
        if (args.command == 'command') this.fileEditor.actionCalled = true;
        return this.editorConfirm(function() { fm.commandDialog(args); });
    }

    if (typeof(args) == 'undefined') args = new Object();

/* Clear timeoud ID if exists */
    if (this.timerID > 0) {
        window.clearTimeout(this.timerID);
        this.timerID = 0;
    }

    var $contentheader  = $('#contentheader');
    var $contentmessage = $('#contentmessage');
    var command_height = $contentheader.height();
    var message_height = 0
    var msg_show       = false;
    var command        = args.command || null;

/* Hide the action bar if visible */
    if (this.current.action) {
        $('#fm_action').attr('selectedIndex', 0);
        this.fadeOut($('#cmd-' + this.current.action));
        this.current.action = null;
    }

/* Display message */
    if (!$contentmessage.is(':hidden')){
        $contentmessage.stopTime('msgtimer');
        this.fadeOut($contentmessage);
        msg_show = true;
    }

/* Display the Command command screen */
    var $command_dialog = $('#command-dialog');
    if (command == 'command') {
        if (this.current.command != command) {
            var $content = $('#content');

            this.printForm('command', function(response) {
                if (response.success) {
                    fm.working_dir = response.data.working_dir;
                    if ($command_dialog.length > 0) $command_dialog.remove();
                    fm.fadeOut($('#listfiles'), function() {
                        $content.append('<div id="command-dialog" class="command"><span class="prompt">' + response.data.prompt + '</span></div>');
                        fm.fadeIn($('#command-dialog').css('overflow-y', 'scroll'), function() { 
                            fm.showStatus(command);
                        });
                    });
                }
            });
        }
    }

/* Display editor form */
    else if ($command_dialog.is(':hidden')) {
        this.fadeOut($('#listfiles'), function() {
            if (command.search(/file|edit/) == 0) {
                var $modal = $('#modal-dialog');
                fm.loading('start');
                
                fm.fadeIn($command_dialog, function() {
                    var $contentframe = $command_dialog.find('.contentframe');
                    var $editor = $contentframe.find('textarea[name="editor"]');
                    $contentframe.css('height', $command_dialog.height() + 'px').css('width', $command_dialog.width() + 'px').css('overflow', 'hidden');
                    if ($('#editor_mode').val() == 'html') {
                        $editor.css('height', $command_dialog.height() - 13 + 'px').css('width', $command_dialog.width() - 5 + 'px');
                        tinyMCE.init(fm.config.tinyMCE);
                    }
                    else {
                      $editor.css('height', $command_dialog.height() - 5 + 'px')
                        .css('width', $command_dialog.width() - 5 + 'px')
                        .change(function() {
                            if (!fm.fileEditor.beingEdited) fm.fileEditor.beingEdited = true;
                        });

                      fm.fadeIn($editor, function() { 
                          if (!$modal.is(':hidden')) $modal.html('').jqmHide();
                      });
                    }
                    fm.loading('end');
                });
            }
            else {
                fm.fadeIn($command_dialog);
            }
        });
    }

/* Display main screen */
    else if ($('#listfiles').is(':hidden') || $('.foldertab').is(':hidden')) {
        if (!$command_dialog.is(':hidden')) {
            this.fadeOut($command_dialog, function() {
                $command_dialog.remove();
                if (command == null) $('.contentframe').css('height', fm.height.content - fm.height.toolbar - message_height + 'px');
                fm.fadeIn($('.foldertab'));
                fm.fadeIn($('.paging'));
                fm.fadeIn($('#listfiles'), function() {
                    if (args.message) fm.showMessage(args);
                    if (args.refresh) fm.cd();
                });
            });
        }
        else {
            this.fadeIn($('#listfiles'), function() {
                if (args.message) fm.showMessage(args);
                if (args.refresh) fm.cd();
            });
            this.fadeIn($('.foldertab'));
            this.fadeIn($('.paging'));
        }
        this.showStatus();      
    }
    if (this.current.command == command) return;

    if (command == null && this.current.command != command) {
        $("#ocwrapper").css('height', this.height.wrapper - command_height - message_height + 'px').css('margin-top', '0px');
        $("#content").css('height', this.height.content - message_height + 'px');
        $(".contentframe").css('height', this.height.content - message_height - command_height - 10 + 'px');

        this.fadeOut($contentheader);
    }
    else {
        $('#primarynav a[rel="' + command + '"]').parent().addClass('selected');

/* Create space for the command panel */
        if ($contentheader.is(':hidden')) {
            if ($(".contentframe").length > 0) {
                $("#content").css('height', fm.height.content  - command_height + 'px');
                this.animate($(".contentframe"), {
                    height : this.height.content - this.height.toolbar - command_height,
                    scrollTop : 0
                }, 'fast', function() {
                    fm.animate($("#ocwrapper"), {
                      'margin-top' : command_height,
                      'height'     : fm.height.wrapper - command_height
                    }, 'fast', function() {
                        fm.slideDown($contentheader, function() {
                            $('#' + command + '_input').val(args.value || '').focus();
                        });
                    });
                });
            }            
        }

/* Hide message box and resize the main screen */
        else if (msg_show) {
            if ($(".contentframe").length > 0) {
                $("#content").css('height', this.height.content  - command_height + 'px');
                $(".contentframe").css('height', this.height.content - this.height.toolbar - command_height + 'px');

                this.animate($("#ocwrapper"), {
                    'margin-top' : command_height,
                    'height'     : this.height.wrapper - command_height
                });
            }
        }
    }

    /* Reset form before display it */
    this.resetForm(command);

    /* Display the command dialobottomg */
    if (this.current.command) {
        this.fadeOut($('#cmd-' + this.current.command), function() {
            fm.fadeIn($('#cmd-' + command), function() {
                $('#' + command + '_input').val(args.value || '').focus();
            });
        });
    }
    else {
        this.fadeIn($('#cmd-' + command));
    }

/* Remove #xx-content */
    $('#content').css('overflow', 'hidden');
    if (this.current.command) {
        this.fadeOut($('#' + this.current.command + '-content'), function() { $('#' + this.current.command + '-content').remove() });
        $('.primarynav a[rel="' + this.current.command + '"]').parent().removeClass('selected');
    }

/* Set the current command */
    this.current.command = command;
    $('#cmd').val(command)

    if (this.form.find('input[name="cmd-result"]').length > 0 && command != 'command') {
        this.form.find('input[name="cmd-result"]').remove();
        this.cd();
    }
}

/* 
  actionDialog method: Show action dialog
  action : should be action name
  json : should be json object
*/
FileMan.prototype.actionDialog = function(args) {
    var fm = this;
    if (this.fileEditor.beingEdited) {
        this.fileEditor.actionCalled = true;
        return this.editorConfirm(function() { 
            fm.actionDialog(args);
        });
    }

    if (!args) args = new Object;
    var action = args.action;
    var json   = args.json;

    if (this.current.action == action) return;

/* Clear timeoud ID if exists */
    if (this.timerID > 0) {
        window.clearTimeout(this.timerID);
        this.timerID = 0;
    }

/* Get rid of hide from .fodlertab */
    if ($('.foldertab').is(':hidden')) {
        $('#command-dialog').remove();
        this.fadeIn($('.foldertab'));
        this.fadeIn($('.paging'));
        this.fadeIn($('.readme'));
    }

    var message_height = 0;
    var toolbar_height = this.height.toolbar;
    var folder_height  = 0;
    var $contentframe  = $('.contentframe');
    var $contentheader = $('#contentheader');

    if (json && json.message) {
        this.showMessage(json);
        message_height = this.height.contentmessage;
    }
    else if (!$('#contentmessage').is(':hidden')) {
        this.slideUp($('#contentmessage'));
    }

/* Display a form instead: this applies for actions under toolbar menus*/
    var html = json && json.data.html ?  json.data.html : '';
    if (html != '') {
        if ($('#command-dialog').length == 0) $('#content').append('<div id="command-dialog"></div>');
        if (action != 'user' && action.search(/log/) == -1) toolbar_height -= this.height.folder;
        if (action != 'user_modify' && json.data.user_modify) action = 'user_modify';

        var $command_dialog = $('#command-dialog').css('overflow-y', 'hidden');
        this.fadeOut($('#listfiles'), function() {
            fm.fadeOut($command_dialog, function() {
                $command_dialog.html(html);
                fm.fadeIn($command_dialog);

                $contentframe = $('#command-dialog .contentframe');
                if (action.search(/user/) == 0) {
                    if (action == 'user') {
                        fm.userManagement(json);
                    }
                    else {
                        fm.userAction();
                        $command_dialog.find('input[name="button-cancel"]').click(function() { fm.actionForm('user'); });

                        $command_dialog.find('input[name="button-browse"]').click(function() {
                            var access = $('textarea[name="access_directories"]').val();
                            var aTemp = access != '' ? access.split('\n') : new Array();
                            fm.cdata.accesses = aTemp;
                            fm.browse({
                                title : 'Select Directories',
                                filter : 1,
                                hidden_query : fm.hiddens.hidden_query,
                                multiple : true,
                                id : 'access_directories'
                            })
                        });

                        $command_dialog.find('select[name="mod_type"]').change(function() {
                            if ($(this).val() == 1) {
                                fm.fadeOut($('#user_section'));
                            }
                            else {
                                fm.fadeIn($('#user_section'));
                            }
                        });
                    }
                }
                else if (action == 'log') {
                    fm.browseLogs(json);
                }
                else if (action == 'uncompress') {
                    fm.uncompress(json.data.files);
                    folder_height = $('#command-dialog .foldertab:first').outerHeight() + 5;
                }

                fm.animate($('#content'), { height : fm.height.content - message_height });
                fm.animate($contentframe, { height :  fm.height.content - toolbar_height - message_height - folder_height }, 'normal', function() {
                    $command_dialog.find('input[id="' + action + '_input"]').focus();
                    $command_dialog.find('.help').cluetip({
                        activation : 'click',
                        closePosition : 'title',
                        closeText: '<img src="' + fm.config.image_url + '/icons/close.gif" alt="Close" />',
                        width : 400,
                        height : 300,
                        sticky : true,
                        arrows : false
                    });
                });          
            });
        });
        this.showStatus(this.languages[action] || action);
    }

    if (!$contentheader.is(':hidden')) {
        this.fadeOut($('#cmd-' + this.current.command), function() {
            fm.animate($("#ocwrapper"), {
                'margin-top' : 0,
                'height'     : fm.height.wrapper
            }, 'normal', function() {
                fm.animate($("#content"), { height: fm.height.content });
                $contentframe.css('height', fm.height.content - toolbar_height + 'px');

                fm.fadeOut($contentheader, function() {
                    $('#' + action + '_input').focus();
                });
            });
        });

        this.current.command = null;
        $('.primarynav a[rel]').parent().removeClass('selected');
    }
    else if (!html) {
        this.animate($("#content"), { height: fm.height.content });
        $contentframe.css('height', fm.height.content - toolbar_height + 'px');
    }

/* Reset form before display it */
    this.resetForm(action);

/* Show action form if applicated */
    if (this.current.action && this.current.action != 'delete') {
        this.fadeOut($('#cmd-' + this.current.action), function() {
            fm.fadeIn($('#cmd-' + action), function () {
                $('#' + action + '_input').focus();
            });
        });
    }
    else {
        this.fadeIn($('#cmd-' + action), function () {
            $('#' + action + '_input').focus();
        });
    }

/* Save the action */
    this.current.action = action;
    $('#cmd').val(action)
    this.form.find('input[name="confirm-name"]').val('');

    /* Handle specific action */
    if (this.current.action.search(/delete|perl|print/) == 0) {
        this.form.submit();
    }
    else if (this.current.action == 'chmod') {
        $('#cmd-chmod .checkbox').click(function() {
            fm.chmod();
        });

        /* Loading permission for a file if selected */
        var fselected = $('input[name="cinput"][checked]');
        if (fselected.length > 0) {
            var fname = fselected.length == 1 ? fselected.val() : $(fselected[0]).val();
            this.parsePerm(fname);
        }
    }
    else if (this.current.action == 'tail') {
        $('#' + this.current.action + '_input').val('25');
    }  
}

/*
  commandReponse method handles output of a command
  json: should be json data object
*/
FileMan.prototype.commandResponse = function(json) {
    var command = this.current.command || this.current.action;

    var fm = this;
    this.form.find('input[name="confirm-name"]').val('');
    if (command.search(/search|replace/) != -1) { /* The search command returns */
        this.paging.num_hits = json.data.hits;
        this.paging.size     = json.data.size;
        this.readme          = '';

        /* Displaying search results, paging, and status info */
        this.sort(json.data.files, this.paging.sb, this.paging.so);
        this.page(this.paging, function(nh) { fm.printFiles(nh); });

        if (json.success) this.showStatus();
        this.form.append('<input type="hidden" name="cmd-result" />'); 

        this.showMessage(json);
    }
    else if (json.data.confirm == 1 && json.data.file) {
        this.modalConfirm({
            html : 'Do you want to overwrite <b>' + json.data.file.name + '</b>?',
            yes : function($modal) {
                fm.form.append('<input type="hidden" name="overwrite_confirmed" value="1" />').submit();
                $modal.html('').jqmHide();
            },
            no : function($modal) {
                $modal.html('').jqmHide();
            }
        });
    }
    else if (command.search(/copy|move/) == 0) {
        this.copy(json);
    }
    else if (command == 'delete') {
        this.remove(json);
    }
    else if (command == 'print') {
        this.print(json);
    }
    else if (command == 'download') {
        if (json.success) {
            this.preview(json.data.file, 'download');
        }
        else {
            this.showMessage(json);
        }
    }
    else if (command == 'perl') {
        this.perl(json);
    }
    else if (command.search(/diff|tail/) == 0) {
        if (json.success) {
            this.showStatus(command);

            this.actionResponse('<pre>' + json.data.output + '</pre>');
            $('#' + command + '_input').focus();

            /* Handle refreshing for tail command if enabled */
            if (command == 'tail' && json.data.refresh > 0) {
                this.timerID = window.setTimeout(function() { fm.form.submit(); }, json.data.refresh * 1000);
            }
        }
        else {
            if (this.timerID) window.clearTimeOut(this.timerID);    
            this.showMessage(json);
        }
    }
    else if (command.search(/user/) == 0) {
        if (json.success == true) {
            this.actionDialog({ action : 'user', json : json });
        }
        else if (json.message) {
            this.showMessage(json);
            $('#user_action').val('');
        }
    }
    else if (command == 'logout') {
      this.login(json.data.html);
    }
    else {
        if (command == 'upload') $('#modal-dialog').jqm().jqmHide();
        if (json.success) {
            /* Overwrite preferences */
            if (command == 'preferences') {
                this.config.effect    = json.data.defaults.effect == 1 ? true : false;
                this.config.readme    = json.data.defaults.readme;
                this.paging.max_hits  = json.data.defaults.maxhits;
                this.paging.sb        = json.data.defaults.sb || 'name';
                this.paging.so        = json.data.defaults.so || 'asc';
            }

            var callback = this.fileEditor.callback;
            var edited   = this.fileEditor.beingEdited;
            var action_called = this.fileEditor.actionCalled;

            /* Re-load file list */
            this.fileEditor = new Object();

            if (action_called != true) {
                if (command == 'uncompress') this.commandDialog({ success : json.success, message : json.message, refresh : true });
                else this.cd(json);
                this.resetForm(command);
            }

            /* Excutive editor's callback if available */
            if (edited && typeof(callback) == 'function') {
                callback();
            }
        }
        else if (json.message) {
            this.showMessage(json);
        }        
    }
}

/* 
  actionResponse method handles displaying the result of actions that aren't requried 'submit' button hit
    (e.g.: delete, perl, print...)
  html : should be html code
*/
FileMan.prototype.actionResponse = function(html) {
    this.form.append('<input type="hidden" name="cmd-result" />');
    if ($('#command-dialog').length == 0) {
        var contentframe_height = this.height.content - this.height.toolbar + this.height.folder;
        this.fadeOut($('.paging'));
        this.fadeOut($('.readme'));
        this.fadeOut($('.foldertab'), function() { $(".contentframe").css('height', contentframe_height + 'px'); });
        $('.contentframe').append('<div id="command-dialog" class="hidden"></div>');
    }
    this.fadeIn($('#command-dialog').html(html));
}

/*
  actionForm method prints out a action form.
  action : should be an action
  args   : should be a hash of all parameters that are passed in.
*/
FileMan.prototype.actionForm = function(action, args) {
    var fm = this;

    this.printForm(action, function (response) {
        if (response.success) {
            fm.actionDialog({ action : action, json : response });
        }
        else if (response.message) {
            fm.showMessage(response);
        }
    }, args);
}

/* 
  uploadFiles : allows multiple files uploading
*/
FileMan.prototype.uploadFiles = function() {
    var $modal = $('#modal-dialog');
    var html   = '<form action="' + this.config.cgi_url + '" method="post"><input type="hidden" name="cmd" value="upload" />' + this.hiddens.hidden_objects +
        '<h1 class="clear"><img src="' + this.config.image_url + '/icons/close.gif" title="Close" class="close" /><span>Upload Files</span></h1>' +
        '<div class="modal-content"><input type="hidden" name="num_files" value="1" />' +
        '<div id="upfiles"><div class="row clear"><label class="name">File Name</label>' +
        '<div class="value"><input type="file" name="file-1" size="40" value="" class="file" />&nbsp;<select name="mode-1" title="Upload mode"><option value="auto">Auto</option>' +
        '<option value="ascii">ASCII</option><option value="binary">Binary</option></select></div></div></div>' +
        '<div class="row upload-more"><a href="#" rel="addfile" class="addfile" alt="Add More Files">Add More Files</a>' +
        '<input type="checkbox" id="overwrite" name="opt_overwrite" value="1" /> <label for="overwrite">Overwrite Existing Files</label></div>' +
        '<div class="buttons"><input type="submit" name="button-upload" value="Upload" class="submit" /></div>' +
        '</div></form>';

    var mwidth = 650;
    var mleft  = parseInt(($(window).width() - mwidth) / 2);
    $modal.jqm().removeClass().addClass('modal-dialog modal-dialog-form')
        .css('width', mwidth + 'px').css('left', mleft + 'px').css('top', '20%')
        .html(html).jqmShow();

    var fm = this;
    $modal.find('a[rel="addfile"]').click(function() {
        var uploads = $modal.find('input[type="file"]');
        if (uploads.length == fm.config.max_upload) return false;
        if (uploads.length < fm.config.max_upload) {
            $('#upfiles').append('<div class="row clear"><label class="name">File Name</label><div class="value"><input type="file" name="file-' + (uploads.length + 1) + '" size="40" class="file" value="" /> <select name="mode-' + (uploads.length + 1) + '" title="Upload mode"><option value="auto">Auto</option>' +
                '<option value="ascii">ASCII</option><option value="binary">Binary</option></select></div></div>');
            $modal.find('input[name="num_files"]').val(uploads.length + 1);
        }
        return false;
    });

    $modal.find('.close').css('cursor', 'pointer').click(function() { $modal.html('').jqmHide(); });

    var form = $modal.find('form');
    form.submit(function() {
        $(this).hide();
        fm.upload(true);
    });

    form.ajaxForm({
        dataType : 'json',
        success : function(response) { fm.commandResponse(response); }
    });

    return false;
}

/*
  upload command 
*/
FileMan.prototype.upload = function(multiple) {
    var $modal = $('#modal-dialog');
    var fm     = this;
    $modal.jqm({
        onHide : function(hash) { 
            if (fm.timerID > 0) {
                window.clearTimeout(fm.timerID);
                fm.timerID = 0;
            }
            $modal.find('.done').css('width', fm.config.uploadmax_width + 'px');
            hash.w.fadeOut('fast',function() { hash.o.remove(); });
        }
    }).removeClass().addClass('modal-dialog upload-dialog').css('width', this.config.uploadmax_width + 25 + 'px').css('top', '40%').css('left', '35%');

    var html = '<div class="modal-content clear">' +
        '<div class="meter-filename">&nbsp;</div>' +
        '<div class="meter-bar" style="width: ' + (fm.config.uploadmax_width + 1) + 'px;"><div class="done"></div></div>' +
        '<div class="meter-info">Starting...</div>' +
        '</div>';

    this.config.serial = randomString();
    if (multiple) {
        $modal.append(html).jqmShow();
        $modal.find('form').attr('action', this.config.cgi_url + '?serial=' + this.config.serial).attr('enctype', 'multipart/form-data');
    }
    else {
        $modal.html(html).jqmShow();
        this.form.attr('action', this.config.cgi_url + '?serial=' + this.config.serial).attr('enctype', 'multipart/form-data');
    }

    if (this.timerID > 0) {
        window.clearTimeout(fm.timerID);
        this.timerID = 0;
    }
    this.timerID = window.setTimeout(function() { fm.uploadProgress(); }, 500);
}

/*
  uploadProgress method
  This method handles upload progress
*/
FileMan.prototype.uploadProgress = function() {
    var $modal = $('#modal-dialog');
    var fm     = this;
    this.printForm('upload', function(response) {
        if (response.status == 'ERR_NOAUTH') {
            fm.login(response.data.html);
        }
        else if (response.success) {
            var uploaded     = response.data.uploaded;
            var upload_size  = response.data.upload_size;
            var elapsed_time = response.data.elapsed_time;
            var filename     = response.data.filename;
            var allowed_space= response.data.allowed_space;
            var free_space   = response.data.free_space;

            if ($modal.find('#uploaded').length == 0) {
                $modal.find('.meter-info').empty().html('Uploading...<span id="uploaded"></span> of <span id="upload-size"></span> at <span id="upload-speed">0</span> KB/sec; <span id="remain">00:00:00</span> remain');
                if (allowed_space > 0 && free_space > upload_size) {
                    $modal.jqmHide();
                    window.clearTimeout(fm.timerID);
                    fm.timerID = 0;
                    fm.showMessage({ message : 'NO_SPACE', success : false });
                    return;
                }
            }

            if (fm.cdata.upload_filename != filename) {
                $modal.find('.meter-filename').html(filename);
                fm.cdata.upload_filename = filename;
            }

            var percentage = upload_size > 0 ? Math.ceil((uploaded / upload_size) * 100) : 0;
            if (fm.cdata.uploaded == uploaded) {
                percentage = 100;
                $modal.find('.done').css('width', fm.config.uploadmax_width + 'px');
            }
            else {
                var done_width = parseInt(percentage * fm.config.uploadmax_width / 100);
                if (done_width > 0) $modal.find('.done').css('width', done_width + 'px');
            }

            var speed  = elapsed_time > 0 ? (uploaded / elapsed_time) : 0;
            var time   = parseInt((elapsed_time * 100) / percentage);
            var remain = eval(time - elapsed_time);

            if (percentage == 100) {
                window.clearTimeout(fm.timerID);
                fm.timerID = 0;
                $modal.find('.meter-info').empty().html('Copying...');
            }
            else {
                $modal.find('#uploaded').html(friendly_size(uploaded));
                $modal.find('#upload-size').html(friendly_size(upload_size));
                $modal.find('#upload-speed').html(friendly_size(speed, 1, upload_size));
                $modal.find('#remain').html(format_time(remain));

                fm.cdata.uploaded = uploaded;
                fm.timerID = window.setTimeout(function() { fm.uploadProgress(); }, 500);
            }
        }
    }, { upload : this.config.serial });
}

/* Download command */
FileMan.prototype.download = function() {
    var file = $('.foldertab input[name="cinput"][checked]');
    if (file.length == 0) {
        this.showMessage({ success : false, message : "No File was selected." });
    }
    else if (file.length > 1 && $('#cmd-download select[name="download_compress"]').val() == 0) {
        this.showMessage({ success : false, message : 'No mode was selected.' });
    } 
}

/*
  Perl command
*/
FileMan.prototype.perl = function(json) {
    this.resetCommand();

    if (json.success) {
        this.showStatus('perl');

        var html = '<pre>';
        for (var i=0; i<json.data.files.length; i++) {
            var message = json.data.files[i].message || json.data.files[i].error;
            var cname   = json.data.files[i].error ? 'error' : 'message';
            html += '<p><b>' + htmlEscape(json.data.files[i].name) + '</b>\n<span class="' + cname + '">' +  message + '</span></p>';
        }
        html += '</pre>';
        this.actionResponse(html);
    }
    else {
        this.showMessage(json);
    }
}

/* 
  hideMessage method: which does hide the message bar
*/
FileMan.prototype.hideMessage = function() {
    var $contentframe   = $('#command-dialog .contentframe').length > 0 ? $('#command-dialog .contentframe') : $('.contentframe');
    var command_height  = $('#contentheader').is(':hidden') ? 0 : $('#contentheader').height();
    var toolbar_height  = this.height.toolbar - ($('#command-dialog .contentframe').length > 0 ? this.height.folder : 0);
    var command         = this.current.command || this.current.action;

    var fm = this;
    this.slideUp($('#contentmessage').stopTime('msgtimer'));
    this.animate($("#ocwrapper"), {
        'margin-top' : command_height,
        'height'     : this.height.wrapper - command_height
    }, 'normal', function() {
        $("#content").css('height', fm.height.content  - command_height + 'px');
        $contentframe.css('height', fm.height.content - toolbar_height - command_height + 'px');
        $('#' + command + '_input').focus();
    });
}

/*
  showMessage method which shows message bar
  args: should be a hash as { message : 'blah', success : true/fase }
*/
FileMan.prototype.showMessage = function(args) {
    var success          = args.success;
    var message          = args.message;
    var $content_message = $('#contentmessage');
    var $content         = $('#content');
    var $contentframe    = $('#command-dialog .contentframe').length > 0 ? $('#command-dialog .contentframe') : $('.contentframe');
    var command          = this.current.command || this.current.action;
    var fm               = this;
    var commnand         = this.current.command || this.current.action;
    
    $content_message.stopTime('msgtimer');  
    if ($content_message.is(':hidden')) {
        this.animate($contentframe, {
            height : $contentframe.height() - this.height.contentmessage
        }, 'normal', function() {
            fm.animate($content, {
                height : $content.height() - fm.height.contentmessage - 2
            }, 'normal', function() {
                $content_message.removeClass(success ? 'error' : 'message').addClass(success ? 'message' : 'error').text(message);
                fm.slideDown($content_message, function() {
                    if (!success) $('#' + command + '_input').focus();
                });
            });  
        });

        if (!success) $content_message.oneTime(5000, 'msgtimer', function() { fm.hideMessage(); });
    }
    else {
        $content_message.removeClass(success ? 'error' : 'message').addClass(success ? 'message' : 'error').text(message);
        if (!success) $content_message.oneTime(5000, 'msgtimer', function() { fm.hideMessage(); });
    }
}

/*
  Print command
*/
FileMan.prototype.print = function(json) {
    if (json.success) {
        var files = json.data.files;
        var url   = this.config.cgi_url + '?cmd=print;print=1' + this.hiddens.hidden_query;
        var fm    = this;
        for (var i=0; i<files.length; i++) {
            url += ';cinput=' + files[i].name;
        }

        var width  = 650;
        var height = screen.height - 300;
        var attrs  = 'width=' + width + ',height=' + height + ',left=200,top=' + (parseInt((this.screen.height - height) / 2)) + ',scrollbars=yes';
        if (files.length == 1) {
            var w = window.open(url, 'print', attrs);
        }
        else {
            this.modalConfirm({
                html : "You've selected multiple files. Do you want to print all as one file? Otherwise, press 'No' to print each file individually.",
                yes : function($modal) {
                    fm.resetCommand();
                    $modal.html('').jqmHide();
                    var w = window.open(url + ';all=1', 'print', attrs);
                },
                no : function($modal) {
                    fm.resetCommand();
                    $modal.html('').jqmHide();
                    var w = window.open(url, 'print', attrs);
                },
                cancel : function($modal) {
                    fm.resetCommand();
                    $modal.html('').jqmHide();
                }
            });
        }
        this.resetCommand();
    }
    else {
        $('#modal-dialog').html('').jqm().jqmHide();
        this.resetCommand();
        this.showMessage(json);
    }
}

/* Delete command */
FileMan.prototype.remove = function(json) {
    if (json.success && json.data.confirms && json.data.confirms.length > 0) {
        var count    = 0;
        var confirms = json.data.confirms;
        var fm       = this;

        /* Print out the confirmation modal dialog */
        this.modalConfirm({
            data : json.data,
            del  : true,
            html : 'Do you want to delete <b><span id="confirm-name">' + confirms[0] + '</span></b>',
            yes  : function($modal) {
                $modal.find('input[name="confirm-name"]').val(confirms[count]);
                $modal.find('form').submit();
            },
            all  : function($modal) {
                $modal.find('input[name="confirm-name"]').val('delete-all');
                $modal.find('form').submit();
            },
            skip : function($modal) {
            /* Remove file from the list */
                $modal.find('input[name="cinput"][value="' + confirms[count] + '"]').remove();

                count++;
                if (count == confirms.length) {
                    if (json.data.num_done > 0) {
                        $modal.find('input[name="confirm-name"]').val('button-skip');
                        $modal.find('form').submit();
                    }
                    else {
                        fm.resetCommand();
                        $modal.html('').jqmHide();
                    }
                }
                else {
                    $modal.find('#confirm-name').html(confirms[count]);
                    $modal.find('input[name="confirm-name"]').val(confirms[count]);
                }
            },
            cancel : function($modal) {
                 if (json.data.num_done > 0) {
                     $modal.find('input[name="confirm-name"]').val('button-cancel');
                     $modal.find('form').submit();
                 }
                 else {
                     fm.resetCommand();
                     $modal.html('').jqmHide();
                 }
            }
        });    
    }
    else {
        /* Hide the modal dialog if visible */
        $('#modal-dialog').html('').jqm().jqmHide();
        if (json.success) {
            this.resetCommand();
            this.cd(json);
        }
        else {
            this.showMessage(json);
        }
    }
}

/* Copy/Move command */
FileMan.prototype.copy = function(json) {
    var command = this.current.command || this.current.action;

    /* Need to confirm on overwrite existing files */
    if (json.success && json.data.confirms && json.data.confirms.length > 0) {
        var count    = 0;
        var confirms = json.data.confirms;
        var fm       = this;

        /* Print out the confirmation modal dialog */
        this.modalConfirm({
            data : json.data,
            html : 'Do you want to overwrite <b><span id="confirm-name">' + confirms[0] + '</span></b>',
            yes  : function($modal) {
                $modal.find('input[name="confirm-name"]').val(confirms[count]);
                $modal.find('form').submit();
            },
            all : function($modal) {
                $modal.find('input[name="confirm-name"]').val('copy-all');
                $modal.find('form').submit();
            },
            skip : function($modal) {
                /* Remove file from the list */
                $modal.find('input[name="cinput"][value="' + confirms[count] + '"]').remove();

                count++;
                if (count == confirms.length) {
                    if (json.data.num_done > 0) {
                        $modal.find('input[name="confirm-name"]').val('button-skip');
                        $modal.find('form').submit();
                    }
                    else {
                        $modal.html('').jqmHide();
                    }
                }
                else {
                    $modal.find('#confirm-name').html(confirms[count]);
                    $modal.find('input[name="confirm-name"]').val(confirms[count]);
                }
            },
            cancel : function($modal) {
                 if (json.data.num_done > 0) {
                     $modal.find('input[name="confirm-name"]').val('button-cancel');
                     $modal.find('form').submit();
                 }
                 else {
                     $modal.html('').jqmHide();
                 }
             }
        });
    }
    else {
        /* Hide the modal dialog if visible */
        $('#modal-dialog').html('').jqm().jqmHide();

        /* Reset values */
        if (json.success) {
            this.cd(json);
            $('#' + command + '_input').val('').focus();
        }
        else {
            this.showMessage(json);
        }
    }
}

/*
  The command command
*/
FileMan.prototype.command = function() {
    this.config.serial = randomString();
    $('#serial').val(this.config.serial);

    if (this.timerID > 0) {
        window.clearTimeout(this.timerID);
        this.timerID = 0;
    }

    var fm      = this;
    var longrun = $('#opt_long').attr('checked') ? true : false;
    this.timerID = window.setTimeout(
        function() {
            fm.commandProgress(fm.config.serial, ';command_input=' + $('#command_input').val() + (longrun ? ';long=1' : ''));
        }, (longrun ? 80 : 100)
    );
}

/*
  commandProgress method handles command output
  randome_str : should be a unique string 
  input : should be a string of command inputs
*/
FileMan.prototype.commandProgress = function(random_str, input) {
    var fm = this; var flag = true;
    var $first_prompt = $('#command-dialog span[class="prompt"]:first');
    if ($('#' + random_str).length == 0) {
        $first_prompt.after('<div><span id="cmd-' + random_str + '"></span></div><div id="' + random_str + '"></div>');
    }
    else {
        flag = false;
    }
    $.ajax({
        type : 'GET',
        url : this.config.cgi_url + '?cmd=command' + input + (this.working_dir ? ';working_dir=' + this.working_dir : '') + ';serial=' + this.config.serial + ';retrieve=1;ajax=1' + this.hiddens.hidden_query,
        dataType : 'xml',
        cache : false,
        success : function(response, tstatus) {
            var prompt  = response.getElementsByTagName('prompt')[0].firstChild.nodeValue;
            var next_prompt  = response.getElementsByTagName('next_prompt')[0].firstChild.nodeValue;
            var command = response.getElementsByTagName('command')[0].firstChild.nodeValue;
            var output  = response.getElementsByTagName('output')[0].firstChild.nodeValue;
            fm.working_dir = response.getElementsByTagName('working')[0].firstChild.nodeValue;
            $('#cmd-command input[name="working_dir"]').val(fm.working_dir);

            if (flag) {
                $('#command_input').val('').focus();
                $('#cmd-' + random_str).html('<span class="prompt">' + htmlEscape(prompt) + ' </span> ' + htmlEscape(command));
            }
            if (next_prompt != $first_prompt.html()) $first_prompt.html(htmlEscape(next_prompt));

            if (output.search(/timeout|done/) > -1) {
                output = output.replace(/done/, '');
                $('#' + random_str).html('<pre>' + htmlEscape(output) + '</pre>');

                /* Clear timer ID */
                window.clearTimeout(fm.timerID);
                fm.timerID = 0;
                $.ajax({
                    type : 'GET',
                    dataType : 'xml',
                    cache : false,
                    url  : fm.config.cgi_url + '?cmd=command;serial=' + fm.config.serial + ';remove=1;ajax=1' + fm.hiddens.hidden_query
                });
            }
            else {
                $('#' + random_str).html('<pre>' + output + '</pre>');
                fm.timerID = window.setTimeout(function() { fm.commandProgress(random_str, input); }, 500);
            }
        }
    });
}

/*
  List information about the files of a directory
  args : should be a hash of all options
  func : should be a callback function.
*/
FileMan.prototype.ls = function(args, func) {
  if (!args) args = new Object();
  var dname = args.dname || '';
  var html  = '<form id="tmpform" action="' + this.config.cgi_url + '" method="post" class="hide">' +
    '<input type="hidden" name="cmd" value="cd" /><input type="hidden" name="ajax" value="1" />' +
    '<input type="hidden" name="f" value="' + dname +'" />' + (args.hidden_objects || this.hiddens.hidden_objects) + '</form>';

  var $form = $('#cdbar').append(html).find('#tmpform');
  if (args.breadcrumbs) $form.find('input[name="work_path"]').val('');

  var params = new Array('load_default', 'filter', 'a');
  for (var i=0; i<params.length; i++) {
    if (args[params[i]]) $form.append('<input type="hidden" name="' + params[i] + '" value="' + args[params[i]] + '" />');
  }

  var fm = this;
  $form.submit(function() {
      $(this).ajaxSubmit({
          dataType : 'json',
          success  : function(response) {
              if (response.status == 'ERR_NOAUTH') {
                fm.login(response.data.html);
              }
              else if (typeof(func) == 'function') {
                func(response);
              }
              $form.remove();
          }
      });
      return false;
  });
  $form.submit();
}

FileMan.prototype.loading = function(action) {
    if (action == 'start') {
        var fm     = this;
        this.timer = true;
        $(document).oneTime(this.config.timer, 'waitingtimer', function() {
            if (!fm.timer) return;
            var mwidth = 16;
            var mleft  = parseInt((fm.screen.width - mwidth) / 2);
            $('#waiting-dialog').jqm().removeClass().addClass('modal-dialog modal-waiting')
                .css('width', mwidth + 'px').css('left', mleft + 'px').css('top', '40%')
                .html('<img src="' + fm.config.image_url + '/waiting.gif" title="waiting" />').jqmShow();
        });
    }
    else {
        this.timer = false;
        if (!$('#waiting-dialog').is(':hidden')) $('#waiting-dialog').html('').jqmHide();
    }
}
/*
  cd command
  args : should be a hash of
    dname : should be directory name where you want to cd to
    breadcrumbs : should be true/false. work_path will be set to null if it's true
    work_path : should be true/false
*/
FileMan.prototype.cd = function(args) {
    if (!args) args = new Object();

    this.loading('start');
    var success = args.success;
    var fm = this;
    this.ls(args, function(response) {
        if (response.success) {
            fm.paging.num_hits     = response.data.hits;
            fm.paging.size         = response.data.size;
            fm.paging.current_page = 1;
            fm.hiddens             = response.data.hiddens;
            fm.readme              = response.data.readme_content;

            if (response.data.root_path) fm.config.root_path = response.data.root_path;
            $('#hiddens').empty().append(fm.hiddens.hidden_objects);

            if (response.data.paths) {         
                fm.paths  = response.data.paths.loop;
                fm.parent = response.data.paths.parent;
                fm.config.work_path = response.data.paths.work_path;
            }
            else {
                fm.paths  = new Array();
                fm.parent = '';
                fm.config.work_path = '/';
            }

            /* Print out the list of files, sorting, bread crumbs, paging */
            fm.sort(response.data.files, fm.paging.sb, fm.paging.so);
            fm.breadCrumbs();
            fm.page(fm.paging, function(nh) { fm.printFiles(nh); });
            fm.showStatus();

            $('#cdform input[name="dname"]').focus();   

            if ($('#listfiles').is(':hidden') || $('.foldertab').is(':hidden')) {
                fm.commandDialog(args);
            }
            else if (!success && !$('#contentmessage').is(':hidden')) {
                fm.hideMessage();
            }
            else if (success) {
                fm.showMessage(args);
            }

            fm.htaccess(response.data.htaccess_users);
        }
        else {
            fm.showMessage(response);
        }
       fm.loading('end');
    });
}

/*
  modalConfirm show a modal confirm dialog
  args : should be a hash of all actions
  e.g. 
  object.modalConfirm({
    data : 'json data object',
    yes : function($modal) {
      Do something here..
    },
    no : function($modal) {
      blah blah..
    }
    ....
  });
*/
FileMan.prototype.modalConfirm = function(args) {
    var $modal  = $('#modal-dialog');
    var html    = '<form action="' + this.config.cgi_url + '" method="post"><input type="hidden" name="cmd" value="' + (this.current.command || this.current.action)+ '" />' +
        '<input type="hidden" name="confirm-name" value="" />' + this.hiddens.hidden_objects +
        '<h1 class="clear"><img src="' + this.config.image_url + '/icons/close.gif" title="Close" class="close" /><span>Confirmation</span></h1>' +
        '<div class="modal-content"><p>' + args.html + '</p><p>';

    if (args.data) {
        for (var i=0; i<args.data.confirms.length; i++) {
            html += '<input type="hidden" name="cinput" value="' + args.data.confirms[i] + '" />\n';
        }
        html += '<input type="hidden" name="num_done" value="' + args.data.num_done + '" />\n';
        if (args.data.input) html += '<input type="hidden" name="' + this.current.action + '_input" value="' + args.data.input + '" />\n';
    }
    html += '</p><div class="buttons">'
    if (args.yes)    html += '<input type="button" name="button-yes" value="Yes" class="submit" />\n';
    if (args.all)    html += '<input type="button" name="button-all" value="' + (args.del ? 'Delete All' : 'Overwrite All') + '"  class="submit" />\n';
    if (args.skip)   html += '<input type="button" name="button-skip" value="Skip" class="submit" />\n';
    if (args.no)     html += '<input type="button" name="button-no" value="No" class="submit" />\n';
    if (args.cancel) html += '<input type="button" name="button-cancel" value="Cancel" class="submit" />\n';

    html += '</div></div></form>';

    var nwidth = 400;
    var nleft  = parseInt($(window).width() - nwidth) /2;
    $modal.jqm().removeClass().addClass('modal-dialog modal-dialog-form modal-confirm')
        .css('left', nleft + 'px').css('top', '30%').css('width', nwidth + 'px')
        .html(html).jqmShow().find('input[type="button"]').click(function() {
        var name = $(this).attr('name');
        if (name == 'button-yes' && typeof(args.yes) == 'function') args.yes($modal);
        else if (name == 'button-all' && typeof(args.all) == 'function') args.all($modal);
        else if (name == 'button-skip' && typeof(args.skip) == 'function') args.skip($modal);
        else if (name == 'button-no' && typeof(args.no) == 'function') args.no($modal);
        else if (name == 'button-cancel' && typeof(args.cancel) == 'function') args.cancel($modal);
    });
    var fm = this;

    $modal.find('h1 img').css('cursor', 'pointer').click(function() { 
        $('select[class="action"]').val('');
        fm.current.action = '';
        $modal.jqmHide();
    });

    $modal.find('form').ajaxForm({
        dataType: 'json',
        success : function(data) {
            fm.commandResponse(data);
        }
    });
}

/*
  printFiles method handles files listing
  nh : should be a page number
*/
FileMan.prototype.printFiles = function(nh) {
    if (typeof(nh) == 'undefined') nh = 1;

    var beg   = nh == 1 ? 0 : ((nh - 1) * this.paging.max_hits);
    var $body = $('.contentframe table[class="foldertab"]');
    $body.empty();
    $('.readme').remove();

    var count = 0;
    var array = '';
    var maps  = this.maps;

    /* Print out parent link */
    if (this.parent != '') {
        var tr = '<tr><td class="selectbox">&nbsp;<\/td>' +
            '<td class="icon"><div class="icon-uplevel"><a href="#" rel="' + this.parent + '" class="icon-linkable link-uplevel">File Folder<\/a><\/div><\/td>' +
            '<td class="name"><a href="#" rel="' + this.parent + '" title="Up One Level" class="link-uplevel">..<\/a><\/td>' +
            '<td class="size">&nbsp;<\/td>' +
            '<td class="type">&nbsp;<\/td>' +
            '<td class="modified">&nbsp;<\/td>' +
            '<td class="owner">&nbsp;<\/td>';

        tr += this.config.is_win
            ? '<\/tr>\n<tr class="spacer"><td colspan="7"><\/td></tr>\n>'
            : '<td class="permission">&nbsp;<\/td><\/tr>\n<tr class="spacer"><td colspan="8"><\/td></tr>\n';

        $body.append(tr);

        $('.link-uplevel').each(function() {
            var link = $(this);
            link.click(function() {
                fm.cd({ dname : link.attr('rel') });
                return false;
            });
        });
    }

    /* Print out a empty page */
    if (this.files.length == 0) {
        $('#fm_action').attr('disabled', true);
        $('#checkall').attr('disabled', true);
        $body.append('<tr><td colspan="' + (this.config.is_win ? 7 : 8) + '" class="empty">No files were found!<\/td><\/tr>');
    }
    else {
        $('#fm_action').attr('disabled', '');
        $('#checkall').attr('disabled', '');

        /* Print files of page n */
        for (var i=beg; i<this.files.length; i++) {
            if (count == this.paging.max_hits) break;
            var desc = this.files[i][maps.desc] == 'Symlink' ? 'Symlink: ' + this.files[i][maps.full_path] : this.files[i][maps.desc];
            var path = '';

            if (this.files[i][maps.path] != '') path = this.files[i][maps.path] + '/';
            var tr = '<tr><td class="selectbox"><input type="checkbox" id="cinput-' + i + '" name="cinput" value="' + path + this.files[i][maps.name] + '" onclick="" \/><\/td>' +
                '<td class="icon"><div class="icon-' + this.files[i][maps.icon] + '"><a href="#" rel="' + path + this.files[i][maps.name] + '" title="'+ desc + '" class="icon-linkable ' + (this.files[i][maps.type] == 1 ? 'link-folder' : 'link-file') + '">File Folder<\/a><\/div><\/td>' +
                '<td class="name"><a href="#" rel="' + path + this.files[i][maps.name] + '" title="' + path + this.files[i][maps.name] + '" class="' + (this.files[i][maps.type] == 1 ? 'link-folder' : 'link-file') + '">' + this.files[i][maps.name] + '<\/a><\/td>' +
                '<td class="size">' + (this.files[i][maps.type] == 1 ? '&nbsp' : friendly_size(this.files[i][maps.size])) + '<\/td>' +
                '<td class="type">' + this.files[i][maps.desc] + '<\/td>' +
                '<td class="modified">' + this.files[i][maps.sdate] + '<\/td>';                

            tr += this.config.is_win
                ? '</tr>\n<tr class="spacer"><td colspan="6"><\/td><\/tr>\n'
                : '<td class="owner">' + this.files[i][maps.owner] + '<\/td><td class="permission"><a href="#" rel="' + this.files[i][maps.name] + '" title="Permission">' + this.files[i][maps.sperm] + '<\/a><\/td><\/tr>\n<tr class="spacer"><td colspan="8"><\/td><\/tr>\n';

            $body.append(tr);
            count++;
        }
    }

    /* display README content if enabled */
    if (this.readme != '') {
        if (this.config.readme == 2) {
            $body.after('<div class="readme"><h1>README\'s content</h1><pre>\n' + this.readme + '</pre></div>');
        }
        else if (this.config.readme == 1) {
            $body.before('<pre class="readme"><b>README\'s content</b>\n' + this.readme + '</pre>');
        }
    }

    /* Set an action for File Folder icons/links */
    var fm = this;
    $('.link-folder[rel]').each(function() {
        var link = $(this);
        link.click(function() {
          fm.cd({ dname : link.attr('rel') });
          return false;
        });
    });

    /* Set an action for File icons */
    $('.icon').find('.link-file[rel]').each(function() {
        var link = $(this);
        link.click(function() {
            fm.printForm('preview', function (response) {
                if (response.success) {
                    fm.preview(response.data.file);
                }
                else {
                    fm.showMessage(response);
                }
            }, { f : link.attr('rel') });
            return false;
        });
    });

    /* Set an action for File links */
    $('.name').find('.link-file[rel]').each(function() {
        var link = $(this);
        link.click(function() {
            fm.loading('start');
            fm.form.find('input[name="cmd-result"]').remove();
            fm.printForm('edit', function(response) {
                if (response.success) {
                    if (response.data.compressed == 1) {
                        fm.actionDialog({ action : 'uncompress', json : response });
                    }
                    else if (response.data.file) {
                        fm.preview(response.data.file);
                    }
                    else {
                        fm.editor('edit', link.attr('rel'), response.data.type, response.data.html);
                    }
                }
                else {
                    fm.showMessage(response);
                }

                fm.loading('end');
            }, { f : link.attr('rel') });
            return false;
        });
    });

    /* Set an action for permission links */
    $('td[class="permission"]').find('a[rel]').each(function() {
        var link = $(this);
        link.click(function() { 
          fm.parsePerm(link.attr('rel'));
          return false;
        });
    });

    /* Print out the sorting image */
    $('.foldertab th a[rel] img').remove();
    $('.foldertab th a[rel="' + this.paging.sb + '"]').append(' <img src="' + this.config.image_url + '/icons/' + (this.paging.so == 'desc' ? 'descending.gif' : 'ascending.gif') + '" title="' + (this.paging.so == 'desc' ? 'V' : '^') + '" \/>');

    /* Set actions for checkboxes */
    var $foldertab = $('.foldertab');
    $foldertab.find('input[name="checkall"]').attr('checked', false);

    $foldertab.find('input[type="checkbox"]').each(function() {
        $(this).change(function() {
            if ($(this).val() == 'checkall') {
                $foldertab.find('input[type="checkbox"]').attr('checked', $(this).attr('checked') ? true : false);
            }
            else {
                var flag = true;
                var fname; var selected = 0;
                $foldertab.find('input[name="cinput"]').each(function() {
                    if ($(this).attr('checked')) {
                      selected++;
                      fname = $(this).val();
                    }
                    else {
                      flag = false;
                    }
                });
                if (selected == 1 && fm.current.action == 'chmod') fm.parsePerm(fname);
                $foldertab.find('input[name="checkall"]').attr('checked', flag);
            }
            fm.fileStats();
        });
    });
}

/*
  sort method handle sorting files
  source : should be an array
  sb : sort by column index
  so : sort order. It should be asc/desc
*/
FileMan.prototype.sort = function(source, sb, so) {
    this.paging.current_page = 1;
    if (typeof(source) == 'undefined') return;
    if (typeof(source) == 'object' || source.length > 0) {

        /* Need to seperate folders and files before sorting */
        var afolders = new Array(); var afiles = new Array();
        var maps     = this.maps;
        for (var i=0; i<source.length; i++) {
            if (source[i][maps.type] == 1) afolders.push(source[i]);
            else afiles.push(source[i]);
        }

        if (afolders.length > 0) afolders.qsort(0, afolders.length, maps[sb], so);
        if (afiles.length > 0) afiles.qsort(0, afiles.length, maps[sb], so);

        if (so == 'desc') {
            for (var i=0; i<afolders.length; i++) {
                afiles.push(afolders[i]);
            }
            this.files = afiles;
        }
        else {
            for (var i=0; i<afiles.length; i++) {
                afolders.push(afiles[i]);
            }
            this.files = afolders;
        }
    }
    this.printFiles();
}

/*
  page method handles paging
*/
FileMan.prototype.page = function(paging, action) {
    var paging = new page({
        image_url : this.config.image_url,
        paging    : paging,
        action    : action
    }, $('.toolbar div[class="paging"]'));
}

/*
  Print files and size of selected files
*/
FileMan.prototype.fileStats = function(args) {
    var nh      = this.paging.current_page;
    var mh      = this.paging.max_hits;
    var files   = this.files;
    var maps    = this.maps;

    if (args) {
        $inputs = args.inputs;
        nh      = args.nh;
        files   = args.files;
    }

    var beg = nh == 1 ? 0 : ((nh - 1) * mh);
    var selected = 0; var size = 0; var fm = this; var fname;
    $('.foldertab input[name="cinput"]').each(function() {
        if ($(this).val() != 'checkall' && $(this).attr('checked')) {
            fname = $(this).val();
            selected++;
            var count = 0;
            for (var i=beg;i<files.length; i++) {
                if (count == mh) break;
                if ($(this).val() == files[i][maps.name]) {
                    size += files[i][maps.size];
                    break;
                }
                count++;
            }
        }
    });

    $('#contentfooter .status').html('Selected <span>' + selected + '</span> files, <span>' + friendly_size(size) + '</span>');
}

/* Create path bread-crumbs */
FileMan.prototype.breadCrumbs = function() {
    var bread_crumbs = '<a href="#" rel="/" class="root">' + ($('#uaccess').length > 0 ? (this.config.root_path + '<\/a>') : ('Root<\/a>: '));
    for (var i=0; i<this.paths.length; i++) {
        bread_crumbs += '/<a href="#" rel="' + (this.paths[i].path != '' ? (this.paths[i].path + '/') : '') + this.paths[i].folder + '">' + this.paths[i].folder + '<\/a>';
    }
    $('#bread-crumbs').html(bread_crumbs);

    var fm = this;
    $('#bread-crumbs a[rel]').each(function() {
        var link = $(this);
        link.click(function() {
            fm.cd({ dname: link.attr('rel'), breadcrumbs : true });
            return false;
        });
    });
}

/* Reset command variables */
FileMan.prototype.resetCommand = function() {
    this.current.command = null;
    this.current.action  = null;
    $('#cmd').val('');
    $('#fm_action').attr('selectedIndex', 0);
}

/* resetForm method: reset all inputs */
FileMan.prototype.resetForm = function(command) {
  $('#cmd-' + command + ' *').each(function() {
    var type = $(this).attr('type');
    if (type && type.search(/text|password|file/) == 0) $(this).val('');
    else if (type == 'checkbox' || type == 'radio') $(this).attr('checked', false);
    else if (this.tagName == 'SELECT') $(this).attr('selectedIndex', 0);
  });
  if (command == 'upload') document.getElementById('myform').reset();
}

/* showStatus method */
FileMan.prototype.showStatus = function(status) {
    var contentfooter = $('#contentfooter');
    if (status) {
        contentfooter.find('.status').html(status);
        contentfooter.find('.summary').addClass('hide');
    }
    else {
        this.fileStats();
        contentfooter.find('.summary').removeClass().addClass('summary').html('Total <span>' + this.paging.num_hits + '</span> files, <span>' + friendly_size(this.paging.size) + '</span>');
    }
}

/* 
  parsePerm method gets permission info of a file
  fname : should be filename
*/
FileMan.prototype.parsePerm = function(fname) {
    $('#fm_action').val('chmod').change();

    /* Loading file info */
    var beg   = this.paging.current_page == 1 ? 0 : ((this.paging.current_page - 1) * this.paging.max_hits);
    var count = 0;
    var file  = new Array();
    for (var i=beg; i<this.files.length; i++) {
        if (count == this.paging.max_hits) break;

        if (fname == this.files[i][this.maps.name]) file = this.files[i];
        count++;
    }
    if (file.length == 0) return;

    /* Check the selected file and print out permissions */
    $('.foldertab input[type="checkbox"]').attr('checked', false);
    $('input[name="cinput"][value="' + fname + '"]').attr('checked', true)

    var sperm = file[this.maps.sperm];
    if (sperm.length >= 16) {
        $('#ar').attr('checked', sperm.substr(0,1) == 'r' ? true : false);
        $('#aw').attr('checked', sperm.substr(1,1) == 'w' ? true : false);
        $('#ax').attr('checked', sperm.substr(2,1) == 'x' ? true : false);
        $('#ur').attr('checked', sperm.substr(4,1) == 'r' ? true : false);
        $('#uw').attr('checked', sperm.substr(5,1) == 'w' ? true : false);
        $('#ux').attr('checked', sperm.substr(6,1) == 'x' ? true : false);
        $('#gr').attr('checked', sperm.substr(8,1) == 'r' ? true : false);
        $('#gw').attr('checked', sperm.substr(9,1) == 'w' ? true : false);
        $('#gx').attr('checked', sperm.substr(10,1) == 'x' ? true : false);
        $('#or').attr('checked', sperm.substr(12,1) == 'r' ? true : false);
        $('#ow').attr('checked', sperm.substr(13,1) == 'w' ? true : false);
        $('#ox').attr('checked', sperm.substr(14,1) == 'x' ? true : false);
    }
    else {
        $('#ur').attr('checked', sperm.substr(0,1) == 'r' ? true : false);
        $('#uw').attr('checked', sperm.substr(1,1) == 'w' ? true : false);
        $('#ux').attr('checked', sperm.substr(2,1) == 'x' ? true : false);
        $('#gr').attr('checked', sperm.substr(4,1) == 'r' ? true : false);
        $('#gw').attr('checked', sperm.substr(5,1) == 'w' ? true : false);
        $('#gx').attr('checked', sperm.substr(6,1) == 'x' ? true : false);
        $('#or').attr('checked', sperm.substr(8,1) == 'r' ? true : false);
        $('#ow').attr('checked', sperm.substr(9,1) == 'w' ? true : false);
        $('#ox').attr('checked', sperm.substr(10,1)== 'x' ? true : false);
    }

    $('#chmod_input').val(file[this.maps.perm]);
}

/*
  chmod command
*/
FileMan.prototype.chmod = function(octal) {
    if (octal && octal.length > 0) {
        var perm_map = { 0: 'u',1 : 'g',2 : 'o' };
        var nums  = octal.split("");
        var count = 0;
        for (var i=0; i<nums.length; i++) {
            if (nums.length == 4 && i == 0) continue;
            if (nums[i] == 7) {
                $('#' + perm_map[count] + 'r').attr('checked', true);
                $('#' + perm_map[count] + 'w').attr('checked', true);
                $('#' + perm_map[count] + 'x').attr('checked', true);
            }
            else if (nums[i] == 6) {
                $('#' + perm_map[count] + 'r').attr('checked', true);
                $('#' + perm_map[count] + 'w').attr('checked', true);
                $('#' + perm_map[count] + 'x').attr('checked', false);
            }
            else if (nums[i] == 5) {
                $('#' + perm_map[count] + 'r').attr('checked', true);
                $('#' + perm_map[count] + 'w').attr('checked', false);
                $('#' + perm_map[count] + 'x').attr('checked', true);
            }
            else if (nums[i] == 4) {
                $('#' + perm_map[count] + 'r').attr('checked', true);
                $('#' + perm_map[count] + 'w').attr('checked', false);
                $('#' + perm_map[count] + 'x').attr('checked', false);
            }
            else if (nums[i] == 3) {
                $('#' + perm_map[count] + 'r').attr('checked', false);
                $('#' + perm_map[count] + 'w').attr('checked', true);
                $('#' + perm_map[count] + 'x').attr('checked', true);
            }
            else if (nums[i] == 2) {
                $('#' + perm_map[count] + 'r').attr('checked', false);
                $('#' + perm_map[count] + 'w').attr('checked', true);
                $('#' + perm_map[count] + 'x').attr('checked', false);
            }
            else if (nums[i] == 1)  {
                $('#' + perm_map[count] + 'r').attr('checked', false);
                $('#' + perm_map[count] + 'w').attr('checked', false);
                $('#' + perm_map[count] + 'x').attr('checked', true);
            }
            count++;
        }
    }
    else {
        var umod=0, gmod=0, omod =0;
        if ($('#ur').attr('checked')) umod = 4;
        if ($('#gr').attr('checked')) gmod = 4;
        if ($('#or').attr('checked')) omod = 4;

        if ($('#uw').attr('checked')) umod += 2;
        if ($('#gw').attr('checked')) gmod += 2;
        if ($('#ow').attr('checked')) omod += 2;

        if ($('#ux').attr('checked')) umod++;
        if ($('#gx').attr('checked')) gmod++;
        if ($('#ox').attr('checked')) omod++;
        $('#chmod_input').val('0' + umod + '' + gmod + '' + omod).focus();
    }
}

/*
  Open a compressed file
  files  : should be an array of array ref
*/
FileMan.prototype.uncompress = function(files) {
    this.cdata = { files : files, nh : 1 };
    this.sortCompressed('name');

    var fm = this;
    $('#command-dialog th a[rel]').each(function() {
        var link = $(this);
        link.click(function() {
            var so = fm.cdata.so || 'asc';
            fm.sortCompressed(link.attr('rel'));
            $('#command-dialog th a[rel]').find('img').remove();
            $('#command-dialog th a[rel="' + link.attr('rel') + '"]').append(' <img src="' + fm.config.image_url + '/icons/' + (so == 'desc' ? 'descending.gif' : 'ascending.gif') + '" title="' + (so == 'desc' ? 'V' : '^') + '" \/>');

            var paging = new page({
                image_url : fm.config.image_url,
                parent : $('#command-dialog'),
                paging : { num_hits : files.length, max_hits : fm.paging.max_hits, current_page : 1, sb : 'name', so : 'asc' },
                action : function(nh) { fm.printCompressed(nh);  }
            }, $('#command-dialog .toolbar div[class="paging"]'));

            return false;
        });
    });

/* Set actions for checkboxes */
    var $foldertab = $('#command-dialog .foldertab');
    $foldertab.find('input[type="checkbox"]').each(function() {
        $(this).click(function() {
            if ($(this).val() == 'checkall') {
                $foldertab.find('input[type="checkbox"]').attr('checked', $(this).attr('checked') ? true : false);
            }
            else {
                var flag = true;
                $foldertab.find('input[name="compress"]').each(function() {
                    if ($(this).attr('checked')) return;
                    flag = false;
                    return false;
                });

                $foldertab.find('input[name="checkall"]').attr('checked', flag);
            }
            fm.fileStats({ inputs : $inputs, nh : fm.cdata.nh, files : fm.cdata.files });
        });
    });

    /* Handle paging */
    var paging = new page({
        image_url : fm.config.image_url,
        parent : $('#command-dialog'),
        paging : { num_hits : files.length, max_hits : fm.paging.max_hits, current_page : 1, sb : 'name', so : 'asc' },
        action : function(nh) { fm.printCompressed(nh);  }
    }, $('#command-dialog .toolbar div[class="paging"]'));

    $('#command-dialog input[name="button-browse"]').click(function() {
        fm.browse({
            title : 'Select Directory',
            filter : 1,
            hidden_query : fm.hiddens.hidden_query,
            id : 'uncompress_input'
        });
    });

    this.fileStats({ inputs : $('#command-dialog .foldertab').find('input[name="compress"]'), nh : this.cdata.nh, files : this.cdata.files });
    $('#contentfooter .summary').removeClass().addClass('summary').html('Total <span>' + files.length + '</span> files, <span>' + friendly_size(this.cdata.size) + '</span>');
}

/*
  This method handles sorting compressed's content
*/
FileMan.prototype.sortCompressed = function(sb) {
    if (this.cdata.files.length == 0) return;

    var so = (!this.cdata.so || this.cdata.so == 'desc') ? 'asc' : 'desc';
    this.cdata.nh = 1;
    
    /* Need to seperate folders and files before sorting */
    var afolders = new Array(); var afiles = new Array();
    var maps     = this.maps;
    var files    = this.cdata.files;
    var size     = 0;

    for (var i=0; i<files.length; i++) {
        if (files[i][maps.type] == 1) afolders.push(files[i]);
        else afiles.push(files[i]);
        size += files[i][maps.size];
    }

    if (afolders.length > 0) afolders.qsort(0, afolders.length, maps[sb], so);
    if (afiles.length > 0) afiles.qsort(0, afiles.length, maps[sb], so);

    if (so == 'desc') {
        for (var i=0; i<afolders.length; i++) {
            afiles.push(afolders[i]);
        }
        this.cdata.files = afiles;
    }
    else {
        for (var i=0; i<afiles.length; i++) {
            afolders.push(afiles[i]);
        }
        this.cdata.files = afolders;
    }

    this.cdata.sb = sb;
    this.cdata.so = so;
    this.cdata.size = size;

    this.printCompressed(this.cdata.nh);
}

/*
  This handles printing out compressed content
*/
FileMan.prototype.printCompressed = function(nh) {
    if (!nh) nh = this.cdata.nh;

    var maps  = this.maps;
    var files = this.cdata.files;
    var beg   = nh == 1 ? 0 : ((nh - 1) * this.paging.max_hits);
    var body = $('#command-dialog .contentframe').find('table[class="foldertab"]');
    body.empty();

    var count = 0;
    for (var i=beg; i<files.length; i++) {
        if (count == this.paging.max_hits) break;
        var tr = '<tr><td class="selectbox"><input type="checkbox" id="compress-' + i + '" name="compress" value="' + files[i][maps.name] + '" onclick="" \/><\/td>' +
            '<td class="icon"><div class="icon-' + files[i][maps.icon] + '"><\/div><\/td>' +
            '<td class="name">' +files[i][maps.name] + '<\/td>' +
            '<td class="size">' + (files[i][maps.type] == 1 ? '&nbsp' : friendly_size(files[i][maps.size])) + '<\/td>' +
            '<td class="type">' + files[i][maps.desc] + '<\/td>' +
            '<td class="modified">' + files[i][maps.sdate] + '<\/td>';

        tr += this.config.is_win 
            ? '</tr>\n<tr class="spacer"><td colspan="6"><\/td><\/tr>\n'
            : '<td class="owner">' + files[i][maps.owner] + '<\/td><td class="permission">' + files[i][maps.sperm] + '<\/td><\/tr>\n<tr class="spacer"><td colspan="8"><\/td><\/tr>\n';

        body.append(tr);
        count++;
    }
    this.cdata.nh = nh;
}

FileMan.prototype.editorConfirm = function(func) {
    var fm = this;
    this.modalConfirm({
        html : 'Do you want to save your changes?',
        yes : function($modal) {
            $modal.html('').jqmHide();
            fm.fileEditor.callback = function() {
                if (typeof(func) == 'function') func();
            }
            fm.form.submit();
        },
        no : function($modal) {
            $modal.html('').jqmHide();
            fm.fileEditor = new Object();
            if (typeof(func) == 'function') func();
        },
        cancel : function($modal) {
            $modal.html('').jqmHide();
        }
    });
}

FileMan.prototype.newfile = function() {
    var fm = this;
    if (this.fileEditor.beingEdited) {
        this.fileEditor.actionCalled = true;
        return this.editorConfirm(function() { fm.newfile(); });
    }

    this.form.find('input[name="cmd-result"]').remove();
    this.printForm('file', function(response) {
        if (response.success) {
            /* Remove command-dialog if exists */
            var $command_dialog = $('#command-dialog');
            if ($command_dialog.length > 0) {
                fm.fadeOut($command_dialog, function() {
                    $command_dialog.remove();
                    fm.editor('file', '', '', response.data.html);
                });
            }
            else {
                fm.editor('file', '', '', response.data.html);
            }
        }
        else {
            fm.showMessage(response);
        }
    });
}
/*
  File command
  command : should be newfile/edit
  filename : shoule be file name
*/
FileMan.prototype.editor = function(command, filename, filetype, html) {
    var content = $('#content').append(html).find('textarea').val();
    this.config.tinyMCE.plugins = (filename != '' && content.search(/<head>|<title>|<body/i) == -1)
        ? "style,table,advhr,advimage,advlink,preview,media,searchreplace"
        : "style,table,advhr,advimage,advlink,preview,media,searchreplace,fullpage";

    /* Remove these objects if they already exist */
    $('#edit_input').val(filename || '');
    this.form.find('input[name="file"]').remove();
    this.form.find('input[name="overwrite_confirmed"]').remove();

    if (filename) {
        this.form.append('<input type="hidden" name="file" value="' + filename + '" />');
        this.showStatus(filename + ' (<span>' + this.config.work_path + '</span>)');
    }
    else {
        this.showStatus('[No Name]');
    }

    /* Editor switch mode action */
    var $switch_mode = $('.switch-mode');
    var $editor_mode = $('#editor_mode');

    if (filetype == 'html' || filetype == '') {
        this.fadeIn($switch_mode.val('Switch To ' + ($editor_mode.val() == 'html' ? 'TEXT' : 'HTML')));
    }
    else {
        this.fadeOut($switch_mode);
    }

    var fm = this;
    this.fileEditor.beingEdited = false;
    $switch_mode.click(function() {
        var mode = $editor_mode.val();
        if (mode == 'html') {
            var content = fm.tinyMCEContent();
            tinyMCE.activeEditor.hide();
            fm.fadeIn($('textarea[name="editor"]').val(content).css('height', $('#command-dialog').height() - 5 + 'px'));
        }
        else {
            var editor = $('#command-dialog textarea[name="editor"]');
            editor.css('height', editor.height() - 8 + 'px');

            if (tinyMCE.activeEditor && tinyMCE.activeEditor.isHidden()) {
                tinyMCE.activeEditor.show();
            }
            else {
                tinyMCE.init(fm.config.tinyMCE);
            }
        }
        $editor_mode.val(mode == 'html' ? 'text' : 'html');
        $switch_mode.val('Switch To ' + (mode == 'html' ? 'HTML' : 'TEXT'));
    });
    
    this.commandDialog({ command : command, value : filename });
}

/*
  This method handles preview/download a file.
  file : File information. It should be a hash
  download : if it's passed it, file will be sent to browser
*/
FileMan.prototype.preview = function(file, download) {
    if (typeof(file) != 'object') return;
    if (!download && file.type.search(/image|text|html/) == 0) {
        var content = file.type.search(/html|text/) == 0
            ? ('<pre>' + file.content + '</pre>')
            : ('<div class="preview-image"><img src="' + this.config.cgi_url + '?cmd=fdownload;f=' + file.name + this.hiddens.hidden_query + '" title="' + file.name + '" /></div>');

        var html = '<div class="toolbar clear"><h3 class="header">Preview a File</h3>' +
            '<div><b>' + file.name + '</b></div></div>' +
            '<div class="contentframe">' + content + '</div>';
        this.actionDialog({ action : 'preview', json : { data : { html : html }} });
    }
    else {
        var src = this.config.cgi_url + '?cmd=fdownload;f=' + file.name
        if (file.source) src += ';type=' + file.source;
        if (file.mode) src += ';mode=' + file.mode;
        src += this.hiddens.hidden_query;

        if ($('.contentframe iframe[name="preview"]').length == 0) {
            $('.contentframe').append('<iframe name="preview" src="' + src + '" class="hide"></iframe>');
        }
        else {
            $('.contentframe iframe[name="preview"]').attr('src', src);
        }
    }
}

/*
  printForm: print out a command form
*/
FileMan.prototype.printForm = function(action, func, args) {
  var html  = '<form id="tmpform" action="' + this.config.cgi_url + '" method="post" class="hide">' +
    '<input type="hidden" name="cmd" value="' + action +'" /><input type="hidden" name="ajax" value="1" /><input type="hidden" name="form" value="1" />';

  if (action == 'command') {
      html += '<input type="hidden" name="prompt" value="1" />';
      $('#cmd-command input[name="working_dir"]').val('');
  }

  if (args && typeof(args) == 'object') {
    for (var i in args) {
      if (typeof(args[i]) == 'object') {
        for (j=0; j<args[i].length;j++) {
          html += '<input type="hidden" name="' + i + '" value="' + args[i][j] + '" />';
        }
      }
      else {
        html += '<input type="hidden" name="' + i + '" value="' + args[i] + '" />';
      }
    }
  }

  html += this.hiddens.hidden_objects + '</form>';

  var $form = $('#home').append(html).find('#tmpform');
  var fm    = this;
  $form.submit(function() {
      $(this).ajaxSubmit({
          dataType : 'json',
          success  : function(response) {
              if (response.status == 'ERR_NOAUTH') {
                fm.login(response.data.html);
              }
              else if (typeof(func) == 'function') {
                func(response);
              }
              $form.remove();
          }
      });
      return false;
  });

  $form.submit();
}

/*
  advanceSearch command
*/
FileMan.prototype.advanceSearch = function() {
    var fm = this;
    this.printForm('search', function(response) {
        var $modal = $('#modal-dialog');
        var mwidth = 650;
        var mleft  = parseInt(($(window).width() - mwidth) / 2);
        var mtop   = parseInt(($(window).height() - 400) / 2);
        $modal.jqm().removeClass().addClass('modal-dialog modal-dialog-form')
            .css('width', mwidth + 'px').css('left', mleft + 'px').css('top', mtop + 'px')
            .html(response.data.html).jqmShow().find('input[name="search_input"]').focus();

        $modal.find('h1 img').css('cursor', 'pointer').click(function() {
            $modal.jqmHide();
            fm.form.find('input[name="search_input"]').focus();
        });

        if (response.success)  {
            $modal.find('form').ajaxForm({
                dataType : 'json',
                success : function(res) {
                    if (res.success) {
                        if (res.data.hits == 0) {
                            $modal.find('form p.error').show().text(res.message);
                        }
                        else {
                            fm.commandResponse(res);
                            $modal.jqmHide();
                        }
                    }
                    else {
                        $modal.find('form p.error').show().text(res.message);
                        $modal.find('input[name="search_input"]').focus();
                    }
                }
            });

            $modal.find('.date-pick').datePicker({ clickInput : true, startDate: fm.startDate() });
            $('#fromdate').bind('dpClosed', function(e, selectedDates) {
                var d = selectedDates[0];
                if (d) {
                    d = new Date(d);
                    $('#todate').dpSetStartDate(d.addDays(1).asString());
                }
            }).dpSetDisabled(true);

            $('#todate').bind('dpClosed', function(e, selectedDates) {
                var d = selectedDates[0];
                if (d) {
                    d = new Date(d);
                    $('#fromdate').dpSetEndDate(d.addDays(-1).asString());
                }
            }).dpSetDisabled(true);

            $modal.find('input[name="search_mod"]').each(function() {
                var obj = $(this);
                obj.click(function() {
                    var flag = obj.val() == 'date' ? false : true;
                    $('#fromdate').dpSetDisabled(flag);
                    $('#todate').dpSetDisabled(flag);
                });
            });
        }
        else {
            this.showMessage(response);
        }
    });
    return false;
}

FileMan.prototype.userAction = function(action) {  
    if (!action || action == '') return;

    if (action == 'user_add') return this.actionForm(action);

    var selected = $('#command-dialog').find('input[name="cuser"][checked]');
    if (selected.length == 0) {
        $('#user_action').attr('selectedIndex', 0);
        this.showMessage({ success : false, message : "No user was selected." });
        return;
    }

    /* Return the modify form instead if one user is selected */ 
    if (action.search(/user_access|user_permission/) == 0) {
        var cuser = new Array;
        selected.each(function() {
            cuser.push($(this).val());
        });
        this.actionForm(action, { cuser : cuser });
    }
    else {
        this.current.action = action;
        $('#cmd').val(action);

        var fm = this;
        this.modalConfirm({
            html : 'Do you want to delete selected user(s)?',
            yes : function($modal) {
                $modal.html('').jqmHide();
                fm.form.submit();
            },
            no : function($modal) {
                $('#user_action').val('');
                $modal.html('').jqmHide();
            }
        });
    }
}

FileMan.prototype.userManagement = function(json) {
    if (json.data.users.length == 0) {
        $('#user_action').attr('disabled', true);
        return;
    }

    this.cdata = {
        map : { type : 0, username : 1, password : 2, name : 3, email : 4, added : 5, permission : 6, access : 7, allowed_space : 8 },
        users : json.data.users,
        so : 'desc',
        nh : 1
    };
    this.sortUsers();
    var fm = this;
    $('#command-dialog th a[rel]').each(function() {
        var link = $(this);
        link.click(function() {
            fm.sortUsers(link.attr('rel'));      

            var so = fm.cdata.so || 'asc';
            $('#command-dialog th a[rel]').find('img').remove();
            $('#command-dialog th a[rel="' + link.attr('rel') + '"]').append(' <img src="' + fm.config.image_url + '/icons/' + (so == 'desc' ? 'descending.gif' : 'ascending.gif') + '" title="' + (so == 'desc' ? 'V' : '^') + '" \/>');
            return false;
        });
    });
    $('#command-dialog select[name="user_action"]').change(function() { fm.userAction($(this).val()); });
    $('#command-dialog .contentframe .username a[rel]').each(function() {
        var link = $(this);
        link.click(function() {
            fm.actionForm('user_modify', { u : link.attr('rel') });
            return false;
        });
    });
}

FileMan.prototype.sortUsers = function(sb) {
    if (!sb) sb = 'username';
    var so = (!this.cdata.so || this.cdata.so == 'desc') ? 'asc' : 'desc';

    var ausers = this.cdata.users;
    var maps   = this.cdata.map;

    ausers.qsort(0, ausers.length, maps[sb], so);

    this.cdata.users = ausers;
    this.cdata.so    = so;
    this.printUsers(this.cdata.nh);
}

FileMan.prototype.printUsers = function(nh) {
    if (!nh) nh = 1;

    var ausers = this.cdata.users;
    var maps   = this.cdata.map;
    var beg   = nh == 1 ? 0 : ((nh - 1) * this.paging.max_hits);
    var body = $('#command-dialog .contentframe').find('table[class="foldertab"]');
    body.empty();

    var count = 0;
    for (var i=beg; i<ausers.length; i++) {
        if (count == this.paging.max_hits) break;
        var u = ausers[i];
        var access = new Array;
        if (u[maps.access]) {
            for (var j=0; j<u[maps.access].length; j++) {
                var a = u[maps.access][j];
                access.push(a.disp);
            } 
        }
        var tr = '<tr><td class="selectbox"><input type="checkbox" name="cuser" value="' + u[maps.username] + '" /><\/td>' +
            '<td class="username"><a href="#" rel="' + u[maps.username] + '">' + u[maps.username] + '</a><\/td>' +
            '<td class="type">' + (u[maps.type] == 0 ? 'User' : 'Admin') + '<\/td>' +
            '<td class="email">' + u[maps.email] + '<\/td>' +
            '<td class="access"><pre>' + access.join("\n") + '</pre><\/td>';      

        tr += '<tr class="spacer"><td colspan="6"><\/td><\/tr>\n';
        body.append(tr);
        count++;
    }
    this.cdata.nh = nh;
}

/* 
    browse which allows you to select files, directories from a list
    args : should be a hash of 
        - title : title of the windows
        - filter : what you want to show up in the list. 1: folder only, 2: folder and text file
        - multiple : allows multiple files selected
        - id : the object ID you want to return to
*/
FileMan.prototype.browse = function(args) {
    if (!args) args = new Object();
    args['modal'] = true;

    this.cdata.changed= false;

    var $modal = $('#modal-dialog');
    var mwidth = 450;
    var mleft  = parseInt(($(window).width() - mwidth) / 2);
    var html   = '<form action="' + this.config.cgi_url + '" method="post">\n<h1 class="clear">\n<img src="' + this.config.image_url + '/icons/close.gif" title="Close" class="close" />\n<span>' + args.title + '</span>\n</h1><div class="modal-content">';
    if (args.filter == 2) html +='<p>Location: <input type="text" name="location" value="" class="text longtext" readonly \/>';
    html += '<p class="error hide"></p>\n<div class="currentpath"><span id="modal-breadcrumbs"></span></div>';

/* Root select box. */
    if (args.multiple) html += '<div class="rootpath"><input type="checkbox" id="location_root" value="1" /><label for="location_root">Root Directory</label></div>';

    html += '<table class="foldertab">\n<tr>';

/* Allow multiple directories selected */
    if (args.multiple) html += '<th class="selectbox">&nbsp<\/th>';

    html += '<th class="icon"><\/th>\n<th class="name">Name</th>\n<th class="scrollbar"><\/th><\/tr><\/table>\n' +
        '<div class="contentframe">\n<table class="foldertab"><\/table><\/div>' +
        '<div class="buttonbar clear"><span><input type="hidden" name="select_path" value="" \/><input type="button" name="button-cancel" value="Cancel" class="submit" />&nbsp;<input type="button" name="button-select" value="Select" class="submit" \/><\/span>';
    html += '<input type="input" name="makedir_input" value="" class="text shorttext" \/><input type="submit" name="button-makedir" value="Create Folder" class="button" \/>';
    html += '</div></div><div id="hiddens" class="hide"><\/div><input type="hidden" name="cmd" value="makedir" \/><\/form>\n';

    $modal.jqm().removeClass().addClass('modal-dialog modal-dialog-form')
        .css('width', mwidth + 'px').css('left', mleft + 'px').css('top', '120px')
        .html(html).jqmShow();

    $modal.find('h1 img').css('cursor', 'pointer').click(function() {
        $modal.find('input[name="button-cancel"]').click();
    });

    var fm = this;
    $modal.find('input[name="button-cancel"]').click(function() {
        $modal.html('').jqmHide();
        if (fm.cdata.changed) fm.cd();
    });

    if (args.id) {
        $modal.find('input[name="button-select"]').click(function() {
            if (args.multiple) {
                var accesses = '';
                if ($modal.find('#location_root').attr('checked')) {
                    accesses = '/';
                }
                else {
                    for (var i=0; i<fm.cdata.accesses.length; i++) {
                        if (fm.cdata.accesses[i] == '' && fm.cdata.accesses[i] != fm.config.root_path) continue;
                        accesses += fm.cdata.accesses[i] + (i == fm.cdata.accesses.length - 1 ? '' : '\n');
                    }
                }
                $('#' + args.id).val(accesses);
            }
            else {
                var val = $modal.find('input[name="select_path"]').val();
                if (args.filter == 2) {
                    var loc = $modal.find('input[name="location"]').val() ;
                    if (loc != '') {
                        val += val == '/' ? loc : ('/' + loc);
                        $('#' + args.id).val(val);
                    }
                    else {
                        return;
                    }
                }
                else {
                    $('#' + args.id).val(val);
                }
            }
            $modal.html('').jqmHide();
        });
    }
    this.browseFiles($modal, args);
}

/*
    browseFiles: listing files and directories 
    $modal : shoule be modal object    
    args : should be a hash of all paramters
*/
FileMan.prototype.browseFiles = function($modal, args) {
    var dname = args.dname;
    var hidden_query = args.hidden_query || '';

    var fm   = this;
    var maps = this.maps;
    var url  = '?cmd=cd' + (args.filter > 0 ? (';filter=' + args.filter) : '') + hidden_query + (typeof(dname) != 'undefined' ? ';f=' + dname : '');
    if (args.multiple) url += ';multiple=1';
    this.ls(args, function(response) {
        if (response.success) {
            var source  = response.data.files;
            var hiddens = response.data.hiddens;
            var paths   = new Array();
            var parent  = '';
            var work_path = '';

            if (response.data.paths) {
                paths  = response.data.paths.loop;
                parent = response.data.paths.parent;
                work_path = response.data.paths.work_path;
            }

            var afolders = new Array(); var afiles = new Array();
            for (var i=0; i<source.length; i++) {
                if (source[i][maps.type] == 1) afolders.push(source[i]);
                else afiles.push(source[i]);
            }

            if (afolders.length > 0) afolders.qsort(0, afolders.length, maps['name'], 'asc');
            if (afiles.length > 0) afiles.qsort(0, afiles.length, maps['name'], 'asc'); 

            for (var i=0; i<afiles.length; i++) {
                afolders.push(afiles[i]);
            }

            var breadcrumbs = '<a href="#" rel="/" class="root link-breadcrumb">Root</a>:';
            for (var i=0; i<paths.length; i++) {
                breadcrumbs += '/<a href="#" rel="' + (paths[i].path != '' ?  paths[i].path + '/' : '')  +  paths[i].folder + '" class="link-breadcrumb">' + paths[i].folder + '<\/a>';
            }
            $modal.find('#modal-breadcrumbs').html(breadcrumbs);

            var files = '';
            if (parent != '') {
                files += '<tr>';
                if (args.multiple) files += '<td class="selectbox">&nbsp;<\/td>';
                files +=    '<td class="icon"><div class="icon-uplevel"><a href="#" rel="' + parent + '" class="icon-linkable link-folder">File Folder<\/a><\/div><\/td>' +
                    '<td class="name"><a href="#" rel="' + parent + '" title="Up One Level" class="link-folder">...<\/a><\/td>' +
                    '<\/tr>\n<tr class="spacer"><td colspan="' + (args.multiple ? 4 : 3) + '"><\/td><\/tr>\n';
            }

            for (var i=0; i<afolders.length; i++) {
                files += '<tr>';
                if (args.multiple) files += '<td class="selectbox"><input type="checkbox" name="cselect" value="' + work_path + '/' + afolders[i][maps.name] +'" /><\/td>';
                files += '<td class="icon"><div class="icon-' + afolders[i][maps.icon] + '"><a href="#" rel="' + afolders[i][maps.name] + '" title="File Folder" class="icon-linkable ' + (afolders[i][maps.type] == 1 ? 'link-folder' : 'link-file') + '"><\/a><\/div><\/td>' +
                    '<td class="name"><a href="#" rel="' + afolders[i][maps.name] + '" title="File Folder" class="' + (afolders[i][maps.type] == 1 ? 'link-folder' : 'link-file') + '">' + afolders[i][maps.name] + '<\/a><\/td>' +
                    '<\/tr>\n<tr class="spacer"><td colspan="' + (args.multiple ? 4 : 3) + '"><\/td><\/tr>\n';
            }
            $modal.find('.contentframe table').empty().append(files);
            $modal.find('#hiddens').empty().append(hiddens.hidden_objects);

            /* Sent action for links and inputs */
            $modal.find('.link-folder[rel]').each(function() {
                var link = $(this);
                link.click(function() {
                    args['dname']          = link.attr('rel');
                    args['hidden_objects'] = hiddens.hidden_objects;
                    args['breadcrumbs']    = false;
                    fm.browseFiles($modal, args);
                    return false;
                });
            });

            $modal.find('.link-breadcrumb[rel]').each(function() {
                var link = $(this);
                link.click(function() {
                    args['dname']          = link.attr('rel');
                    args['breadcrumbs']    = true;
                    args['hidden_objects'] = fm.hiddens.hidden_objects;
                    fm.browseFiles($modal, args);
                    return false;
                });
            });

            $modal.find('.link-file[rel]').each(function() {
                var link = $(this);
                link.click(function() {
                    $modal.find('input[name="location"]').val(link.attr('rel'));
                });
            });

            $modal.find('form').ajaxForm({
                dataType: 'json',
                success : function(data) {
                    if (data.success) {
                        args['hidden_query'] = hiddens.hidden_query;
                        fm.browseFiles($modal, args);
                        $modal.find('input[name="makedir_input"]').val('').focus();
                        fm.cdata.changed = true;
                    }
                    else {
                        $modal.find('.error').removeClass('hide').html(data.message);
                        $modal.find('input[name="makedir_input"]').focus();
                    }
                }
            });

            $modal.find('input[name="location"]').val('');
            $modal.find('input[name="select_path"]').val(work_path);

            /* This applies for multiple selects */
            if (args.multiple) {
                $modal.find('input[name="cselect"]').each(function() {
                    var input = $(this);
                    input.click(function() {
                        fm.updateAccess(input.val(), input.attr('checked'));
                    });
                });

                $modal.find('#location_root').change(function() {
                    $modal.find('input[name="cselect"]').attr('disabled', $(this).attr('checked') ? true : false);
                    fm.cdata.accesses = new Array();
                });

                /* Pre-select user access folders */
                var found_root = false;
                var preselect  = fm.cdata.accesses;
                for (i=0; i<preselect.length; i++) {
                    var found = $modal.find('input[value="' + preselect[i] + '"]');
                    if (found.length > 0) found.attr('checked', true);
                    else if (preselect[i] == '/') {
                        found_root = true;
                        break;
                    }
                }

                if (found_root) $modal.find('#location_root').attr('checked', true).change();                
            }
            
        }
        else {
            fm.showMessage(response);
        }
    });
}

/* Add/Remove a user access directory */
FileMan.prototype.updateAccess = function(path, flag) {
    if (!flag) { /* Remove a path from the selected list */
        var accesses = new Array();
        for (var i=0; i<this.cdata.accesses.length; i++) {
            if (path == this.cdata.accesses[i]) continue;
            accesses[accesses.length] = this.cdata.accesses[i];
        }
        this.cdata.accesses = accesses;
    }
    else { /* Add a path into the list */
        var found = false;
        for (var i=0; i<this.cdata.accesses.length; i++) {
            if (path == this.cdata.accesses[i]) {
                found = true;
                break;
            }
        }
        if (!found) this.cdata.accesses.push(path);
    }
}

/* Browse logs actions */
FileMan.prototype.browseLogs = function(json) {
    if (json.data.logs.length == 0) {
        $('#log_action').attr('disabled', true);
        return;
    }

    this.cdata = {
        map : { uid: 0, ip: 1, date: 2, action: 3, desc: 4, sdate : 5 },
        logs : json.data.logs,
        so : 'asc',
        nh : 1
    };

    var fm = this;
    $('#command-dialog th a[rel]').each(function() {
        var link = $(this);
        link.click(function() {
            fm.sortLogs(link.attr('rel'));
            var so = fm.cdata.so || 'asc';
            $('#command-dialog th a[rel]').find('img').remove();
            $('#command-dialog th a[rel="' + link.attr('rel') + '"]').append(' <img src="' + fm.config.image_url + '/icons/' + (so == 'desc' ? 'descending.gif' : 'ascending.gif') + '" title="' + (so == 'desc' ? 'V' : '^') + '" \/>');

            var paging = new page({
                image_url : fm.config.image_url,
                parent : $('#command-dialog'),
                paging : { num_hits : json.data.logs.length, max_hits : fm.paging.max_hits, current_page : 1, sb : 'date', so : 'asc' },
                action : function(nh) { fm.printLogs(nh);  }
            }, $('#command-dialog .toolbar div[class="paging"]'));

            return false;
        });
    });

    var paging = new page({
        image_url : fm.config.image_url,
        parent : $('#command-dialog'),
        paging : { num_hits : json.data.logs.length, max_hits : fm.paging.max_hits, current_page : 1, sb : 'date', so : 'asc' },
        action : function(nh) { fm.printLogs(nh);  }
    }, $('#command-dialog .toolbar div[class="paging"]'));

    $('#log_action').change(function() {
        var action = $(this).val();
        if (action == 'log_delete') {
            fm.current.action = action;
            $('#cmd').val(action);
            fm.modalConfirm({
                html : 'Are you sure you want to clear the logs?',
                yes : function($modal) {
                    $modal.html('').jqmHide();
                    fm.form.submit();
                },
                no : function($modal) {
                    $('#log_action').val('');
                    $modal.html('').jqmHide();
                }
            });
        }
        else if (action == 'log_search') {
            fm.printForm('log', function (response) {
                var $modal = $('#modal-dialog');
                var mwidth = 650;
                var mleft  = parseInt((fm.screen.width - mwidth) / 2);

                if (response.success)  {
                    $modal.jqm().removeClass().addClass('modal-dialog modal-dialog-form')
                        .css('width', mwidth + 'px').css('left', mleft + 'px')
                        .html(response.data.html).jqmShow();

                    $modal.find('h1 img').css('cursor', 'pointer').click(function() { $modal.jqmHide(); });

                    $modal.find('form').ajaxForm({
                        dataType: 'json',
                        success : function(res) {
                            if (res.success) {
                                $modal.jqmHide();
                                fm.cdata.logs = res.data.logs;

                                var paging = new page({
                                    image_url : fm.config.image_url,
                                    parent : $('#command-dialog'),
                                    paging : { num_hits : res.data.logs.length, max_hits : fm.paging.max_hits, current_page : 1, sb : 'date', so : 'asc' },
                                    action : function(nh) { fm.printLogs(nh);  }
                                }, $('#command-dialog .toolbar div[class="paging"]'));

                                fm.sortLogs();
                                if (res.message) fm.showMessage(res);
                            }
                            else {
                                $modal.find('form p.error').show().text(res.message);
                                $modal.find('input[name="search_input"]').focus();
                            }
                        }
                    });

                    $modal.find('.date-pick').datePicker({ clickInput : true, startDate : fm.startDate() }); 
                    $('#fromdate').bind('dpClosed', function(e, selectedDates) {
                        var d = selectedDates[0];
                        if (d) {
                            d = new Date(d);
                            $('#todate').dpSetStartDate(d.addDays(1).asString());
                        }
                    });

                    $('#todate').bind('dpClosed', function(e, selectedDates) {
                        var d = selectedDates[0];
                        if (d) {
                            d = new Date(d);
                            $('#fromdate').dpSetEndDate(d.addDays(-1).asString());
                        }
                    });
                }
            }, { search : 1 });
        }
        $(this).val('');
    });
    fm.sortLogs();
}

FileMan.prototype.sortLogs = function(sb) {
    if (!sb) sb = 'date';
    var so = (!this.cdata.so || this.cdata.so == 'desc') ? 'asc' : 'desc';

    var alogs = this.cdata.logs;
    var maps  = this.cdata.map;

    alogs.qsort(0, alogs.length, maps[sb], so);

    this.cdata.logs = alogs;
    this.cdata.so   = so;
    this.cdata.nh   = 1;
    this.printLogs(this.cdata.nh);
}

FileMan.prototype.printLogs = function(nh) {
    if (!nh) nh = 1;

    var alogs = this.cdata.logs;
    var maps  = this.cdata.map;
    var beg   = nh == 1 ? 0 : ((nh - 1) * this.paging.max_hits);
    var body = $('#command-dialog .contentframe').find('table[class="foldertab"]');
    body.empty();

    var count = 0;
    for (var i=beg; i<alogs.length; i++) {
        if (count == this.paging.max_hits) break;
        var l = alogs[i];
        var tr = '<tr><td class="modified">' + l[maps.sdate] + '<\/td>' +
            '<td class="owner">' + l[maps.uid] + '<\/td>' +
            '<td class="permission">' + l[maps.ip] + '<\/td>' +
            '<td class="action">' + l[maps.action] + '<\/td>' +
            '<td class="name">' + l[maps.desc] + '<\/td>';      

        tr += '<tr class="spacer"><td colspan="6"><\/td><\/tr>\n';
        body.append(tr);
        count++;
    }
    this.cdata.nh = nh;
}

/*
  protect command 
*/
FileMan.prototype.htaccess = function(users) {
    $('#cmd-protect input[name="protect-delete-all"]').remove();

    var select = $('#cmd-protect select');
    select.empty();

    if (users && users.length > 0) {
        users.qsort(0, users.length, 0, 'asc');
        select.append('<option value="">---</option>');
        for (var i=0; i<users.length; i++) {
            select.append('<option value="' + users[i] + '">' + users[i] + '</option>');
        }
        select.attr('disabled', false);

        var fm = this;
        $('#cmd-protect input[name="button-delete"]').attr('disabled', false).click(function() { fm.htaccessDelete(); });
        $('#cmd-protect input[name="button-delete-all"]').attr('disabled', false).click(function() { fm.htaccessDelete(true); });
    }
    else {
        select.attr('disabled', true);
        $('#cmd-protect input[name="button-delete"]').attr('disabled', true);
        $('#cmd-protect input[name="button-delete-all"]').attr('disabled', true);
    }
}

/*
  need a confirmation on delete htaccess users
*/
FileMan.prototype.htaccessDelete = function(all) {
    var msg;
    if (all) {
        msg = 'Are you sure you want to delete all users?';
        $('#cmd-protect').append('<input type="hidden" name="protect-delete-all" value="1" />');
    }
    else if ($('#protect_user').val() == '')  {
        this.showMessage({ success : false, message : "No user was selected." });
        return;
    }
    else {
        $('#cmd-protect input[name="protect-delete-all"]').remove();
        msg = 'Are you sure you want to delete "' + $('#protect_user').val() + '"?';
        $('#htaccess-delete').val('');
    }

    var fm = this;
    this.modalConfirm({
        html : msg,
        yes : function($modal) {
            $modal.html('').jqmHide();
            fm.form.submit();
        },
        no : function($modal) {
            $('#user_action').val('');
            $modal.html('').jqmHide();
        }
    });
}

/* Help contents */
FileMan.prototype.help = function() {
    var width  = 780;
    var height = 600;
    var attrs  = 'resizable=no,status=yes,toolbar=no,menubar=no,location=no,width=' + width + ',height=' + height + ',left=400,top=10';
    var w = window.open(this.config.cgi_url + '?page=help.html' + this.hiddens.hidden_query, 'help', attrs);
    w.focus();
}

/* About FileMan */
FileMan.prototype.about = function() {
    var $modal = $('#modal-dialog');
    var nleft  = parseInt(($(window).width() - 400) / 2);
    var ntop   = parseInt((this.screen.height - 400)/ 2);
    var html   = '<div class="aboutcontent">' +
        '<div><b>Version:<\/b> ' + this.config.version + '<\/div>' +
        '<div><b>Registration Number:<\/b> ' + (this.config.regnum != '' ? this.config.regnum : 'Free') + '<\/div>' +
        '<div class="copyright">&copy;2001 - 2008. Powered By Gossamer Threads Inc.<br \/><b> <a href="http://www.gossamer-threads.com/scripts/fileman/license.htm" target="_blank">View License Information &raquo;<\/a><\/b><\/div>' +
        '<div class="close"><a href="#">Close<\/a><\/div><\/div>';
    $modal.jqm().removeClass().addClass('modal-dialog modal-about ')
        .css('left', nleft + 'px').css('top', ntop + 'px').css('width', '420px')
        .html(html).jqmShow();

    $modal.find('.close a').click(function() {
      $modal.html('').jqmHide();
      return false;
    });
}

FileMan.prototype.startDate = function() {
    var format = this.config.date_format.split(/-|\\/);
    var d = '';
    for (var i=0; i<format.length; i++) {
        if (format[i] == 'yyyy') {
            d += d != '' ? '-1996' : '1996';
        }
        else {
            d += d != '' ? '-01' : '01';
        }

    }
    return d;
}

/*
  Animate method
  $obj : should be jquery object 
  args : should be a hash of all properties that are used for animate. e.g. margin-top, height, width, etc...
  func : should be a callback function
*/
FileMan.prototype.animate = function($obj, args, speed, func) {
    if (this.config.effect) {
        var maps = { height : 'height', width : 'width', 'margin-top' : 'marginTop', 'margin-bottom' : 'marginBottom' };
        var opts = new Object();

        for (var i in args) {
            if (!maps[i]) continue;
            opts[maps[i]] = args[i];
        }
        $obj.animate(opts, speed || 'normal', function() {
            if (typeof(func) == 'function') func();
        })
    }
    else {
        for (var i in args) {
            $obj.css(i, args[i] + 'px');      
        }
        if (typeof(func) == 'function') func();
    }
}

/*
  slideUp method
  $obj : should be a jquery object
  func : should be a callback function
*/
FileMan.prototype.slideUp = function($obj, func) {
    if (this.config.effect) {
        $obj.slideUp('normal', function() {
            if (typeof(func) == 'function') func();
        });
    }
    else {
        $obj.hide('fast', function() {
            if (typeof(func) == 'function') func();
        });
    }
}

/*
  slideDown method
  $obj : should be a jquery object
  func : should be a callback function
*/
FileMan.prototype.slideDown = function($obj, func) {
    if (this.config.effect) {
        $obj.slideDown('normal', function() {
            if (typeof(func) == 'function') func();
        });
    }
    else {
        $obj.show('fast', function() {
            if (typeof(func) == 'function') func();
        });
    }
}

/*
  Show a object with/without an effection
  $obj : should be a jquery object
  func : should be a callback function
*/
FileMan.prototype.fadeIn = function($obj, func) {
    if (this.config.effect) {
        $obj.fadeIn('fast', function() {
            if (typeof(func) == 'function') func();
        });
    }
    else {
        $obj.show('fast', function() {
            if (typeof(func) == 'function') func();
        });
    }
}

/*
  Hide a object with/without an effection
  $obj : should be a jquery object
  func : should be a callback function
*/
FileMan.prototype.fadeOut = function($obj, func) {
    if (this.config.effect) {
        $obj.fadeOut('fast', function() {
            if (typeof(func) == 'function') func();
        });
    }
    else {
        $obj.hide('fast', function() {
            if (typeof(func) == 'function') func();
        });
    }
}

/* Unescape GT tags and manually the textarea with the content instead of using tinyMCE.activeEditor.save() method */
FileMan.prototype.tinyMCEContent = function() {
    var content = '';
    if (tinyMCE.activeEditor == null) return content;

    content = tinyMCE.activeEditor.getContent();
    content = content.replace(/%&gt;/gi, '%>');
    content = content.replace(/&lt;%/gi, '<%');
    return content;
}

/* quick sort which allows you to sort an array of arrays
source: is an array
begin: should be a number. Which is the start point
end: should be a number. Which is the end point
column: should be sort column
 */
Array.prototype.qsort = function(begin, end, column, sort_order) {
    if (end - 1 > begin) {
        var pivot = begin + Math.floor(Math.random() * (end - begin));

        pivot = this.partition(begin, end, pivot, column, sort_order);

        this.qsort(begin, pivot, column, sort_order);
        this.qsort(pivot + 1, end, column, sort_order);
    }
}

Array.prototype.partition = function(begin, end, pivot, column, sort_order) {
    var piv = this[pivot][column];
    this.swap(pivot, end - 1);

    var store = begin;
    if (sort_order == 'desc') {
        for (var i= begin; i<end - 1; ++i) {
            if (this[i][column] > piv) {
                this.swap(store, i);
                ++store;
            }
        }
    }
    else {
        for (var i= begin; i<end - 1; ++i) {
            if (this[i][column] <= piv) {
                this.swap(store, i);
                ++store;
            }
        }
    }

    this.swap(end - 1, store);
    return store;
}

Array.prototype.swap = function(a, b) {
    var tmp = this[a];
    this[a] = this[b];
    this[b] = tmp;
}

/* 
  page Object 
  args : is a hash of
    - image_url : image URL
    - paging : should be a hash of max_hits, so, sb
*/
function page(args, $page) {
    for (var i in args) {
        this[i] = args[i];
    }
    if (args.paging.max_hits >= args.paging.num_hits) {
        $page.html('');
        return;
    }

    var paging  = args.paging;
    var options = {
        max_pages      : 20,
        boundary_pages : 1,
        style          : 1,
        style_next     : '<img src="' + args.image_url + '/paging-next.gif" alt="&gt;" title="Next Page" />',
        style_prev     : '<img src="' + args.image_url + '/paging-prev.gif" alt="&lt;" title="Previous Page" />',
        style_first    : '<img src="' + args.image_url + '/paging-first.gif" alt="|&lt;" title="First Page" />',
        style_last     : '<img src="' + args.image_url + '/paging-last.gif" alt="&gt;|" title="Last Page" />',
        style_nonext   : '<img src="' + args.image_url + '/paging-nonext.gif" alt="" />',
        style_noprev   : '<img src="' + args.image_url + '/paging-noprev.gif" alt="" />',
        style_nofirst  : '<img src="' + args.image_url + '/paging-nofirst.gif" alt="" />',
        style_nolast   : '<img src="' + args.image_url + '/paging-nolast.gif" alt="" />',
        lang_of        : ' of ',
        paging_pre     : '',
        paging_post    : ''
    };

    paging.num_pages = parseInt(paging.num_hits / paging.max_hits);
    if (paging.num_hits % paging.max_hits > 0) paging.num_pages++ 

    this.page = $page;
    this.paging.num_pages = paging.num_pages;
    this.paging.options   = options;
    this.print(true);
    this.pagingAction();
}

page.prototype.print = function(fresh) {
    var paging  = this.paging;
    var options = this.paging.options;
    var start = 0; var end = 0;
    if (paging.num_pages <= options.max_pages) {
        start = 1;
        end   = paging.num_pages;
    }
    else if (paging.current_page >= paging.num_pages - options.max_pages / 2) {
        end   = paging.num_pages;
        start = end - options.max_pages + 1;
    }
    else if (paging.current_page <= options.max_pages / 2) {
        start = 1;
        end   = options.max_pages;
    }
    else {
        start = paging.current_page - parseInt(options.max_pages / 2) + 1;
        if (options.max_pages % 2 > 0)  start--;
        end = paging.current_page + parseInt(options.max_pages / 2);
    }

    var left_boundary  = 0;
    var right_boundary = 0;
    if (end >= paging.num_pages - options.boundary_pages - 1) end = paging.num_pages;
    else right_boundary = 1;

    if (start <= options.boundary_pages + 2) start = 1;
    else left_boundary = 1;

    var pages = new Array();
    if (left_boundary > 0) {
        for (var i=0; i<options.boundary_pages;i++) pages.push(i + 1);
        pages.push('...');
    }
    for (var i=start;i<=end;i++) {
        pages.push(i);
    }

    if (right_boundary > 0) {
        pages.push('...');
        for (var i=paging.num_pages - options.boundary_pages + 1; i<=paging.num_pages; i++) pages.push(i);
    }

    paging.pages = pages;
    var page_html = '';
    
    if (fresh) {
      page_html += options.paging_pre;
      page_html += '<span id="page-first">' + options.style_nofirst + '<\/span> <span id="page-prev">' + options.style_noprev + '<\/span> ';
      page_html += '<select>';
    }

    for (var i=0; i<pages.length; i++) {
        if (pages[i] == '...') {
            page_html += '<option value="" disabled="disabled">...<\/option>';
        }
        else {
            page_html += '<option value="' + pages[i] + '"';
            if (pages[i] == paging.current_page) page_html += ' selected="selected"';
            page_html += '>' + pages[i] + options.lang_of + paging.num_pages + '<\/option>';
        }
    }

    var pg = this;
    if (fresh) {
      page_html += '<\/select> ';
      page_html += '<span id="page-next">' + options.style_next + '<\/span> <span id="page-last">' + options.style_last + '<\/span>';
      page_html += options.paging_post;
      this.page.html(page_html);
    }
    else {
      this.page.find('select').empty().html(page_html);
    }

    this.page.find('select').change(function() {
        if (this.options[this.selectedIndex].innerHTML != '...' && typeof(pg.action) == 'function') {
            pg.gotoPage(this.options[this.selectedIndex].value);
        }
    });
}

/* 
  Setting actions for paging: next, previous, etc...
*/
page.prototype.pagingAction = function() {
    var pg = this;
    var parent_obj = this.parent ? this.parent : $('.toolbar');

    if (this.paging.current_page == 1) {
        if (parent_obj.find('#page-first').find(this.paging.options.style_nofirst).length == 0) parent_obj.find('#page-first').html(this.paging.options.style_nofirst);
        if (parent_obj.find('#page-prev').find(this.paging.options.style_noprev).length == 0) parent_obj.find('#page-prev').html(this.paging.options.style_noprev);
    }
    else {
        if (parent_obj.find('#page-first').find(this.paging.options.style_first).length == 0) {
            parent_obj.find('#page-first').html(this.paging.options.style_first);
            parent_obj.find('#page-first img').click(function() { pg.gotoPage(1); });
        }
        if (parent_obj.find('#page-prev').find(this.paging.options.style_prev).length == 0) {
            parent_obj.find('#page-prev').html(this.paging.options.style_prev);
            parent_obj.find('#page-prev img').click(function() { pg.gotoPage(pg.paging.current_page - 1) });
        }
    }

    if (this.paging.current_page == this.paging.num_pages) {
        if (parent_obj.find('#page-last').find(this.paging.options.style_nolast).length == 0) parent_obj.find('#page-last').html(this.paging.options.style_nolast);
        if (parent_obj.find('#page-prev').find(this.paging.options.style_nonext).length == 0) parent_obj.find('#page-next').html(this.paging.options.style_nonext);
    }
    else {
        if (parent_obj.find('#page-last').find(this.paging.options.style_last).length == 0) {
            parent_obj.find('#page-last').html(this.paging.options.style_last);
            parent_obj.find('#page-last img').click(function() { pg.gotoPage(pg.paging.num_pages); });
        }
        if (parent_obj.find('#page-next').find(this.paging.options.style_next).length == 0) {
            parent_obj.find('#page-next').html(this.paging.options.style_next);
            parent_obj.find('#page-next img').click(function() { 
              pg.gotoPage(pg.paging.current_page + 1); 
            });
        }
    }
    this.page.find('img').css('cursor', 'pointer');
}

/* 
  gotoPage  method
*/
page.prototype.gotoPage = function(nh) {
    if (nh > this.paging.num_pages) return;

    this.paging.current_page = parseInt(nh);

    if (this.paging.num_pages > this.paging.options.max_pages) this.print();
    this.pagingAction();

    this.page.find('option[value="' + nh +'"]').attr('selected', true);
    if (typeof(this.action) == 'function') this.action(nh);
}

/* Global functions */
function friendly_size(num, force_kb, total_size) {
    if (num < 100) return num + ' bytes';
    var force_mb = total_size > 999999 ? 1 : 0;
    var unit;
    if((num > 999999 || force_mb) && !force_kb) {
        num = num/(1024*1024);
        num = num.toString();
        var testnum = num.replace( /^(\d+\.\d).*/, '$1' );
        if(testnum == '0.0') testnum = num.replace( /^(\d+\.\d\d).*/, '$1' );
        if(testnum == '0.00') testnum = num.replace( /^(\d+\.\d\d\d).*/, '$1' );
        num = testnum;
        unit = 'MB';
    }
    else {
        var kb = num/1024;
        var decimal = kb - parseInt(kb);
        num = parseInt(kb);
        if (decimal > 0) {
          var str = decimal.toFixed(3).substr(1, 3);
          num += '' + str;
        }
        unit = 'KB';
    }
    return num + '&nbsp;' + unit;
}

function getScreenHeight() { /* $(window).height() does not working properly on window resizing */
    if (window.innerHeight) return window.innerHeight;
    else if (document.documentElement.clientHeight) return document.documentElement.clientHeight;
    else if (window.clientHeight) return window.clientHeight;
    else if (document.body.clientHeight) return document.body.clientHeight;
    else return 0;
}

function getScreenWidth() {
    if (window.innerWidth) return window.innerWidth;
    else if (document.documentElement.clientWidth) return document.documentElement.clientWidth;
    else if (window.clientWidth) return window.clientWidth;
    else if (document.body.clientWidth) return document.body.clientWidth;
    else return 0;
}

function randomString() {
    var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
    var string_length = 8;
    var randomstring = '';
    for (var i=0; i<string_length; i++) {
        var rnum = Math.floor(Math.random() * chars.length);
        randomstring += chars.substring(rnum,rnum+1);
    }

    return randomstring;
}

function format_time(num) {
    if(num >= 60 * 60){
        var secs_left = num % (60 * 60);
        var mins_left = secs_left / 60;
        mins_left = mins_left.toString();
        mins_left = mins_left.replace( /^(\d+)\..*/, '$1' ); // show no decimal places.
        mins_left = mins_left.replace( /^(\d)$/, '0$1' ); // for single-digits, prepend a zero.

        num = num/(60*60);
        num = num.toString();
        num = num.replace( /^(\d+)\..*/, '$1' ); // show no decimal places.
        num = num + ':' + mins_left + ':00';
    }
    else if(num >= 60) {
        var secs_left = num % 60;
        secs_left = secs_left.toString().replace( /^(\d)$/, '0$1' ); // for single-digits, prepend a zero.

        num = num/60;
        num = num.toString();
        num = num.replace( /^(\d+)\..*/, '$1' ); // show no decimal places.
        num = num.replace( /^(\d)$/, '0$1' ); // for single-digits, prepend a zero.

        num = '00:' + num + ':' + secs_left;
    }
    else  {
        num = num.toString();
        num = num.replace( /^(\d+)\..*/, '$1' ); // show no decimal places.
        num = num.replace( /^(\d)$/, '0$1' ); // for single-digits, prepend a zero.
        num = '00:00:' + num;
    }
    return num;
}

function htmlEscape(text) {
    text = text.replace(/&/g, '&amp;');
    text = text.replace(/</g, '&lt;');
    text = text.replace(/>/g, '&gt;');
    text = text.replace(/"/g, '&quot;');
    return text;
}

