/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
 * @fileoverview    functions used wherever an sql query form is used
 *
 * @requires    jQuery
 * @requires    js/functions.js
 *
 */

var $data_a;

/**
 * decode a string URL_encoded
 *
 * @param string str
 * @return string the URL-decoded string
 */
function PMA_urldecode(str) {
    return decodeURIComponent(str.replace(/\+/g, '%20'));
}

function PMA_urlencode(str) {
    return encodeURIComponent(str.replace(/\%20/g, '+'));
}

/**
 * Get the field name for the current field.  Required to construct the query
 * for inline editing
 *
 * @param   $this_field  jQuery object that points to the current field's tr
 * @param   disp_mode    string
 */
function getFieldName($this_field, disp_mode) {

    if(disp_mode == 'vertical') {
        var $field = $this_field.siblings('th').find('a').clone();
        // happens when just one row (headings contain no a)
        if ($field.length == 0) {
            $field = $this_field.siblings('th').clone();
        }
    }
    else {
        var this_field_index = $this_field.index();
        // ltr or rtl direction does not impact how the DOM was generated
        //
        // 5 columns to account for the checkbox, edit, appended inline edit, copy and delete anchors but index is zero-based so substract 4
        var $field = $('#table_results').find('thead').find('th:nth('+ (this_field_index-4 )+') a').clone();
        // happens when just one row (headings contain no a)
        if ($field.length == 0) {
            $field = $('#table_results').find('thead').find('th:nth('+ (this_field_index-4 )+')').clone();
        }
    }
    $field.children().remove();
    var field_name = $.trim($field.text());

    return field_name;
}

/**
 * The function that iterates over each row in the table_results and appends a
 * new inline edit anchor to each table row.
 *
 */
function appendInlineAnchor() {
    var disp_mode = $("#top_direction_dropdown").val();

    if (disp_mode == 'vertical') {
        // there can be one or two tr containing this class, depending
        // on the ModifyDeleteAtLeft and ModifyDeleteAtRight cfg parameters
        $('#table_results tr')
            .find('.edit_row_anchor')
            .removeClass('edit_row_anchor')
            .parent().each(function() {
            var $this_tr = $(this);
            var $cloned_tr = $this_tr.clone();

            var $img_object = $cloned_tr.find('img:first').attr('title', PMA_messages['strInlineEdit']);
            if ($img_object.length != 0) {
                var img_src = $img_object.attr('src').replace(/b_edit/,'b_inline_edit');
                $img_object.attr('src', img_src);
            }

            $cloned_tr.find('td')
             .addClass('inline_edit_anchor')
             .find('a').attr('href', '#');
            var $edit_span = $cloned_tr.find('span:contains("' + PMA_messages['strEdit'] + '")');
            var $span = $cloned_tr.find('a').find('span');
            if ($edit_span.length > 0) {
                $span.text(' ' + PMA_messages['strInlineEdit']);
                $span.prepend($img_object);
            } else {
                $span.text('');
                $span.append($img_object);
            }

            $cloned_tr.insertAfter($this_tr);
        });

        $('#rowsDeleteForm').find('tbody').find('th').each(function() {
            var $this_th = $(this);
            if ($this_th.attr('rowspan') == 4) {
                $this_th.attr('rowspan', '5');
            }
        });
    }
    else {
        // horizontal mode
        $('.edit_row_anchor').each(function() {

            var $this_td = $(this);
            $this_td.removeClass('edit_row_anchor');

            var $cloned_anchor = $this_td.clone();

            var $img_object = $cloned_anchor.find('img').attr('title', PMA_messages['strInlineEdit']);
            if ($img_object.length != 0) {
                var img_src = $img_object.attr('src').replace(/b_edit/,'b_inline_edit');
                $img_object.attr('src', img_src);
                $cloned_anchor.find('a').attr('href', '#');
                var $edit_span = $cloned_anchor.find('span:contains("' + PMA_messages['strEdit'] + '")');
                var $span = $cloned_anchor.find('a').find('span');
                if ($edit_span.length > 0) {
                    $span.text(' ' + PMA_messages['strInlineEdit']);
                    $span.prepend($img_object);
                } else {
                    $span.text('');
                    $span.append($img_object);
                }
            } else {
                // Only text is displayed. See $cfg['PropertiesIconic']
                $cloned_anchor.find('a').attr('href', '#');
                $cloned_anchor.find('a span').text(PMA_messages['strInlineEdit']);

                // the link was too big so <input type="image"> is there
                $img_object = $cloned_anchor.find('input:image').attr('title', PMA_messages['strInlineEdit']);
                if ($img_object.length > 0) {
                    var img_src = $img_object.attr('src').replace(/b_edit/,'b_inline_edit');
                    $img_object.attr('src', img_src);
                }
                $cloned_anchor
                 .find('.clickprevimage')
                 .text(' ' + PMA_messages['strInlineEdit']);
            }

            $cloned_anchor
             .addClass('inline_edit_anchor');

            $this_td.after($cloned_anchor);
        });

        $('#rowsDeleteForm').find('thead, tbody').find('th').each(function() {
            var $this_th = $(this);
            if ($this_th.attr('colspan') == 4) {
                $this_th.attr('colspan', '5');
            }
        });
    }
}

