"use strict";
$( document ).ready( function(){
    var default_value = $('#search_text').val();
    $("[name='select_column']").trigger( "onchange" );
    var selected_column = $("[name='select_column']").val()

    if( $('#'+selected_column).hasClass("select2-hidden-accessible") ){
        $('#'+$("[name='select_column']").val()).val(default_value).trigger('change');
        $('#search_text').attr('value','');
    } else {
        $('#search_text').val(default_value);
    } 
});

function add( id ) {
    let div = document.getElementById( id );
    const div_children = div.children;
    let tables = [];
    let js_buttons = [];
    
    for( let i = 0; i < div_children.length; i++ ) {
        if( div_children[i].classList.contains( "related_tables" ) ) {
            tables.push( div_children[i] );
        } else if( div_children[i].classList.contains( "js-button" ) ) {
            js_buttons.push( div_children[i] );
        }
    }

    if( tables[tables.length-1].classList.contains( "dbdata-cardized" ) ) {
        $('.dropdown').select2('destroy');

        let clone = tables[tables.length-1].cloneNode( true );
        
        clone = reduce_tables( clone );
        clone = increment_table_ids( clone, id );
        change_action( clone, "insert" );

        remove_links( clone );
        remove_images( clone );

        // Removes links.
        let links = clone.querySelectorAll( "a" );
        links.forEach( function ( link ) {
            if( ! link.classList.contains( 'redirect-link' ) ) {
                link.remove(); // NOTE: might be incompatible with IE.
            }
        } );

        // Removes images.
        let images = clone.querySelectorAll( "img" );
        images.forEach( function ( image ) {
            if( image.classList.contains( 'image-preview' ) ) {
                image.remove(); // NOTE: might be incompatible with IE.
            }
        } );

        // Resets UUIDs.
        let uuids = clone.querySelector( 'table' )
                         .querySelectorAll( 'input[data-type=\'uuid\']' );
        uuids.forEach( function ( input ) {
            input['value'] = uuid();
        } );

        tables[tables.length-1].appendChild( clone );

        $( '.dropdown' ).select2({ dropdownAutoWidth: true });
    } else if( tables[tables.length-1].classList.contains( "dbdata-tabular" ) ) {
        let last_table = tables[tables.length-1];
        const last_table_rows = last_table.querySelectorAll( "tr" );
        const last_row = last_table_rows[last_table_rows.length-1];

        $('.dropdown').select2('destroy');

        let clone_last_row = last_row.cloneNode( true );
        clone_last_row = increment_table_ids( clone_last_row, id );
        change_action( clone_last_row, "insert" );

        remove_links( clone_last_row );
        remove_images( clone_last_row );

        // Removes links.
        let links = clone_last_row.querySelectorAll( "a" );
        links.forEach( function ( link ) {
            if( ! link.classList.contains( 'redirect-link' ) ) {
                link.remove(); // NOTE: might be incompatible with IE.
            }
        } );

        // Removes images.
        let images = clone_last_row.querySelectorAll( "img" );
        images.forEach( function ( image ) {
            if( image.classList.contains( 'image-preview' ) ) {
                image.remove(); // NOTE: might be incompatible with IE.
            }
        } );

        // Resets UUIDs.
        let uuids = clone_last_row.querySelectorAll( 'input[data-type=\'uuid\']' );
        uuids.forEach( function ( input ) {
            input['value'] = uuid();
        } );

        let last_table_form = last_table.getElementsByClassName( "dbdata-input-form" )[0];
        // Existance of tbody is checked. Otherwise, last table
        // element is selected.
        let found_tbody = last_table_form.querySelectorAll( "tbody" );
        if( found_tbody.length > 0 ) {
            found_tbody[0].appendChild( clone_last_row );
        } else {
            last_table_form.lastChild.appendChild( clone_last_row );
        }

        $( '.dropdown' ).select2({ dropdownAutoWidth: true });

        js_buttons.forEach( function ( js_button ) {
            div.appendChild( js_button );
        } );
    }
}

function remove_links( element ) {
    let links = element.querySelectorAll( "a" );
    links.forEach( function ( link ) {
        if( ! link.classList.contains( 'redirect-link' ) ) {
            link.remove(); // NOTE: might be incompatable with IE.
        }
    } );
}

