function AddAttachedModules() {

    var $this = this;

    $this.wrapper = null;

    $this.alias = null;

    $this.options = {
        alias: null,
        son_module: null,
        father_fk: null,
        fields: null,
        conditions: null,
        strict_conditions: null
    };

    $this.init = function(options) {
        $this.options = $.extend($this.options, options);
        $this.alias = $this.options.son_module;
        $this.wrapper = $('.' + $this.alias + 'Connections');

        if($this.options.father_fk == null) {
            $this.generateFatherFk();
        }

        $this.getAllItems();

        // On document ready, attach oninput listener to search bar.
        $(document).ready(function(){
            $('#searchInput' + $this.alias).on('input', function() {
                $this.triggerSearch();
            });
        });
    };

    $this.generateFatherFk = function() {
        // Generate random string
        $this.options.father_fk = Math.random().toString(36).slice(2);

        if($('#GeneratedFatherFk').length == 0) {
            $this.wrapper.append($('<input>').hide().attr('name', 'data[' + $this.options.father_module + '][moduleconnections_generated_id]').val($this.options.father_fk))
        }
    };

    // Get results based on search string.
    this.getResults = function(searchString, callbackFunction) {
        if(searchString.length == 0) {
            $this.wrapper.find('.no-results').hide();
            $this.wrapper.find('.results-found').hide();
            $this.showResults([]);
            return;
        }


        var dataToSend = {
            'father_module': $this.options.father_module,
            'son_module': $this.options.son_module,
            'term': searchString,
            'father_fk': $this.options.father_fk,
            'fields': $this.options.fields,
            'conditions': $this.options.conditions,
            'strict_conditions': $this.options.strict_conditions
        };

        var url = "/" + $this.options.locale + "/_moduleconnections/search/";
        $.post(url, dataToSend, function(data, textStatus) {
            callbackFunction(data);
        }, "json");

    };

    // Show results.
    this.showResults = function(data) {
        // Hide all earlier results.
        $this.wrapper.find('.items .result').remove();

        // Holder is hidden element which serves as template for item display.
        var holder = $this.wrapper.find('.results .holder');
        // For each found item, copy template, fill it with data and append it to result area.
        $(data).each(function(index, value) {

            var item = $(holder).clone();
            $(item).addClass('result');
            $(item).find('div.name').append($("<a href='" + value[$this.alias].path + "' target='_blank'>" + value[$this.alias].name + "</a>"));
            if(typeof value.Image !== 'undefined') {
                $(item).find('div.image').append($("<img src='/" + value.Image.path + value.Image.filename + "' />"));
            }
            $(item).find('div.action a').attr('data-son_fk', value[$this.alias].id);

            // Add onclick listener to add button.
            $(item).find('div.action a').on('click',function() {
                var father_fk = $this.options.father_fk;
                var son_fk = $(this).data('son_fk');
                var name = $(this).closest('div.item').find('div.name a').text();
                var path = $(this).closest('div.item').find('div.name a').attr('href');
                var filename = '';
                if($(this).closest('div.item').find('div.image img').attr('src') != 'undefined') {
                    filename = $(this).closest('div.item').find('div.image img').attr('src');
                }
                var data = {'father_module' : $this.alias, 'son_module' : $this.options.son_module, 'father_fk' : father_fk, 'son_fk' : son_fk, 'name' : name, 'path' : path, 'file' : filename};
                $this.addItem(data, this);

            });
            $(holder).parent().append(item);
            $(item).fadeIn();
        });

        $this.updatePlaceholders();

    };

    // Add item from search results
    this.addItem = function(dataToSend, form) {
        var url = '/' + $this.options.locale + '/_moduleconnections/additem/';
        $.post(url, dataToSend, function(data, textStatus) {
            $(form).closest('div.item').fadeOut('500', $(form).closest('div.item').remove());
            $this.getAllItems(data);
            $this.triggerSearch();
        }, "json");
    };

    // Remove item from attached
    this.removeItem = function(dataToSend, form) {
        var url = '/' + $this.options.locale + '/_moduleconnections/removeItem/';
        $.post(url, dataToSend, function(data, textStatus) {
            $(form).closest('div.item').fadeOut('500', $(form).closest('div.item').remove());
            $this.getAllItems(data);
            $this.triggerSearch();
        }, "json");
    };

    // Get all attached items
    this.getAllItems = function() {
        $this.showLoader();
        var url = "/" + $this.options.locale + "/_moduleconnections/getAll/" + $this.options.father_module + "/" + $this.options.son_module  + "/" + $this.options.father_fk;
        $.getJSON(url, null, $this.showSelected);
    };

    // Show attached items in view. Works same as show results.
    this.showSelected = function(data) {
        $this.wrapper.find('.chosenones .selected').remove();
        var holder = $this.wrapper.find('.chosenones .holder');
        $(data).each(function(index, value) {
            var item = $(holder).clone();

            $(item).addClass('selected');
            $(item).attr('data-relationship-id', value.ModuleConnection.id);
            $(item).find('div.name').append($("<a href='" + value.ModuleConnection.path + "' target='_blank'>" + value.ModuleConnection.name + "</a>"));
            $(item).find('div.image').append($("<img src='" + value.ModuleConnection.file + "' />"));
            $(item).find('div.action a').attr('data-son_fk', value.ModuleConnection.son_fk);

            $(item).find('div.action a').on('click',function() {
                var father_fk = $this.options.father_fk;
                var son_fk = $(this).data('son_fk');
                var data = {'father_module' : $this.options.father_module, 'son_module' : $this.options.son_module, 'father_fk' : father_fk, 'son_fk' : son_fk};
                $this.removeItem(data);

            });

            $(holder).parent().append(item);
            $(item).fadeIn();
        });

        $this.wrapper.find('.chosenones').sortable({
            axis: 'y',
            containment: 'parent',
            stop: function(event, ui) {
                $this.refreshOrdering();
            }
        });

        $this.updatePlaceholders();
        $this.hideLoader();
    };

    this.refreshOrdering = function() {
        var allItems = {};
        var ordering = 1;
        $this.wrapper.find('.chosenones .selected').each(function() {
            var id = $(this).attr('data-relationship-id');
            allItems[id] = ordering;
            ordering++;
        });

        var url = "/" + $this.options.locale + "/_moduleconnections/refreshOrdering/" + $this.options.father_module + "/" + $this.options.son_module;
        $.post(
            url,
            allItems,
            function(data, textStatus) {},
            "json"
        );
    };

    $this.updatePlaceholders = function() {
        if($('#searchInput' + $this.alias).val().trim().length == 0) {
            $this.wrapper.find('.results-found').hide();
            $this.wrapper.find('.no-results').hide();
        } else {
            var resultsCount = $this.wrapper.find('.results .item.result').length;
            if(resultsCount == 0) {
                $this.wrapper.find('.results-found').hide();
                $this.wrapper.find('.no-results').show();
            } else {
                $this.wrapper.find('.no-results').hide();
                $this.wrapper.find('.results-found').show();
            }
        }
    };

    $this.triggerSearch = function() {
        var searchTerm = $('#searchInput' + $this.alias).val();
        var results = $this.getResults(searchTerm, $this.showResults);
    };

    $this.showLoader = function() {
        if(!$this.wrapper.is(':visible')) {
            return;
        }
        $('#PageLoader').show();
    };

    $this.hideLoader = function() {
        $('#PageLoader').fadeOut();
    };

}