/**#@+
 * @namespace   jQuery
 */

/**
 * @description <p>Ajax scripts for sql and browse pages</p>
 *
 * Actions ajaxified here:
 * <ul>
 * <li>Retrieve results of an SQL query</li>
 * <li>Paginate the results table</li>
 * <li>Sort the results table</li>
 * <li>Change table according to display options</li>
 * <li>Inline editing of data</li>
 * </ul>
 *
 * @name        document.ready
 * @memberOf    jQuery
 */
$(document).ready(function() {

    /**
     * Set a parameter for all Ajax queries made on this page.  Don't let the
     * web server serve cached pages
     */
    $.ajaxSetup({
        cache: 'false'
    });

    /**
     * current value of the direction in which the table is displayed
     * @type    String
     * @fieldOf jQuery
     * @name    disp_mode
     */
    var disp_mode = $("#top_direction_dropdown").val();

    /**
     * Update value of {@link jQuery.disp_mode} everytime the direction dropdown changes value
     * @memberOf    jQuery
     * @name        direction_dropdown_change
     */
    $("#top_direction_dropdown, #bottom_direction_dropdown").live('change', function(event) {
        disp_mode = $(this).val();
    })

    /**
     * Attach the {@link appendInlineAnchor} function to a custom event, which
     * will be triggered manually everytime the table of results is reloaded
     * @memberOf    jQuery
     */
    $("#sqlqueryresults").live('appendAnchor',function() {
        appendInlineAnchor();
    })

    /**
     * Trigger the appendAnchor event to prepare the first table for inline edit
     * (see $GLOBALS['cfg']['AjaxEnable'])
     * @memberOf    jQuery
     * @name        sqlqueryresults_trigger
     */
    $("#sqlqueryresults.ajax").trigger('appendAnchor');

    /**
     * Append the "Show/Hide query box" message to the query input form
     *
     * @memberOf jQuery
     * @name    appendToggleSpan
     */
    // do not add this link more than once
    if (! $('#sqlqueryform').find('a').is('#togglequerybox')) {
        $('<a id="togglequerybox"></a>')
        .html(PMA_messages['strHideQueryBox'])
        .appendTo("#sqlqueryform")
        // initially hidden because at this point, nothing else
        // appears under the link
        .hide();

        // Attach the toggling of the query box visibility to a click
        $("#togglequerybox").bind('click', function() {
            var $link = $(this)
            $link.siblings().slideToggle("fast");
            if ($link.text() == PMA_messages['strHideQueryBox']) {
                $link.text(PMA_messages['strShowQueryBox']);
                // cheap trick to add a spacer between the menu tabs
                // and "Show query box"; feel free to improve!
                $('#togglequerybox_spacer').remove();
                $link.before('<br id="togglequerybox_spacer" />');
            } else {
                $link.text(PMA_messages['strHideQueryBox']);
            }
            // avoid default click action
            return false;
        })
    }

    /**
     * Ajax Event handler for 'SQL Query Submit'
     *
     * @see         PMA_ajaxShowMessage()
     * @see         $cfg['AjaxEnable']
     * @memberOf    jQuery
     * @name        sqlqueryform_submit
     */
    $("#sqlqueryform.ajax input:submit").live('click', function(event) {
        event.preventDefault();

        var $form = $(this).closest("form");
        var clicked_button = $(this).attr('id');

        if ('button_submit_query' == clicked_button) {
            $form.find("select[name=id_bookmark]").attr("value","");
        }

        if (! checkSqlQuery($form[0])) {
            return false;
        }

        // remove any div containing a previous error message
        $('.error').remove();

        var $msgbox = PMA_ajaxShowMessage();

        PMA_prepareForAjaxRequest($form);

        $.post($form.attr('action'), $form.serialize() , function(data) {
            if(data.success == true) {
                // fade out previous messages, if any
                $('.success').fadeOut();
                $('.sqlquery_message').fadeOut();
                // show a message that stays on screen
                if (typeof data.sql_query != 'undefined') {
                    $('<div class="sqlquery_message"></div>')
                     .html(data.sql_query)
                     .insertBefore('#sqlqueryform');
                    // unnecessary div that came from data.sql_query
                    $('.notice').remove();
                } else {
                    $('#sqlqueryform').before(data.message);
                }
                $('#sqlqueryresults').show();
                // this happens if a USE command was typed
                if (typeof data.reload != 'undefined') {
                    // Unbind the submit event before reloading. See bug #3295529
                    $("#sqlqueryform.ajax").die('submit');
                    $form.find('input[name=db]').val(data.db);
                    // need to regenerate the whole upper part
                    $form.find('input[name=ajax_request]').remove();
                    $form.append('<input type="hidden" name="reload" value="true" />');
                    $.post('db_sql.php', $form.serialize(), function(data) {
                        $('body').html(data);
                    }); // end inner post
                }
            }
            else if (data.success == false ) {
                // show an error message that stays on screen
                $('#sqlqueryform').before(data.error);
                $('#sqlqueryresults').hide();
            }
            else {
                // real results are returned
                // fade out previous messages, if any
                $('.success').fadeOut();
                $('.sqlquery_message').fadeOut();
                $received_data = $(data);
                $zero_row_results = $received_data.find('textarea[name="sql_query"]');
                // if zero rows are returned from the query execution
                if ($zero_row_results.length > 0) {
                    $('#sqlquery').val($zero_row_results.val());
                } else {
                    $('#sqlqueryresults').show();
                    $("#sqlqueryresults").html(data);
                    $("#sqlqueryresults").trigger('appendAnchor');
                    $('#togglequerybox').show();
                    if($("#togglequerybox").siblings(":visible").length > 0) {
                        $("#togglequerybox").trigger('click');
                    }
                    PMA_init_slider();
                }
            }
            PMA_ajaxRemoveMessage($msgbox);

        }) // end $.post()
    }) // end SQL Query submit

    /**
     * Ajax Event handlers for Paginating the results table
     */

    /**
     * Paginate when we click any of the navigation buttons
     * (only if the element has the ajax class, see $cfg['AjaxEnable'])
     * @memberOf    jQuery
     * @name        paginate_nav_button_click
     * @uses        PMA_ajaxShowMessage()
     * @see         $cfg['AjaxEnable']
     */
    $("input[name=navig].ajax").live('click', function(event) {
        /** @lends jQuery */
        event.preventDefault();

        var $msgbox = PMA_ajaxShowMessage();

        /**
         * @var $the_form    Object referring to the form element that paginates the results table
         */
        var $the_form = $(this).parent("form");

        $the_form.append('<input type="hidden" name="ajax_request" value="true" />');

        $.post($the_form.attr('action'), $the_form.serialize(), function(data) {
            $("#sqlqueryresults").html(data);
            $("#sqlqueryresults").trigger('appendAnchor');
            PMA_init_slider();
            
            PMA_ajaxRemoveMessage($msgbox);
        }) // end $.post()
    })// end Paginate results table

    /**
     * Paginate results with Page Selector dropdown
     * @memberOf    jQuery
     * @name        paginate_dropdown_change
     * @see         $cfg['AjaxEnable']
     */
    $("#pageselector").live('change', function(event) {
        var $the_form = $(this).parent("form");

        if ($(this).hasClass('ajax')) {
            event.preventDefault();

            var $msgbox = PMA_ajaxShowMessage();

            $.post($the_form.attr('action'), $the_form.serialize() + '&ajax_request=true', function(data) {
                $("#sqlqueryresults").html(data);
                $("#sqlqueryresults").trigger('appendAnchor');
                PMA_init_slider();
                PMA_ajaxRemoveMessage($msgbox); 
            }) // end $.post()
        } else {
            $the_form.submit();
        }

    })// end Paginate results with Page Selector

    /**
     * Ajax Event handler for sorting the results table
     * @memberOf    jQuery
     * @name        table_results_sort_click
     * @see         $cfg['AjaxEnable']
     */
    $("#table_results.ajax").find("a[title=Sort]").live('click', function(event) {
        event.preventDefault();

        var $msgbox = PMA_ajaxShowMessage();

        $anchor = $(this);

        $.get($anchor.attr('href'), $anchor.serialize() + '&ajax_request=true', function(data) {
            $("#sqlqueryresults")
             .html(data)
             .trigger('appendAnchor');
            PMA_ajaxRemoveMessage($msgbox);
        }) // end $.get()
    })//end Sort results table

    /**
     * Ajax Event handler for the display options
     * @memberOf    jQuery
     * @name        displayOptionsForm_submit
     * @see         $cfg['AjaxEnable']
     */
    $("#displayOptionsForm.ajax").live('submit', function(event) {
        event.preventDefault();

        $form = $(this);

        $.post($form.attr('action'), $form.serialize() + '&ajax_request=true' , function(data) {
            $("#sqlqueryresults")
             .html(data)
             .trigger('appendAnchor');
            PMA_init_slider();
        }) // end $.post()
    })
    //end displayOptionsForm handler

    /**
     * Ajax Event handlers for Inline Editing
     */

    /**
     * On click, replace the fields of current row with an input/textarea
     * @memberOf    jQuery
     * @name        inline_edit_start
     * @see         PMA_ajaxShowMessage()
     * @see         getFieldName()
     */
    $(".inline_edit_anchor span a").live('click', function(event) {
        /** @lends jQuery */
        event.preventDefault();

        var $edit_td = $(this).parents('td');
        $edit_td.removeClass('inline_edit_anchor').addClass('inline_edit_active').parent('tr').addClass('noclick');

        // Adding submit and hide buttons to inline edit <td>.
        // For "hide" button the original data to be restored is 
        //  kept in the jQuery data element 'original_data' inside the <td>.
        // Looping through all columns or rows, to find the required data and then storing it in an array.

        var $this_children = $edit_td.children('span.nowrap').children('a').children('span.nowrap');
        // Keep the original data preserved.
        $data_a = $edit_td.children('span.nowrap').children('a').clone();

        // Change the inline edit to save.
        var $img_object = $this_children.find('img');

        // If texts are displayed. See $cfg['PropertiesIconic']
        if ($this_children.parent('a').find('span:contains("' + PMA_messages['strInlineEdit'] + '")').length > 0) {
            $this_children.text(' ' + PMA_messages['strSave']);
        } else {
            $this_children.empty();
        }

        // If icons are displayed. See $cfg['PropertiesIconic']
        if ($img_object.length > 0) {
            $img_object.attr('title', PMA_messages['strSave']);
            var img_src = $img_object.attr('src').replace(/b_inline_edit/,'b_save');
            $img_object.attr('src', img_src);
            $this_children.prepend($img_object);
        }

        // Clone the save link and change it to create the hide link.
        var $hide_a = $edit_td.children('span.nowrap').children('a').clone().attr('id', 'hide');
        var $hide_span = $hide_a.find('span');
        var $img_object = $hide_a.find('span img');

        // If texts are displayed. See $cfg['PropertiesIconic']
        if ($hide_a.find('span:contains("' + PMA_messages['strSave'] + '")').length > 0) {
            $hide_span.text(' ' + PMA_messages['strHide']);
        } else {
            $hide_span.empty();
        }

        // If icons are displayed. See $cfg['PropertiesIconic']
        if ($img_object.length > 0) {
            $img_object.attr('title', PMA_messages['strHide']);
            var img_src = $img_object.attr('src').replace(/b_save/,'b_close');
            $img_object.attr('src', img_src);
            $hide_span.prepend($img_object);
        }

        // Add hide icon and/or text.
        $edit_td.children('span.nowrap').append($('<br /><br />')).append($hide_a);

        if (disp_mode != 'vertical') {
            $('#table_results tbody tr td span a#hide').click(function() {
                var $this_hide = $(this).parents('td');

                var $this_span = $this_hide.find('span');
                $this_span.find('a, br').remove();
                $this_span.append($data_a.clone());

                $this_hide.removeClass("inline_edit_active hover").addClass("inline_edit_anchor");
                $this_hide.parent().removeClass("hover noclick");
                $this_hide.siblings().removeClass("hover");

                var last_column = $this_hide.siblings().length;
                var txt = '';
                for(var i = 4; i < last_column; i++) {
                    if($this_hide.siblings("td:eq(" + i + ")").hasClass("inline_edit") == false) {
                        continue;
                    }
                    txt = $this_hide.siblings("td:eq(" + i + ")").data('original_data');
                    if($this_hide.siblings("td:eq(" + i + ")").children().length != 0) {
                        $this_hide.siblings("td:eq(" + i + ")").empty();
                        $this_hide.siblings("td:eq(" + i + ")").append(txt);
                    }
                }
                $(this).prev().prev().remove();
                $(this).prev().remove();
                $(this).remove();
            });
        } else {
            var txt = '';
            var rows = $edit_td.parent().siblings().length;

            $('#table_results tbody tr td span a#hide').click(function() {
                var $hide_a = $(this);
                var pos = $hide_a.parents('td').index();

                var $this_span = $hide_a.parent();
                $this_span.find('a, br').remove();
                $this_span.append($data_a.clone());

                var $this_row = $this_span.parents('tr');
                // changing inline_edit_active to inline_edit_anchor
                $this_row.siblings("tr:eq(3) td:eq(" + pos + ")").removeClass("inline_edit_active").addClass("inline_edit_anchor");

                // removing marked and hover classes.
                $this_row.parent('tbody').find('tr').find("td:eq(" + pos + ")").removeClass("marked hover");

                for( var i = 6; i <= rows + 2; i++){
                    if( $this_row.siblings("tr:eq(" + i + ") td:eq(" + pos + ")").hasClass("inline_edit") == false) {
                        continue;
                    }
                    txt = $this_row.siblings("tr:eq(" + i + ") td:eq(" + pos + ")").data('original_data');
                    $this_row.siblings("tr:eq(" + i + ") td:eq(" + pos + ")").empty();
                    $this_row.siblings("tr:eq(" + i + ") td:eq(" + pos + ")").append(txt);
                }
                $(this).prev().remove();
                $(this).prev().remove();
                $(this).remove();
            });
        }

        // Initialize some variables
        if(disp_mode == 'vertical') {
            /**
             * @var this_row_index  Index of the current <td> in the parent <tr>
             *                      Current <td> is the inline edit anchor.
             */
            var this_row_index = $edit_td.index();
            /**
             * @var $input_siblings  Object referring to all inline editable events from same row
             */
            var $input_siblings = $edit_td.parents('tbody').find('tr').find('.inline_edit:nth('+this_row_index+')');
            /**
             * @var where_clause    String containing the WHERE clause to select this row
             */
            var where_clause = $edit_td.parents('tbody').find('tr').find('.where_clause:nth('+this_row_index+')').val();
        }
        // horizontal mode
        else {
            var this_row_index = $edit_td.parent().index();
            var $input_siblings = $edit_td.parent('tr').find('.inline_edit');
            var where_clause = $edit_td.parent('tr').find('.where_clause').val();
        }

        $input_siblings.each(function() {
            /** @lends jQuery */
            /**
             * @var data_value  Current value of this field
             */
            var data_value = $(this).html();

            // We need to retrieve the value from the server for truncated/relation fields
            // Find the field name

            /**
             * @var this_field  Object referring to this field (<td>)
             */
            var $this_field = $(this);
            /**
             * @var field_name  String containing the name of this field.
             * @see getFieldName()
             */
            var field_name = getFieldName($this_field, disp_mode);
            /**
             * @var relation_curr_value String current value of the field (for fields that are foreign keyed).
             */
            var relation_curr_value = $this_field.find('a').text();
            /**
             * @var relation_key_or_display_column String relational key if in 'Relational display column' mode,
             * relational display column if in 'Relational key' mode (for fields that are foreign keyed).
             */
            var relation_key_or_display_column = $this_field.find('a').attr('title');
            /**
             * @var curr_value String current value of the field (for fields that are of type enum or set).
             */
            var curr_value = $this_field.text();

            if($this_field.is(':not(.not_null)')){
                // add a checkbox to mark null for all the field that are nullable.
                $this_field.html('<div class="null_div">Null :<input type="checkbox" class="checkbox_null_'+ field_name + '_' + this_row_index +'"></div>');
                // check the 'checkbox_null_<field_name>_<row_index>' if the corresponding value is null
                if($this_field.is('.null')) {
                    $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', true);
                }

                // if the select/editor is changed un-check the 'checkbox_null_<field_name>_<row_index>'.
                if ($this_field.is('.enum, .set')) {
                    $this_field.find('select').live('change', function(e) {
                        $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', false);
                    })
                } else if ($this_field.is('.relation')) {
                    $this_field.find('select').live('change', function(e) {
                        $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', false);
                    })
                    $this_field.find('.browse_foreign').live('click', function(e) {
                        $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', false);
                    })
                } else {
                    $this_field.find('textarea').live('keypress', function(e) {
                        // FF errorneously triggers for modifier keys such as tab (bug #3357837)
                        if (e.which != 0) {
                            $('.checkbox_null_' + field_name + '_' + this_row_index).attr('checked', false);
                        }
                    })
                }

                // if 'checkbox_null_<field_name>_<row_index>' is clicked empty the corresponding select/editor.
                $('.checkbox_null_' + field_name + '_' + this_row_index).bind('click', function(e) {
                    if ($this_field.is('.enum')) {
                        $this_field.find('select').attr('value', '');
                    } else if ($this_field.is('.set')) {
                        $this_field.find('select').find('option').each(function() {
                            var $option = $(this);
                            $option.attr('selected', false);
                        })
                    } else if ($this_field.is('.relation')) {
                        // if the dropdown is there to select the foreign value
                        if ($this_field.find('select').length > 0) {
                            $this_field.find('select').attr('value', '');
                        // if foriegn value is selected by browsing foreing values
                        } else {
                            $this_field.find('span.curr_value').empty();
                        }
                    } else {
                        $this_field.find('textarea').val('');
                    }
                })

            } else {
                $this_field.html('<div class="null_div"></div>');
            }

            // In each input sibling, wrap the current value in a textarea
            // and store the current value in a hidden span
            if($this_field.is(':not(.truncated, .transformed, .relation, .enum, .set, .null)')) {
                // handle non-truncated, non-transformed, non-relation values

                value = data_value.replace("<br>", "\n");
                // We don't need to get any more data, just wrap the value
                $this_field.append('<textarea>' + value + '</textarea>');
                $this_field.data('original_data', data_value);
            }
            else if($this_field.is('.truncated, .transformed')) {
                /** @lends jQuery */
                //handle truncated/transformed values values

                /**
                 * @var sql_query   String containing the SQL query used to retrieve value of truncated/transformed data
                 */
                var sql_query = 'SELECT `' + field_name + '` FROM `' + window.parent.table + '` WHERE ' + PMA_urldecode(where_clause);

                // Make the Ajax call and get the data, wrap it and insert it
                $.post('sql.php', {
                    'token' : window.parent.token,
                    'server' : window.parent.server,
                    'db' : window.parent.db,
                    'ajax_request' : true,
                    'sql_query' : sql_query,
                    'inline_edit' : true
                }, function(data) {
                    if(data.success == true && $edit_td.hasClass('inline_edit_active')) {
                        $this_field.append('<textarea>'+data.value+'</textarea>');
                    } else {
                        PMA_ajaxShowMessage(data.error);
                    }
                }) // end $.post()
                $this_field.data('original_data', data_value);
            }
            else if($this_field.is('.relation')) {
                /** @lends jQuery */
                //handle relations

                /**
                 * @var post_params Object containing parameters for the POST request
                 */
                var post_params = {
                        'ajax_request' : true,
                        'get_relational_values' : true,
                        'server' : window.parent.server,
                        'db' : window.parent.db,
                        'table' : window.parent.table,
                        'column' : field_name,
                        'token' : window.parent.token,
                        'curr_value' : relation_curr_value,
                        'relation_key_or_display_column' : relation_key_or_display_column
                }

                $.post('sql.php', post_params, function(data) {
                    if ($edit_td.hasClass('inline_edit_active')) {
                        $this_field.append(data.dropdown);
                    }
                }) // end $.post()
                $this_field.data('original_data', data_value);
            }
            else if($this_field.is('.enum')) {
                /** @lends jQuery */
                //handle enum fields

                /**
                 * @var post_params Object containing parameters for the POST request
                 */
                var post_params = {
                        'ajax_request' : true,
                        'get_enum_values' : true,
                        'server' : window.parent.server,
                        'db' : window.parent.db,
                        'table' : window.parent.table,
                        'column' : field_name,
                        'token' : window.parent.token,
                        'curr_value' : curr_value
                }
                $.post('sql.php', post_params, function(data) {
                    if ($edit_td.hasClass('inline_edit_active')) {
                        $this_field.append(data.dropdown);
                    }
                }) // end $.post()
                $this_field.data('original_data', data_value);
            }
            else if($this_field.is('.set')) {
                /** @lends jQuery */
                //handle set fields

                /**
                 * @var post_params Object containing parameters for the POST request
                 */
                var post_params = {
                        'ajax_request' : true,
                        'get_set_values' : true,
                        'server' : window.parent.server,
                        'db' : window.parent.db,
                        'table' : window.parent.table,
                        'column' : field_name,
                        'token' : window.parent.token,
                        'curr_value' : curr_value
                }

                $.post('sql.php', post_params, function(data) {
                    if ($edit_td.hasClass('inline_edit_active')) {
                        $this_field.append(data.select);
                    }
                }) // end $.post()
                $this_field.data('original_data', data_value);
            }
            else if($this_field.is('.null')) {
                //handle null fields
                $this_field.append('<textarea></textarea>');
                $this_field.data('original_data', 'NULL');
            }
        })
    }) // End On click, replace the current field with an input/textarea

    /**
     * After editing, clicking again should post data
     *
     * @memberOf    jQuery
     * @name        inline_edit_save
     * @see         PMA_ajaxShowMessage()
     * @see         getFieldName()
     */
    $(".inline_edit_active span a").live('click', function(event) {
        /** @lends jQuery */

        event.preventDefault();

        /**
         * @var $this_td    Object referring to the td containing the
         * "Inline Edit" link that was clicked to save the row that is
         * being edited
         *
         */
        var $this_td = $(this).parent().parent();
        var $test_element = ''; // to test the presence of a element

        // Initialize variables
        if(disp_mode == 'vertical') {
            /**
             * @var this_td_index  Index of the current <td> in the parent <tr>
             *                      Current <td> is the inline edit anchor.
             */
            var this_td_index = $this_td.index();
            /**
             * @var $input_siblings  Object referring to all inline editable events from same row
             */
            var $input_siblings = $this_td.parents('tbody').find('tr').find('.inline_edit:nth('+this_td_index+')');
            /**
             * @var where_clause    String containing the WHERE clause to select this row
             */
            var where_clause = $this_td.parents('tbody').find('tr').find('.where_clause:nth('+this_td_index+')').val();
        } else {
            var $input_siblings = $this_td.parent('tr').find('.inline_edit');
            var where_clause = $this_td.parent('tr').find('.where_clause').val();
        }

        /**
         * @var nonunique   Boolean, whether this row is unique or not
         */
        if($this_td.is('.nonunique')) {
            var nonunique = 0;
        }
        else {
            var nonunique = 1;
        }

        // Collect values of all fields to submit, we don't know which changed
        /**
         * @var relation_fields Array containing the name/value pairs of relational fields
         */
        var relation_fields = {};
        /**
         * @var relational_display string 'K' if relational key, 'D' if relational display column 
         */
        var relational_display = $("#relational_display_K").attr('checked') ? 'K' : 'D';
        /**
         * @var transform_fields    Array containing the name/value pairs for transformed fields
         */
        var transform_fields = {};
        /**
         * @var transformation_fields   Boolean, if there are any transformed fields in this row
         */
        var transformation_fields = false;

        /**
         * @var sql_query String containing the SQL query to update this row
         */
        var sql_query = 'UPDATE `' + window.parent.table + '` SET ';

        var need_to_post = false;
        
        var new_clause = '';
        var prev_index = -1;

        $input_siblings.each(function() {
            /** @lends jQuery */
            /**
             * @var this_field  Object referring to this field (<td>)
             */
            var $this_field = $(this);

            /**
             * @var field_name  String containing the name of this field.
             * @see getFieldName()
             */
            var field_name = getFieldName($this_field, disp_mode);

            /**
             * @var this_field_params   Array temporary storage for the name/value of current field
             */
            var this_field_params = {};

            if($this_field.is('.transformed')) {
                transformation_fields =  true;
            }
            /**
             * @var is_null String capturing whether 'checkbox_null_<field_name>_<row_index>' is checked.
             */
            var is_null = $this_field.find('input:checkbox').is(':checked');
            var value;
            var addQuotes = true;

            if (is_null) {
                sql_query += ' `' + field_name + "`=NULL , ";
                need_to_post = true;
            } else {
                if($this_field.is(":not(.relation, .enum, .set, .bit)")) {
                    this_field_params[field_name] = $this_field.find('textarea').val();
                    if($this_field.is('.transformed')) {
                        $.extend(transform_fields, this_field_params);
                    }
                } else if ($this_field.is('.bit')) {
                    this_field_params[field_name] = '0b' + $this_field.find('textarea').val();
                    addQuotes = false;
                } else if ($this_field.is('.set')) {
                    $test_element = $this_field.find('select');
                    this_field_params[field_name] = $test_element.map(function(){
                        return $(this).val();
                    }).get().join(",");
                } else {
                    // results from a drop-down
                    $test_element = $this_field.find('select');
                    if ($test_element.length != 0) {
                        this_field_params[field_name] = $test_element.val();
                    }

                    // results from Browse foreign value
                    $test_element = $this_field.find('span.curr_value');
                    if ($test_element.length != 0) {
                        this_field_params[field_name] = $test_element.text();
                    }

                    if($this_field.is('.relation')) {
                        $.extend(relation_fields, this_field_params);
                    }
                }
                    if(where_clause.indexOf(field_name) > prev_index){
                        new_clause += '`' + window.parent.table + '`.' + '`' + field_name + "` = '" + this_field_params[field_name].replace(/'/g,"''") + "'" + ' AND ';
                    }
                if (this_field_params[field_name] != $this_field.data('original_data')) {
                    if (addQuotes == true) {
                        sql_query += ' `' + field_name + "`='" + this_field_params[field_name].replace(/'/g, "''") + "', ";
                    } else {
                        sql_query += ' `' + field_name + "`=" + this_field_params[field_name].replace(/'/g, "''") + ", ";
                    }
                    need_to_post = true;
                }
            }
        })

        /*  
         * update the where_clause, remove the last appended ' AND '
         * */

        //Remove the last ',' appended in the above loop
        sql_query = sql_query.replace(/,\s$/, '');
        //Fix non-escaped backslashes
        sql_query = sql_query.replace(/\\/g, '\\\\');
        new_clause = new_clause.substring(0, new_clause.length-5);
        new_clause = PMA_urlencode(new_clause);
        sql_query += ' WHERE ' + PMA_urldecode(where_clause);
        // Avoid updating more than one row in case there is no primary key
        // (happened only for duplicate rows)
        sql_query += ' LIMIT 1';
        /**
         * @var rel_fields_list  String, url encoded representation of {@link relations_fields}
         */
        var rel_fields_list = $.param(relation_fields);

        /**
         * @var transform_fields_list  String, url encoded representation of {@link transform_fields}
         */
        var transform_fields_list = $.param(transform_fields);

        // if inline_edit is successful, we need to go back to default view
        var $del_hide = $(this).parent();
        var $chg_submit = $(this);

        if (need_to_post) {
            // Make the Ajax post after setting all parameters
            /**
             * @var post_params Object containing parameters for the POST request
             */
            var post_params = {'ajax_request' : true,
                            'sql_query' : sql_query,
                            'disp_direction' : disp_mode,
                            'token' : window.parent.token,
                            'server' : window.parent.server,
                            'db' : window.parent.db,
                            'table' : window.parent.table,
                            'clause_is_unique' : nonunique,
                            'where_clause' : where_clause,
                            'rel_fields_list' : rel_fields_list,
                            'do_transformations' : transformation_fields,
                            'transform_fields_list' : transform_fields_list,
                            'relational_display' : relational_display,
                            'goto' : 'sql.php',
                            'submit_type' : 'save'
                          };

            $.post('tbl_replace.php', post_params, function(data) {
                if(data.success == true) {
                    PMA_ajaxShowMessage(data.message);
                    if(disp_mode == 'vertical') {
                        $this_td.parents('tbody').find('tr').find('.where_clause:nth(' + this_td_index + ')').attr('value', new_clause);
                    }
                    else {
                        $this_td.parent('tr').find('.where_clause').attr('value', new_clause);
                    }
                    // remove possible previous feedback message
                    $('#result_query').remove();
                    if (typeof data.sql_query != 'undefined') {
                        // display feedback
                        $('#sqlqueryresults').prepend(data.sql_query);
                    }
                    PMA_unInlineEditRow($del_hide, $chg_submit, $this_td, $input_siblings, data, disp_mode);
                } else {
                    PMA_ajaxShowMessage(data.error);
                };
            }) // end $.post()
        } else {
            // no posting was done but still need to display the row
            // in its previous format
            PMA_unInlineEditRow($del_hide, $chg_submit, $this_td, $input_siblings, '', disp_mode);
        }
    }) // End After editing, clicking again should post data
}, 'top.frame_content') // end $(document).ready()


/**
 * Visually put back the row in the state it was before entering Inline edit 
 *
 * (when called in the situation where no posting was done, the data
 * parameter is empty) 
 */
function PMA_unInlineEditRow($del_hide, $chg_submit, $this_td, $input_siblings, data, disp_mode) {

    // deleting the hide button. remove <br><br><a> tags
    $del_hide.find('a, br').remove();
    // append inline edit button.
    $del_hide.append($data_a.clone());

    // changing inline_edit_active to inline_edit_anchor
    $this_td.removeClass('inline_edit_active').addClass('inline_edit_anchor');

    // removing hover, marked and noclick classes
    $this_td.parent('tr').removeClass('noclick');
    if(disp_mode != 'vertical') {
        $this_td.parent('tr').removeClass('hover').find('td').removeClass('hover');
    } else {
        $this_td.parents('tbody').find('tr').find('td:eq(' + $this_td.index() + ')').removeClass('marked hover');
    }

    $input_siblings.each(function() {
        // Inline edit post has been successful.
        $this_sibling = $(this);

        var is_null = $this_sibling.find('input:checkbox').is(':checked');
        if (is_null) {
            $this_sibling.html('NULL');
            $this_sibling.addClass('null');
        } else {
            $this_sibling.removeClass('null');
            if($this_sibling.is(':not(.relation, .enum, .set)')) {
                /**
                 * @var new_html    String containing value of the data field after edit
                 */
                var new_html = $this_sibling.find('textarea').val();

                if($this_sibling.is('.transformed')) {
                    var field_name = getFieldName($this_sibling, disp_mode);
                    if (typeof data.transformations != 'undefined') {
                        $.each(data.transformations, function(key, value) {
                            if(key == field_name) {
                                if($this_sibling.is('.text_plain, .application_octetstream')) {
                                    new_html = value;
                                    return false;
                                } else {
                                    var new_value = $this_sibling.find('textarea').val();
                                    new_html = $(value).append(new_value);
                                    return false;
                                }
                            }
                        })
                    }
                }
            } else {
                var new_html = '';
                var new_value = '';
                $test_element = $this_sibling.find('select');
                if ($test_element.length != 0) {
                    new_value = $test_element.val();
                }
                $test_element = $this_sibling.find('span.curr_value');
                if ($test_element.length != 0) {
                    new_value = $test_element.text();
                }

                if($this_sibling.is('.relation')) {
                    var field_name = getFieldName($this_sibling, disp_mode);
                    if (typeof data.relations != 'undefined') {
                        $.each(data.relations, function(key, value) {
                            if(key == field_name) {
                                new_html = $(value);
                                return false;
                            }
                        })
                    }
                } else if ($this_sibling.is('.enum')) {
                    new_html = new_value;
                } else if ($this_sibling.is('.set')) {
                    if (new_value != null) {
                        $.each(new_value, function(key, value) {
                            new_html = new_html + value + ',';
                        })
                        new_html = new_html.substring(0, new_html.length-1);
                    }
                }
            }
            $this_sibling.text(new_html);
        }
    })
}

/**
 * Starting from some th, change the class of all td under it
 */
function PMA_changeClassForColumn($this_th, newclass) {
    // index 0 is the th containing the big T
    var th_index = $this_th.index();
    var has_big_t = !$this_th.closest('tr').children(':first').hasClass('column_heading');
    // .eq() is zero-based
    if (has_big_t) {
        th_index--;
    }
    var $tds = $this_th.closest('table').find('tbody tr').find('td.data:eq('+th_index+')');
    if ($this_th.data('has_class_'+newclass)) {
        $tds.removeClass(newclass);
        $this_th.data('has_class_'+newclass, false);
    } else {
        $tds.addClass(newclass);
        $this_th.data('has_class_'+newclass, true);
    }
}

$(document).ready(function() {

    $('.browse_foreign').live('click', function(e) {
        e.preventDefault();
        window.open(this.href, 'foreigners', 'width=640,height=240,scrollbars=yes,resizable=yes');
        $anchor = $(this);
        $anchor.addClass('browse_foreign_clicked');
        return false;
    });

    /**
     * vertical column highlighting in horizontal mode when hovering over the column header
     */
    $('.column_heading.pointer').live('hover', function() {
        PMA_changeClassForColumn($(this), 'hover');
        });

    /**
     * vertical column marking in horizontal mode when clicking the column header
     */
    $('.column_heading.marker').live('click', function() {
        PMA_changeClassForColumn($(this), 'marked');
        });
})

/**#@- */