function remove_images( element ) {
    let images = element.querySelectorAll( "img" );
    images.forEach( function ( image ) {
        if( image.classList.contains( 'image-preview' ) ) {
            image.remove(); // NOTE: might be incompatable with IE.
        }
    } );
}

function reduce_tables( table, index ) {
    /* Only one and last table is kept.*/
    let reduced_table;
    if( index == null ) {
        reduced_table = table.children[table.children.length-1];
    } else {
        reduced_table = table.children[index];
    }

    // Check if any of the related tables have multiple entries. If yes,
    // the same reduction of tables is performed recursively.
    let table_children = reduced_table.children;
    Array.from( table_children ).forEach( function ( table_child ) {
        if( table_child.classList.contains( "related" ) &&
            table_child.classList.contains( "expandable" ) ) {
            let related_tables = table_child.children;
            Array.from( related_tables ).forEach( function ( related_table ) {
                if( related_table.classList.contains( "related_tables" ) &&
                    related_table.classList.contains( "dbdata-cardized" ) ) {
                    let last_related_entry = reduce_tables( related_table, 0 );
                    while( related_table.lastChild ) {
                        related_table.removeChild( related_table.lastChild );
                    }

                    related_table.appendChild( last_related_entry );
                } else if( related_table.classList.contains( "related_tables" ) &&
                           related_table.classList.contains( "dbdata-tabular" ) ) {

                    // Existance of tbody is checked. Otherwise, last table
                    // element is selected.
                    let found_tbody = related_table.querySelectorAll( "tbody" );
                    if( found_tbody.length > 0 ) {
                        let related_table_rows =
                            found_tbody[0].querySelectorAll( "tr" );
                        let rows_count = related_table_rows.length;

                        // Rows count differs when there is tbody.
                        while( rows_count > 1 ) {
                            related_table_rows[0]
                                .parentNode
                                .removeChild( related_table_rows[rows_count-1] );
                            rows_count--;
                        }
                    } else {
                        let related_table_rows =
                            related_table.querySelectorAll( "tr" );
                        let rows_count = related_table_rows.length;

                        // Rows count includes table header.
                        while( rows_count > 2 ) {
                            related_table_rows[0]
                                .parentNode
                                .removeChild( related_table_rows[rows_count-1] );
                            rows_count--;
                        }
                    }
                }
            } );

            hide_insert_form( table_child );
        }
    } );

    return reduced_table;
}

function remove( id ) {
    let div = document.getElementById( id );
    const div_children = div.children;
    let tables = [];
    for( let i = 0; i < div_children.length; i++ ) {
        if( div_children[i].classList.contains( "related_tables" ) ) {
            tables.push( div_children[i] );
        }
    }

    if( tables[tables.length-1].classList.contains( "dbdata-cardized" ) ) {
        let entries = tables[tables.length-1].children;
        let last_entry = entries[entries.length-1];
        const action = detect_action( last_entry );

        if( action === "insert" ) {
            if( entries.length > 1 ) {
                tables[tables.length-1].removeChild( last_entry );
            } else {
                $('.dropdown').select2('destroy');

                const selected_elements = tables[tables.length-1].querySelectorAll(
                    "input:not(.isexpanded), select:not(.related_table_selector), " +
                    "textarea, label, option"
                );
                let is_entry_empty = true;
                selected_elements.forEach( function( selected_element ) {
                    if( is_entry_empty == true && ! is_element_empty( selected_element ) ) {
                        is_entry_empty = false;
                    }
                    
                    empty_out_element( selected_element );
                    selected_element.classList.remove( "invalid" );
                    if( selected_element.classList.contains( "validation-message" ) ) {
                        selected_element.innerHTML = "";
                    }
                } );

                /* Hides the table there is only one empty row. */
                if( is_entry_empty ) {
                    reduce_tables( tables[tables.length-1] );
                    hide_insert_form_by_id( id );
                }

                $( '.dropdown' ).select2({ dropdownAutoWidth: true });
            }
        }
    } else { /* Terminal horizontal tables. */
        let last_table = tables[tables.length-1];
        const last_table_rows = last_table.querySelectorAll( "tr" );
        const last_row = last_table_rows[last_table_rows.length-1];
        const action = detect_action( last_row );

        if( action === "insert" ) {
            if( last_table_rows.length > 2 ) {
                last_row.parentNode.removeChild( last_row );
            } else {
                $('.dropdown').select2('destroy');

                const selected_elements =
                      last_row.querySelectorAll( "input, select, textarea, label, option" );
                let is_row_empty = true;
                selected_elements.forEach( function( selected_element ) {
                    if( is_row_empty == true && ! is_element_empty( selected_element ) ) {
                        is_row_empty = false;
                    }

                    // TODO: maybe it can be added to the conditional where empty elements
                    // are checked.
                    empty_out_element( selected_element );
                    selected_element.classList.remove( "invalid" );
                    if( selected_element.classList.contains( "validation-message" ) ) {
                        selected_element.innerHTML = "";
                    }
                } );

                /* Hides the table there is only one empty row. */
                if( is_row_empty ) {
                    hide_insert_form_by_id( id );
                }

                $( '.dropdown' ).select2({ dropdownAutoWidth: true });                
            }
        }
    }
}

