/* 
 * AJAX Terminal (0.4.1)
 * by Sagie Maoz (n0nick.net)
 * n0nick@php.net
 *
 * jQuery plugin to create a web-based console-like behavior that posts user input commands
 * to an AJAX server, and prints the result text.
 * Designed to be utterly simple and highly customizable.
 *
 * Copyright (c) 2009 Sagie Maoz <n0nick@php.net>
 * Licensed under the GPL license, see http://www.gnu.org/licenses/gpl-3.0.html 
 *
 *
 * NOTE: This script requires jQuery to work.  Download jQuery at www.jquery.com
 *
 */
 
(function($) {

    $.fn.terminal = function(url, options) {

        settings = $.extend({
            'max_height'        : '100%',
            'form_method'        : 'post',
            'input_name'        : 'input',
            'post_vars'            : {},
            'custom_prompt'    : false,
             'focus_on_load'    : true,
            'submit_on_load'    : false,
            'grab_focus_on_click' : true,
            'hello_message'    : false,
            'unix_theme'        : true,
            'allow_empty_input' : false,
            'tab_width'            : 4,
            'disable_input'    : false,
            'onload'                : null
        }, options);

        if (settings.custom_prompt)
        {
            settings.custom_prompt = $.trim(settings.custom_prompt) + ' ';
        }

        return this.each(function()
        {
            var terminal_container = $(this);

            terminal_container.append('<div></div>');
            var terminal = terminal_container.find('div:last');

            if (settings.max_height == '100%')
            {
                settings.max_height = terminal_container.innerHeight();
            }

            terminal.css({
                'display'    : 'block',
                'overflow-x'    : 'hidden',
                'overflow-y'    : 'auto',
                'padding'    : '0',
                'max-height': settings.max_height + 'px',
            });

            terminal.append('<span></span');
            var terminal_output = terminal.find('span:last');

            terminal.append('<form method="'+settings.form_method+'" action="'+url+'"></form>');
            var terminal_form = $(this).find('form:last');

            if (settings.custom_prompt)
            {
                terminal_form.append('<span>' + settings.custom_prompt + '</span>');
            }

            terminal_form.css('display', 'inline');
            terminal_form.attr('onsubmit', 'return false;');

            var tabString = "";
            for (var i=0; i<settings.tab_width; i++)
            {
                tabString+= "&nbsp;";
            }

            var terminal_append = function(data)
            {
                var formattedData = $('<span/>').html(data.replace('\n', '<br/>'));
                var dataRows = formattedData.html().split(/\n/);
                data = '';
                for (row in dataRows)
                {
                    data += '<span>' + dataRows[row].replace(/\t/g, tabString);
                    if (!(row == dataRows.length-1 && (!dataRows[row] || !settings.custom_prompt)))
                    {
                        data+= '<br />';
                    }
                    data += '</span>';
                }

                terminal_output.append('<span>' + data + '</span>');

                terminal_form.show();
                terminal_input.val('').focus();
                
                // if input is disabled, we trick a focus so the scrolling will be ok
                if (settings.disable_input)
                {
                    terminal_input.removeAttr('disabled').focus().attr('disabled', 'disabled');
                }
            }
            // outsource this function for misc. implementations
            terminal_container[0].append = terminal_append; //TODO bad [0]
            
            var terminal_clear = function()
            {
                terminal_output.text('');
            }
            terminal_container[0].clear = terminal_clear; //TODO bad [0] again!
            
            var terminal_command = function(e, first)
            {
                var first = first || false;
                var val = $.trim(terminal_input.val());

                if ("" == val && !first)
                {
                     if (!settings.allow_empty_input)
                          return false;
                }

                 terminal_form.hide();
                 if ("" != val || settings.allow_empty_input)
                {
                    var last_command = '<span>';
                      last_command+= settings.custom_prompt? settings.custom_prompt : '';
                      last_command+= val + '<br />';
                     terminal_output.append(last_command);
                 }

                 post_vars = settings.post_vars;
                 post_vars[settings.input_name] = val;

                function terminal_command_success(data)
                {
                    if (data == "TERM_CLEAR")
                        window.location = window.location; 
                    else 
                        return terminal_append(data);
                }

                function terminal_command_error(x, tStatus)
                {
                    var out = 'ERROR: ';
                    switch(tStatus)
                    {
                        case 'timeout':
                            out+= 'Server timeout. Try again later.';
                            break;
                        case 'notmodified':
                            out+= 'Server did not response properly. Try again.';
                            break;
                        case 'parsererror':
                            out+= 'Client error. Try again.';
                            break;
                        default:
                        case 'error':
                            out+= 'A server error has occured. Check your command.';
                            break;
                    }
                    return terminal_command_success(out);
                }

                $.ajax({
                    'type' : terminal_form.attr('method'),
                    'url' : terminal_form.attr('action'),
                    'cache' : false,
                    'data' : post_vars,
                    'dataType' : 'text',
                    'success' : terminal_command_success,
                    'error' : terminal_command_error,
                });
                if (typeof e == 'object' && typeof e['preventDefault'] == 'function')
                {
                    e.preventDefault();
                }

            }
            terminal_form.submit(terminal_command);

            terminal_form.append('<input type="text" name="'+settings.input_name+'" />');
            var terminal_input = terminal_form.find('input:last');
            terminal_input.css('width', '80%');
            terminal_input.attr('autocomplete', 'off');

            if (settings.unix_theme)
            {
                terminal_container.css({
                    'border' : 'none',
                    'background-color' : 'black',
                });
                terminal_form.css({
                    'padding' : '0',
                    'margin' : '0',
                });
                terminal_input.css({
                    'border' : 'none',
                    'background-color' : 'black',
                    'padding' : '0',
                    'margin' : '0',
                });
                terminal_container.find('input, span').css({
                    'color' : 'lightgrey',
                    'font-family' : 'monospace',
                    'font-size' : '1em',
                    'line-height' : '1.3em',
                });
            }

            $(document).ready(function()
            {
                if (settings.grab_focus_on_click)
                {
                    terminal_container.mouseup(function()
                    {
                        if (document.getSelection) {
                            if ("" == document.getSelection()) {
                                $(terminal_input.focus());      
                            }
                        } else {
                            $(terminal_input.focus());  
                        }
                    });
                }

                if (settings.hello_message)
                    terminal_output.append('<span>' + settings.hello_message + '<br /></span>');

                if (settings.submit_on_load)
                    terminal_command(null, true);

                if (settings.focus_on_load)
                    terminal_input.focus();

                if (settings.disable_input)
                    terminal_input.attr('disabled', 'disabled');

                if (settings.onload)
                    settings.onload();

            });
        });

    }

}(jQuery));