function increment_table_ids( table, div_id ) {
    let ids = [ div_id ];
    let table_changeables = [];

    const related_expandables =
        table.getElementsByClassName( "related expandable" );
    const selected_elements =
        table.querySelectorAll( "input, select, textarea, label, option" );

    for( let i = 0; i < related_expandables.length; i++ ) {
        ids.push( related_expandables[i].id );
        table_changeables.push( related_expandables[i] );
    }
    for( let i = 0; i < selected_elements.length; i++ ) {
        table_changeables.push( selected_elements[i] );
    }

    const variables_to_increment = [ "id", "name", "htmlFor", "value", "onclick", "onchange" ];

    ids.forEach( function( id ) {
        for( let i = 0; i < table_changeables.length; i++ ) {
            // Changes variables that have values that correspond to id.
            variables_to_increment.forEach( function( variable ) {
                if( typeof table_changeables[i][variable] !== 'undefined' &&
                    table_changeables[i][variable] !== null &&
                    table_changeables[i][variable] !== "" ) {
                    if( variable === 'onclick' ) {
                        // HACK: storing 'onclick' string is not recommended.
                        let onclick_string =
                            table_changeables[i].getAttribute("onclick");
                        onclick_string =
                            increment_id( onclick_string, id, 1 );
                        table_changeables[i].setAttribute(
                            "onclick", onclick_string
                        );
                    } else if( variable === 'onchange' ) {
                        // HACK: storing 'onchange' string is not recommended.
                        let onchange_string =
                            table_changeables[i].getAttribute("onchange");
                        onchange_string =
                            increment_id( onchange_string, id, 1 );
                        table_changeables[i].setAttribute(
                            "onchange", onchange_string
                        );
                    } else {
                        if( variable === "value" &&
                            table_changeables[i].getAttribute( "type" ) === "file" ) {
                            return;
                        } else {
                            table_changeables[i][variable] =
                                increment_id( table_changeables[i][variable], id, 1 );
                        }
                    }
                }
            } );

            empty_out_element( table_changeables[i] );
            table_changeables[i].classList.remove( "invalid" );
            if( table_changeables[i].classList.contains( "validation-message" ) ) {
                table_changeables[i].innerHTML = "";
            }
        }
    } );
 
    return table;
}

function empty_out_element( element ) {
    if( element.getAttribute( "type" ) !== 'button' &&
        element.getAttribute( "type" ) !== 'hidden' &&
        element.getAttribute( "type" ) !== 'checkbox' &&
        element.getAttribute( "type" ) !== 'radio' &&
        element.tagName.toLowerCase() !== 'option' ) {
        element.value = "";
        if( typeof element.selectedIndex !== "undefined" &&
            element.className === "related_table_selector" ) {
            element.selectedIndex = 0;
        }
        if( typeof element.selectedIndex !== "undefined" &&
            element.className === "dropdown" ) {
            element.selectedIndex = element.length - 1;
        }
    }
    if( element.getAttribute( "type" ) === 'checkbox' &&
        element.className !== "isexpanded" &&
        element.className !== "expandable" ) {
        element.checked = false;
    }
}

function is_element_empty( element ) {
    if( ( element.getAttribute( "type" ) !== 'button' &&
          element.getAttribute( "type" ) !== 'hidden' &&
          element.getAttribute( "type" ) !== 'checkbox' &&
          element.getAttribute( "type" ) !== 'radio' &&
          element.tagName.toLowerCase()  !== 'option' &&
          element.value !== "" ) ||
        ( element.getAttribute( "type" ) === 'checkbox' &&
          element.className !== "expandable" &&
          element.checked ) ) {
        return false;
    } else {
        return true;
    }
}

function increment_id( name, basename, increment_by ) {
    const regexp_retrieve = new RegExp( basename + ":(\\d+)(\\.*)", "g" );

    const counter = regexp_retrieve.exec( name );
    if( counter !== null ) {
        const counter_name = parseInt( counter[1] ) + parseInt( increment_by );
        const counter_end = counter[2];

        const replace_with = basename + ":" + counter_name + counter_end;
        const updated_name = name.replace( regexp_retrieve, replace_with );

        return updated_name;
    } else {
        return name;
    }
}

function detect_action( element, id ) {
    let action = null;
    const labels = element.querySelectorAll( "label" );

    for( let i = 0; i < labels.length; i++ ) {
        const inputs = labels[i].querySelectorAll( "input" );
        for ( let j = 0; j < inputs.length; j++ ) {
            if( inputs[j].name.startsWith("action:") && inputs[j].type === "radio" &&
                inputs[j].checked ) {
                action = inputs[j].value;
                break;
            }
        }
        if( action !== null ) {
            break;
        }
    }

    return action;
}

function change_action( table, action ) {
    const labels = table.querySelectorAll( 'label' );
    labels.forEach( function( label ) {
        if( label.textContent === 'insert' ) {
            let inputs = label.querySelectorAll( 'input' );
            inputs.forEach( function( input ) {
                input.checked = 'checked';
                input.value = 'insert';
            } );
        }
    } );
}

function insert_suggested_value( id, type ) {
    const select_id = "select:" + id;
    const input_id = "input:" + id;
    const sel = document.getElementById( select_id );
    if( type === "text" ) {
        document.getElementById( input_id ).value =
            sel.options[sel.selectedIndex].text;
    } else {
        document.getElementById( input_id ).value = sel.value;
    }
}

function empty_out_hidden_inputs( id ) {
    let related_expandable = document.getElementById( id );
    if( related_expandable.style.display === 'none' ) {
        let selected_elements =
            related_expandable
                .querySelectorAll( "input, select, textarea, label, option" );
        selected_elements.forEach( function( selected_element ) {
            empty_out_element( selected_element );
            selected_element.classList.remove( "invalid" );
            if( selected_element.classList.contains( "validation-message" ) ) {
                selected_element.innerHTML = "";
            }
            
            // Creating new input is necessary, because browser does not
            // allow to copy file inputs.
            if( selected_element.getAttribute( "type" ) === 'file' ) {
                let input_name = selected_element.name;
                let parent_node = selected_element.parentNode;
                selected_element.remove();
                let input_file = document.createElement( "INPUT" );
                input_file.setAttribute( "type", "file" );
                input_file.setAttribute( "name", input_name );
                input_file.setAttribute( "value", null );
                parent_node.appendChild( input_file );
            }
        } );
    }
}

function unhide_insert_form( id ) {
    const add_table_id = "add-table:" + id;
    const table_name = document.getElementById(add_table_id).value;
    let expandables =
        document.querySelectorAll( 'div[id=\'' + table_name + '\'], ' +
                                   'label[for=\'expandable:' + table_name + '\']');
    expandables.forEach( function( expandable ) {
        expandable.style = "";
    });
    expandables[0].scrollIntoView( true );

    let uuid_fields = document.querySelector( 'div[id=\'' + table_name + '\']' )
                              .querySelector( 'table' )
                              .querySelectorAll( 'input[data-type=\'uuid\']' );
    for( let i = 0; i < uuid_fields.length; i++ ) {
        uuid_fields[i]["value"] = uuid();
    }
}

function hide_insert_form_by_id( id ) {
    document.getElementById(id).style = 'display: none';
    let expandables =
        document.querySelectorAll( 'div[id=\'' + id + '\'], ' +
                                   'label[for=\'expandable:' + id + '\']');
    expandables.forEach( function( expandable ) {
        expandable.style = "display: none";
    });

    let uuid_fields = document.querySelector( 'div[id=\'' + id + '\']' )
                              .querySelectorAll( 'input[data-type=\'uuid\']' );
    for( let i = 0; i < uuid_fields.length; i++ ) {
        uuid_fields[i]["value"] = '';
    }
}

function hide_insert_form( entry ) {
    entry.style = 'display: none';
    const id = entry.id;
    let expandables =
        entry.parentNode.querySelectorAll( 'div[id=\'' + id + '\'], ' +
                                           'label[for=\'expandable:' + id + '\']');
    expandables.forEach( function( expandable ) {
        expandable.style = "display: none";
    });
}

function unhide_form_buttons() {
    const divs = document.getElementsByClassName( 'related_form' );
    for( let i = 0; i < divs.length; i++ ) {
        const forms = divs[i].getElementsByTagName( 'dbdata-input-form' );
        let hidden_buttons = forms[0].getElementsByClassName( 'hidden' );
        if( hidden_buttons.length == 0 ) {
            continue;
        }
        hidden_buttons[0].className = '';
    }
    let selector = document.getElementById( 'related_table_selector' );
    selector.className = '';
    toggle_related_div( 'related_table_selector' );
}

function toggle_related_div( toggle ) {
    const value = document.getElementById( toggle ).value;
    let divs  = document.getElementsByClassName( 'related_form' );
    for( let i = 0; i < divs.length; i++ ) {
        // More sophisticated HTML5 add() and remove() methods could
        // be used; for now using simple cross-browser solution:
        if( divs[i].id == value ) {
            divs[i].className = 'related_form';
        } else {
            divs[i].className = 'related_form hidden';
        }
    }
}

function follow_popup_link( popup_id ) {
    window.open( document.getElementById( popup_id ).value );
}

function hide_by_id( id ) {
    document.getElementById( id ).style.display='none';
}

function show_by_id( id ) {
    document.getElementById( id ).style.display='inline';
}

function toggle_search_value() {
    const operator = document.getElementsByName( 'select_operator' )[0].value;
    const search_value_field = document.getElementsByName( 'search_value' )[0];
    search_value_field.disabled =
        operator == 'known' || operator == 'unknown';
    
    $('#select_operator').disabled = operator == 'known' || operator == 'unkown';

}

// Quick-and-dirty way to generate UUIDs, as taken from
// https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript
function uuid() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });
}

function search_suggest( fk_list ){
    $('#search_text').val('');
    var select_column = $("[name='select_column']").val();
    $('#search_text').show();
    $('#search_text').attr('name','search_value');
    
    if( fk_list.includes(select_column) ){
        $("#select_operator option").each( function() {
            if( this.value !== "eq" && this.value !== "ne" && 
                this.value !== "known" && this.value !== "unknown") {
                $("#select_operator option[value="+this.value+"]").prop('disabled','disabled');
            }
        }  );       
        if( $('#select_operator').val() !== "eq" && $('#select_operator').val() !== "ne" && 
            $('#select_operator').val() !== "known" && $('#select_operator').val() !== "unkown" ){
            $("#select_operator").val("eq");
        }
    } else {
        $("#select_operator option").each( function() {
            $("#select_operator option[value="+this.value+"]").prop('disabled',false);
        }  ); 
    }

    fk_list.forEach(function(fk) {
        
        if( fk === select_column ){
            $('#search_text').hide();
            $('#search_text').attr('name','');
            $('#'+fk).attr('name','search_value');
            
            if( !$('#'+fk).hasClass("select2-hidden-accessible") ) {
                $('#'+fk).select2();
            }
        } else {
            $('#'+fk).attr('name','');
        
            if( $('#'+fk).hasClass("select2-hidden-accessible") ) {
                $('#'+fk).select2('destroy');
            }
        }
    });
    toggle_search_value();
}
