{% load common_filters %}

{% comment %}
/**
  Copyright (C) 2012-2016 University of Dundee & Open Microscopy Environment.
  All rights reserved.

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as
  published by the Free Software Foundation, either version 3 of the
  License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Affero General Public License for more details.

  You should have received a copy of the GNU Affero General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
{% endcomment %}

<!-- Include script for filtering center panel -->
<script src="{% static 'webclient/javascript/ome.center_plugin_filter.js'|add:url_suffix %}" type="text/javascript"></script>

<script>
/**
 * This script is included in the main containers.html page as well as public.html,
 * adding itself as a selection listener to the jsTree in each case.
 * It loads appropriate data into the middle panel on selection changes in the jsTree.
 * For the main containers.html page, it also responds to switching between 'plugins'
**/

$(document).ready(function() {

    // Revamp of thumbnail update

    /*

    When should the panel update

    1) The image selection has changed (update)
    2) The container selection has changed (refresh)
    3) Something has been deleted or moved out (remove)
    4) Something has been added (refresh)

    Problems

    An image is moved to another dataset while selected.
    This causes the view to shift to the new view
    There will also be a remove attempt (this must do nothing)

    */

    var inst = $.jstree.reference('#dataTree');
    var parentNode;     // the currently selected node
    // We compile the underscore templates, ready for rendering
    var tmplText = $('#icon_thumbnails_template').html();
    var iconTmpl = _.template(tmplText);
    var headerText = $('#icon_header_template').html();
    var headerTmpl = _.template(headerText);
    // Variables for layout and thumbnail zooming
    var layout = "icon";
    var icon_styles = [];
    var li_styles = [];
    var aspect_ratios = [];
    var iconSize = 65;
    var parentId;       // E.g. dataset-1

    var dateFormatOptions = {
        weekday: "short", year: "numeric", month: "short",
        day: "numeric", hour: "2-digit", minute: "2-digit"
    };

    var setIconSize = function() {
        $("#dataIcons").get(0).style.setProperty("--iconSize", iconSize + "px");
    }

    // Start listening for Node Loading events on the tree...
    // If a node loads and it's selected, update_thumbs...
    $("#dataTree").on('load_node.jstree', function(event, data){
        if (data.node.state.selected) {
            update_thumbnails_panel(event, data);
        }
    });

    $("#content_details").on("click", "input.button_pagination", function(){
        var page = $(this).attr('data-page');
        page = parseInt(page, 10);
        inst.deselect_all(true);
        inst.change_page(parentNode, page);
        // and then reselect the same node again to trigger update
        inst.select_node(parentNode);
    });

    // double-click handler on image - launches image viewer
    $("#content_details").on("dblclick", "li.row", function(event) {
        var $this = $(this),
            iid = $this.attr('id').split("-")[1],
            url;
        // Image only has share ID if user doesn't own the share.
        if ($this.attr('data-share')) {
            url = "{% url 'web_image_viewer' 99 0 %}".replace('/99/', "/" + $this.attr('data-share') + "/" );
        } else {
            url = "{% url 'web_image_viewer' 0 %}";
        }
        url = url.replace('/0/', "/" + iid + "/" );
        // We try to traverse the jstree, to find parent of selected image
        var parent = OME.getTreeImageContainerBestGuess(iid);
        if (parent && parent.data) {
            if (parent.type === 'dataset') {
                url += '?' + parent.type + '=' + parent.data.id;
            }
        }
        window.open(url, '_blank');
    });

    // Set up the centre panel header.
    var setupDatasetHeader = function() {
        var html = headerTmpl({'layout': layout, 'staticUrl': '{% static "webclient/" %}'});
        $("#content_details").html(html);

        // single click handler on image (container). Selection then update toolbar & metadata pane
        $( "#icon_table" ).on( "click", "li.row", function(event) {
            event.preventDefault();
            handleClickSelection(event);
        });

        $("#filtersearch label").inFieldLabels();

        $("#thumb_size_slider").slider({
            max: 200,
            min: 30,
            value: iconSize,
            slide: function(event, ui) {
                iconSize = ui.value;
                setIconSize();
            }
        });
        // handle Radio buttons
        $("#layout_chooser button").on('click', function(event) {
            if ($(event.target).attr('id') == 'table_layout') {
                layout = 'table';
            } else {
                layout = 'icon';
            }
            setLayout();
            $("#layout_chooser button").removeClass("checked");
            $(event.target).addClass("checked");
        });
    }

    // This is called directly by various jstree plugins
    // E.g. omecut_plugin.js as well as the jstree in containers.html
    window.update_thumbnails_panel = function(event, data) {

        // Get the current selection
        var selected = inst.get_selected(true);

        if (!$("#content_details").is(":visible") || selected.length === 0) {
            $("#content_details").html("");
            parentId = undefined;
            clearThumbnailsPanel();
            return Promise.resolve();
        }
        var dtype = selected[0].type;
        if (selected.length > 1 && dtype !== "image") {
            $("#content_details").html("");
            parentId = undefined;
            clearThumbnailsPanel();
            return Promise.resolve();
        }

        // parent node could be dataset, orphaned, share or tag
        // see WEBCLIENT.UI.TREE.pagination_nodes and ome.tree.js
        var parentTypes = WEBCLIENT.UI.TREE.pagination_nodes,
            imgNodes = [];
        if (parentTypes.indexOf(dtype) < 0) {
            parentNode = selected[0];
        } else if (dtype === "image") {
            parentNode = inst.get_node(inst.get_parent(selected[0]));
        } else if (dtype === "plate" || dtype === "acquisition") {
            parentId = undefined;
            load_spw(event, data);
            return Promise.resolve();
        // All other types have blank centre panel
        } else {
            parentId = undefined;
            clearThumbnailsPanel();
            return Promise.resolve();
        }

        if (!parentNode) {
            // need this for pagination etc
            parentNode = inst.get_node(data.node);
        }

        var newParentId = parentNode.type + "-" + parentNode.data.obj.id;
        if (parentId === newParentId
                && event.type !== "copy_node"
                && event.type !== "create_node"
                && event.type !== "load_node"
                && event.type !== "delete_node"
                && event.type !== "refreshThumb"
                && event.type !== "refreshThumbnails") {

            highlightSelectedThumbs(selected);

            return Promise.resolve();
        }
        // update single thumbnail, see OME.refreshThumbnails
        if (event.type === "refreshThumb") {
            OME.load_thumbnail(
                data.imageId,
                "{% url 'webindex' %}get_thumbnail/"+data.imageId+"/",
                function(thumb) {
                    $("li#image_icon-"+data.imageId+ " img").attr("src", thumb);
                }
            );
            return Promise.resolve();
        }

        parentId = newParentId;

        // clear html and stored data before adding back html
        clearThumbnailsPanel();

        imgNodes = [];
        parentNode.children.forEach(function(ch){
            var childNode = inst.get_node(ch);
            // Ignore non-images under tags or 'deleted' under shares
            if (childNode.type == "image") {
                imgNodes.push(childNode);
            }
        });

        var imgJson = [],
            selFileSets = [],
            shareId = null;
        // Convert jsTree nodes into json for template
        imgNodes.forEach(function(node){
            var d = node.data.obj.date || node.data.obj.acqDate;
            var date = new Date(d);
            date = date.toLocaleTimeString(undefined, dateFormatOptions);
            var iData = {'id': node.data.obj.id,
                    'name': node.text,
                    'data': JSON.parse(JSON.stringify(node.data)),
                    'selected': node.state.selected,
                    'date': date,
                };
            // Note fileset IDs for selected images
            if (iData.selected) {
                var fsId = node.data.obj.filesetId;
                if (fsId) {
                    selFileSets.push(fsId);
                }
            }
            // If image is in share and share is not owned by user...
            if (node.data.obj.shareId && !parentNode.data.obj.isOwned) {
                // share ID will be needed to open image viewer
                iData.shareId = node.data.obj.shareId;
                shareId = node.data.obj.shareId;
            }
            imgJson.push(iData);
        });

        // Now we know which filesets are selected, we can
        // go through all images, adding fs-selection flag if in
        if (selFileSets.length > 0) {
            imgJson.forEach(function(img){
                if (selFileSets.indexOf(img.data.obj.filesetId) > -1) {
                    img.fsSelected = true;
                }
            });
        }

        if ($("#icon_table").length == 0) {
            setupDatasetHeader();
        }

        var json = {'images': imgJson,
                    'webindex': '{% url "webindex" %}',
                    'layout': layout,
                    'paging': false}
        // Add 'dataset':id if we have it
        json['dataset'] = parentNode.type == 'dataset' ? parentNode.data.obj.id : false;

        var childCount = parentNode.data.obj.childCount;
        if (PAGE_SIZE < childCount) {
            json.pageCount = Math.ceil(childCount / PAGE_SIZE);
            json.paging = true;
            json.page = inst.get_page(parentNode);
        }

        var html = iconTmpl(json);
        $("#icon_table").html(html);
        // intial size
        setIconSize();

        // load thumbnails in a batches
        thumbnailsBatch = {{ thumbnails_batch|default:50|json_dumps|safe }};
        iids = $.map(imgJson, function(img){
            return img.id;
        });
        thumbUrl = "{% url 'get_thumbnails_json' %}";
        if (shareId !== null) {
          thumbUrl = "{% url 'get_thumbnails_json' %}" + shareId + "/"
        }

        // getThumbnailSet() doesn't work with share permissions, so we get
        // single thumbnails at a time
        if (parentNode.type === "share") {
            thumbnailsBatch = 1;
        }
        var promise = OME.load_thumbnails(
            thumbUrl, iids, thumbnailsBatch,
            "{% static 'webgateway/img/image128.png' %}"
        );

        // setup quicksearch filtering of images
        setupFiltering();

        // init the elementsorter plugin
        setupSorting();

        // plugin to handle drag-select of images (share is single-select only)
        if (parentNode.type !== "share") {
            setupSelectable();
        }

        // scroll to selected thumbnail (if any)
        focusThumbnail();

        return promise;
    }

    // Update thumbnails when we switch between plugins
    $('#center_panel_chooser').on('center_plugin_changed.ome', update_thumbnails_panel);

    // Use selected nodes from tree to indicate thumbnails
    var highlightSelectedThumbs = function(selected) {
        $("#dataIcons li.row").removeClass("ui-selected").removeClass("fs-selected");
        var selFileSets = [];
        selected.forEach(function(node){
            if (node.type == "image") {
                $("#image_icon-" + node.data.obj.id).addClass("ui-selected");
            }
            var fsId = node.data.obj.filesetId;
            if (fsId) {
                selFileSets.push(fsId);
            }
        });
        selFileSets.forEach(function(fsId){
            $("#dataIcons li[data-fileset='" + fsId + "']").addClass("fs-selected");
        });
        focusThumbnail();
    }

    var focusThumbnail = function() {
        // We focus the thumbnail to make sure it's scrolled into view
        var $focused = $(':focus');
        $("#dataIcons li.ui-selected").first().trigger('focus');
        // Then re-focus the jstree node, so that hot-keys work etc
        $focused.trigger('focus');
    }

    var getRandom = function() {
        return (Math.random() + "").slice(2);
    }

    var setupSelectable = function() {
        $("#dataIcons").selectable({
            filter: 'li.row',
            distance: 2,
            stop: function() {
                // Make the same selection in the jstree etc
                syncTreeSelection();
            },
            start: function() {
                // Remove any fileset selection markings
                $("#dataIcons li.row:visible")
                    .removeClass("fs-selected")
                    .removeClass("lastSelected");
            }
        });
    }

    var setupSorting = function() {
        // simple emulation of table-sorter for other elements...
        // performs sort when intialised on 'sort-init' column
        $(".element_sorter").elementsorter({
            head: '.thead div',             // Selector for the equivalent of 'table head'
            body: 'li.row',                 // Selector for the equivalent of 'table rows'
            sort_key: '.hidden_sort_text'   // optional - how to find the text within each child of a 'row'.
        });
    }

    var setupFiltering = function() {
        // All the image filtering functionality setup here...
        // {'id': {'text': 'name', 'images': [1,2,3]} } for all tags used for filtering
        var usedTags = {};
        // {key: {'values':{'imageId': 'val1, val2'}, 'type': 'number'}
        var usedKeyValues = {};
        var currentFilterKey;
        var filter_tag_ids = [];

        var filterObjects = [];

        function doFiltering() {
            // get image IDs, find which are filtered and update images
            $("#dataIcons li.row").each(function(){
                var $this = $(this);
                var iid = $this.attr("data-id");
                // check if visible in all filters
                var visible = true;
                filterObjects.forEach(function(f){
                    if (!f.isImageVisible(iid)) {
                        visible = false;
                    }
                });
                if (visible) {
                    $this.removeClass('mapFilter_hidden');
                } else {
                    $this.addClass('mapFilter_hidden');
                }
            });
            // finally, we de-select hidden
            deselectFiltered();
        }

        // Chooser for revealing various filter components
        $("#choosefilter").on('change', function() {
            var $this = $(this),
                filterby = $this.val();
            // reset chooser
            $this.val("addfilter");

            // if we're already showing this filter, ignore
            if ($("#filter" + filterby).is( ":visible" )) {
                return;
            }

            // Handle 'Remove all filters'
            if (filterby == "removeAll") {
                $(".imagefilter").hide();
                // clear text filter (will also undo fitering)
                $('#id_search').val('').trigger('keyup');
                // reset rating to 0
                $("#filterrating img").attr('src', "{% static 'webclient/image/rating' %}0.png");
                // clear any filtering by rating/unrated
                $("#dataIcons li.row").removeClass('ratingFilter_hidden');
                // reset Tag filtering
                filter_tag_ids = [];
                // clear filter objects if any exist
                if (filterObjects.length) {
                    filterObjects = [];
                    doFiltering();
                }
                renderFilterTags();
            }

            // Unrated and By rating are mutually exclusive
            if (filterby === "unrated") {
                // reset 'by rating' filter
                $("#filterrating").hide().find("img").attr('src', "{% static 'webclient/image/rating' %}0.png");
                // do filtering
                filterUnrated();
            } else if (filterby === "rating") {
                $("#filterunrated").hide();
                $("#dataIcons li.row").removeClass('ratingFilter_hidden');
            }

            if (filterby === "tag") {
                // Load tags for images
                var iids = [];
                $("#dataIcons li.row").each(function(){
                    iids.push($(this).attr("data-id"));
                });
                // Check to ensure images are available for filtering
                // if (iids.length === 0) {
                //     // No images to filter
                //     return;
                // }
                var query = "image=" + iids.join("&image=");
                $.getJSON("{% url 'api_annotations' %}?type=tag&" + query, function(data){
                    // map imageId to rating... rdata = {'iid': hide?}
                    usedTags = data.annotations.reduce(function(prev, t){
                        var imgId = t.link.parent.id;
                        if (!prev[t.id]) {
                            prev[t.id] = {'textValue': t.textValue, 'images': []};
                        }
                        prev[t.id].images.push(imgId);
                        return prev;
                    }, {});
                    renderFilterTags();
                });
            }

            if (filterby === "map") {
                // Load map annotations for images
                var iids = [];
                $("#dataIcons li.row").each(function(){
                    iids.push($(this).attr("data-id"));
                });

                var f = new MapAnnFilter(iids, $('#center_toolbar'), doFiltering, filterObjects);
                filterObjects.push(f);
                return;
            }

            // Show filter
            if (filterby != "addfilter") {
                $("#filter" + filterby).show();
            }
        });
        // Filters have a 'X' for clearing filter
        $(".filtersearch").on('click', '.removefilter', function(){
            var $fltr = $(this).parent();
            var fid = $fltr.attr('id');
            if (fid === 'filterrating') {
                $("#dataIcons li.row").removeClass('ratingFilter_hidden');
                $("#filterrating img").attr('src', "{% static 'webclient/image/rating' %}0.png");
            } else if (fid === 'filterunrated') {
                $("#dataIcons li.row").removeClass('ratingFilter_hidden');
                $fltr.hide();
            } else if ($fltr.attr('data-tagId')) {
                // Remove a single Tag
                var tagId = $fltr.attr('data-tagId');
                filter_tag_ids = filter_tag_ids.filter(function(i){return i !== tagId});
                renderFilterTags();
            } else if (fid == 'filtertag') {
                // Remove ALL tags and hide tag filter
                $fltr.hide();
                filter_tag_ids = [];
                renderFilterTags();
            }
        });

        // Handle filtering by text
        var $filter_input = $('#id_search');
        var filter_txt = $filter_input.val();
        $filter_input.quicksearch('#dataIcons li.row', {
            'delay': 300,
            'bind': 'keyup',
            'loader': 'span.loading',
            'selector': '.hidden_sort_text',
            // override to replace &amp; from item.innerHTML with '&'
            testQuery: function (query, txt, _row) {
                txt = txt.replace(/&amp;/g, '&')
                // query is a list of strings
                for (var i = 0; i < query.length; i += 1) {
                    if (txt.indexOf(query[i]) === -1) {
                        return false;
                    }
                }
                return true;
            },
            onAfter: function(){
                // onAfter can get triggered without text change, E.g. by tree selection!
                var new_txt = $filter_input.val();
                if (filter_txt != new_txt){     // test text has changed
                    filter_txt = new_txt;
                    deselectFiltered();
                }
            }
        });

        // filter by unrated
        var filterUnrated = function(){
            var iids = [];
            $("#dataIcons li.row").each(function(){
                iids.push($(this).attr("data-id"));
            });
            // Check to ensure images are available for filtering
            if (iids.length === 0) {
                // No images to filter
                return;
            }
            var query = "image=" + iids.join("&image=");
            $.getJSON("{% url 'api_annotations' %}?type=rating&" + query, function(data){
                // map imageId to rating... rdata = {'iid': hide?}
                var rdata = data.annotations.reduce(function(prev, r){
                    var iid = "" + r.link.parent.id;
                    prev[iid] = true;
                    return prev;
                }, {});
                $("#dataIcons li.row").each(function(){
                    var $this = $(this),
                        iid = $this.attr("data-id");
                    if (rdata[iid]) {
                        // hide
                        $this.addClass('ratingFilter_hidden');
                    } else {
                        // show
                        $this.removeClass('ratingFilter_hidden');
                    }
                });
                // finally, we de-select hidden
                deselectFiltered();
            });
        };

        // filter by rating
        $("#filterrating img").on('click', function(event) {
            var iids = [],
                $rating = $(this),
                clickX = event.pageX - $rating.offset().left;
            var rating = (clickX/ $rating.width()) * 5;
            rating = parseInt(Math.ceil(rating), 10);
            var src="{% static 'webclient/image/rating' %}" + rating + ".png";
            $rating.attr('src', src);
            $("#dataIcons li.row").each(function(){
                iids.push($(this).attr("data-id"));
            });
            // Check to ensure images are available for filtering
            if (iids.length === 0) {
                // No images to filter
                return;
            }
            var query = "image=" + iids.join("&image=");
            // get ratings...
            $.getJSON("{% url 'api_annotations' %}?type=rating&" + query, function(data){
                // map imageId to rating... rdata = {'iid': show?}
                var rdata = data.annotations.reduce(function(prev, r){
                    // we don't care who owns the rating/link
                    var iid = "" + r.link.parent.id,
                        longValue = r.longValue;
                    if (r.longValue === rating) {
                        prev[iid] = true;
                    }
                    return prev;
                }, {});
                $("#dataIcons li.row").each(function() {
                    var $this = $(this),
                        iid = $this.attr("data-id");
                    if (rating === 0 || rdata[iid]) {
                        $this.removeClass('ratingFilter_hidden');
                    } else {
                        $this.addClass('ratingFilter_hidden');
                    }
                });
                // finally, we de-select hidden
                deselectFiltered();
            });
        });

        // Filtering by Tag
        function renderFilterTags() {
            // Render Tag filter chooser, without current filter tags
            var tagList = [];

            for (t in usedTags) {
                if (usedTags.hasOwnProperty(t)) {
                    tagList.push({id: t, text: usedTags[t].textValue});
                }
            }
            // sort list of tags
            tagList.sort(function(a, b){
                return a.text < b.text ? -1 : 1;
            });
            var html = tagList.map(function(t){
                // don't show tags we're filtering by
                if (filter_tag_ids.indexOf(t.id) > -1) return "";
                return "<option value='" + t.id + "'>" + t.text.escapeHTML() + "</option>";
            }).join("");
            html = "<option value='0'>Choose Tag</option>" + html;
            $("#filter_by_tag").html(html);

            // hide filtered images
            $("#dataIcons li.row").each(function() {
                var $this = $(this),
                    iid = parseInt($this.attr("data-id"), 10);
                // Visible if image has ALL filter tags
                var visible = filter_tag_ids.reduce(function(prev, tid){
                    return prev && (usedTags[tid].images.indexOf(iid) > -1);
                }, true);
                if (visible) {
                    $this.removeClass('tagFilter_hidden');
                } else {
                    $this.addClass('tagFilter_hidden');
                }
            });
            // show tags
            var html = filter_tag_ids.map(function(tagId){
                var tagText = usedTags[tagId].textValue.escapeHTML();
                return "<div class='tag' data-tagId='" + tagId + "'><a class='tag_inner' href='#'>" + tagText + "</a><span class='removeTag removefilter' title='Remove Tag'>-</span></div>";
            }).join("");
            $("#currentFilterTags").html(html);
        };

        $("#filter_by_tag").on('change', function(event){
            var $this = $(event.target);
            var tagId = $this.val();
            if (filter_tag_ids.indexOf(tagId) === -1) {
                filter_tag_ids.push(tagId);
            }

            renderFilterTags();

            // reset choose
            $this.val('0');

            // finally, we de-select hidden
            deselectFiltered();
        });
    }

    // When we filter, unselect the hidden icons and update
    // selections in the jstree
    var deselectFiltered = function(e, a){
        // check if any selection change is needed
        var $filtered = $("#dataIcons li.ui-selected:hidden");
        if ($filtered.length == 0) return;

        // If we've filtered any selected images, de-select icon
        $filtered.removeClass("ui-selected");

        var imageId = $filtered.first().data('id');
        syncTreeSelection(imageId);
    };

    // handles selection for 'clicks' (not drags)
    var handleClickSelection = function(event) {

        // It is possible to select the image itself or its individual container
        // Handle that here
        var $targetIcon = $(event.target).closest(".row");

        var imageId = $targetIcon.attr('data-id');

        // Add ui-selected class to range of icons etc
        highlightClickedIcons(event, $targetIcon);

        syncTreeSelection();

    }


    var highlightClickedIcons = function(event, $targetIcon) {
        /***
         * Based on the icon that was selected and any modifier keys
         * update the thumbnail selections
        */

        // Get the visible icons that might need selecting
        var $visibleIcons = $("#dataIcons li.row:visible");

        // Get the start point for a range select if there is one
        // and it is visible
        var $lastSelected = $('#dataIcons .lastSelected:visible');
        if ($lastSelected.length === 0) {
            // possible after drag select - just pick selected
            $lastSelected = $('#dataIcons .ui-selected:visible');
        }

        // Calculate the index of the last selected item if there was one
        var lastSelectedIndex = -1;
        $lastSelected.each(function(index, el) {
            lastSelectedIndex = $visibleIcons.index(el);
        });

        // Get the index of the target item
        var targetIndex = $visibleIcons.index($targetIcon);

        // Remove the starting point as a new one is about to be applied
        $lastSelected.removeClass('lastSelected');

        // Get the platform specific multi-select key
        var multiSelectKey = OME.multi_key() + "Key";

        var selectedIcons = [];
        var unselectedIcons = [];

        // If this is a range select
        if (event.shiftKey && lastSelectedIndex != -1) {
            // Find the start and end of the range
            var start = Math.min(lastSelectedIndex, targetIndex);
            var end = Math.max(lastSelectedIndex, targetIndex);

            // Mark the icons for selection
            $visibleIcons.slice(start, end+1).each(function(index, el) {
                $(el).addClass('ui-selected');
            });


        // If this is a multi-select
        } else if (event[multiSelectKey] && lastSelectedIndex != -1) {
            if ($targetIcon.hasClass('ui-selected')) {
                $targetIcon.removeClass('ui-selected');
            } else {
                $targetIcon.addClass('ui-selected');
            }

        // This is a single selection or there was no other selection for the range/multi select
        } else {
            // Remove all selections
            $visibleIcons.removeClass("ui-selected fs-selected");
            // Add selection for this one item
            $targetIcon.addClass("ui-selected lastSelected");
        }

        // Mark the most recent selection
        $targetIcon.addClass('lastSelected');
    }


    // use IDs of the selected visible thumbnails to sync tree selection
    var syncTreeSelection = function() {

        var $selectedIcons = $('#dataIcons li.ui-selected');
        if (parentNode.type == 'share') {
            // We don't support multi-selection of images in share
            $selectedIcons.removeClass('ui-selected');
            $selectedIcons = $selectedIcons.first().addClass('ui-selected');
        }
        var imageId = $selectedIcons.first().data('id');

        // Get the node that seems to be the current container
        // Images only, all that is required for now as center panel only shows images
        var containerNode;
        if (imageId) {
            // don't lookup container if no images selected
            containerNode = OME.getTreeImageContainerBestGuess(imageId);
        }

        // Deselect all to begin (supress jstree event)
        inst.deselect_all(true);

        var fsIds = {};
        if (containerNode) {

            // Select the selected icons in the tree (supress jstree event)
            $selectedIcons.each(function(index, el) {
                var $el = $(el),
                    fsId = $el.data('fileset');
                if (fsId != undefined && fsId != '') {
                    fsIds[fsId] = true;
                }
                var selectedNode = inst.locate_node($el.data('type') + '-' + $el.data('id'), containerNode)[0];
                inst.select_node(selectedNode, true);
                // we also focus the node, so that hotkey events come from the node
                if (selectedNode) {
                    $("#" + selectedNode.id).children('.jstree-anchor').trigger('focus');
                }
            });
        } else {
            console.log('jstree may need to be refreshed');
        }
        // Update thumbnail highlighting of filesets
        highlightFilesets(fsIds);

        // Since we've suppressed jstree events, we need to manually handle selection change...
        OME.writeSelectedObjs(undefined, $selectedIcons);
        // Update the buttons in the jstree
        if (buttonsShowHide) {
            buttonsShowHide(inst.get_selected(true), inst);
        }

        // Tell jsTree how many elements are selected
        // This event also bubbles up to $("body")
        $("#dataTree").trigger('selection_change.ome', inst.get_selected(true).length);

        return false;
    }

    // When an image(s) are selected, also indicate others with the same fileset(s).
    var highlightFilesets = function(fsIds) {
        var $selectee = $("#dataIcons").find("li.row");
        $selectee.removeClass('fs-selected');
        for (var fsid in fsIds) {
            $selectee.filter("[data-fileset='"+ fsid + "']").addClass('fs-selected');
        }
    }

    // switch between 'icon' or 'table' layout by switching CSS
    var setLayout = function() {
        if (layout == "icon"){
            $("#dataIcons").removeClass("tableLayout");
            $("#dataIcons").addClass("iconLayout");
        }
        else {
            $("#dataIcons").removeClass("iconLayout");
            $("#dataIcons").addClass("tableLayout");
        }
        // on larger pages, may need to scroll to show selected thumbnail again
        focusThumbnail();
    }


    // This is called for plates or acquisitions (runs) only.
    // Was previously used for loading ALL data types but now
    // images are retrieved from jsTree directly so we only need to
    // load plates.
    // TODO: More cleanup needed to remove all non-SPW code
    var load_spw = function(event, data) {
        // Get the container that is currently rendered
        // If any of these are not defined then nothing was selected
        var $contentDetails = $("div#content_details");

        // Get details about the currently displayed container
        var currentType = $contentDetails.data('type');
        var currentId = $contentDetails.data('id');
        var currentPath = $contentDetails.data('path')
        var currentNode = false;
        var currentPage = $("div#page").data('page');
        var currentField = $contentDetails.data('field');

        if (currentPage === undefined) {
            currentPage = 1;
        }

        if (currentField === undefined) {
            currentField = 0;
        }

        // Retrieve current container node
        if (currentType != undefined &&
            currentId != undefined &&
            currentPath != undefined) {

            currentPath = JSON.parse(currentPath);
            currentNode = inst.find_omepath(currentPath);
        }

        // Get the current selection
        var selected = inst.get_selected(true);

        // If there are selections then determine if the currently
        // rendered container is one of them.
        var containerNode = false;
        if (currentNode) {
            $.each(selected, function(index, node) {
                if (node === currentNode) {
                    containerNode = node;
                    // Break out of each
                    return false;
                }

            });
        }

        // If the containerNode is the current container then this is
        // a selection change within the container or a pagination/field
        // change
        if (containerNode) {
            // This is a page change
            if (getPageOr1(inst, containerNode) !== currentPage) {
                loadThumbnailsPanel(containerNode, getPageOr1(inst, containerNode), undefined);

            // Fields are only applicable for acquisitions
            } else if ((containerNode.type === 'acquisition' || containerNode.type === 'plate') &&
                       getfieldOr0(inst, containerNode) !== currentField) {
                loadThumbnailsPanel(containerNode, undefined, getfieldOr0(inst, containerNode));
            }

            // Return as this was either a page/field change or image
            // selection only
            return;
        }

        // There was no current node or it was not selected
        // Load the first of the selected nodes
        containerNode = selected[0];

        // While the new selection may not be the same path as the old one
        // if it is an equivalent node, we can save a reload and simply update
        // the recorded path, but only if it is the same page/field
        if (currentNode &&
            inst.omecompare(containerNode, currentNode) &&
            (currentPage === inst.get_page(containerNode || (containerNode.type === 'acquisition' && currentField === inst.get_field(containerNode))))) {
            $contentDetails.data('path', JSON.stringify(inst.get_omepath(containerNode)));
            return;
        }

        // Load the thumbnails for this container with the appropriate page/field
        // E.g. public.html tree doesn't support pages/fields
        var nodePage = inst.get_page ? inst.get_page(containerNode) : 1;
        var nodeField = inst.get_field ? inst.get_field(containerNode) : 0;
        loadThumbnailsPanel(containerNode, nodePage, nodeField);
        return;
    };

        // Load the thumbnails (Will wait until there are no new requests
    // for 200ms)
    var loadThumbnailsPanelTimeout = false;
    var loadThumbnailsPanel = function(node, newPage, newField) {
        // Reset timeout if within 200ms of the last request
        if (loadThumbnailsPanelTimeout) {
            window.clearTimeout(loadThumbnailsPanelTimeout);
        }

        loadThumbnailsPanelTimeout = window.setTimeout(function() {
            // Clear the timeout
            loadThumbnailsPanelTimeout = false;

            // Update the central panel
            var inst = $.jstree.reference('#dataTree');
            var url = "{% url 'webindex' %}";
            node = inst.get_node(node);
            var nodeType = node.type;
            var nodeId = node.data.obj.id;
            var show = WEBCLIENT.initially_select.join("|");
            // clear WEBCLIENT.initially_select so we don't select well next time user loads plate
            WEBCLIENT.initially_select = [];

            switch(nodeType) {
                case 'plate':
                    url += 'load_plate/' + nodeType + '/' + nodeId + '/?index=' + newField;
                    if (show) {
                        url += "&show=" + show;
                    }
                    break;
                case 'acquisition':
                    url += 'load_plate/' + nodeType + '/' + nodeId + '/?index=' + newField;
                    if (show) {
                        url += "&show=" + show;
                    }
                    break;
                default:
                    url = undefined;
            }

            if (url != undefined) {
                // Loading screen
                $("div#content_details").html('<p class="loading_center">Loading... please wait. <img src ="{% static "webgateway/img/spinner_big.gif" %}"/></p>');

                // Load html from url
                $("div#content_details").load(url);
                setThumbnailsPanel(nodeType, nodeId, inst.get_omepath(node), newPage, newField);

            // Or if it's not a container that can be loaded, sometimes display a message
            } else {
                // If there are no children of a project node, display a message
                if (nodeType === 'project' && !inst.is_parent(node)) {
                    var msg = "<p class='center_message' title='Create Datasets using toolbar or right-click menu'>No Datasets in Project</a>";
                    $("div#content_details").html(msg);

                // If there are no children of a screen node, display a message
                } else if (nodeType === 'screen' && !inst.is_parent(node)) {
                    msg = "<p class='center_message' title='Import Plates using OMERO.insight'>No Plates in Screen</a>";
                    $("div#content_details").html(msg);
                }

                // And ensure the content is empty
                clearThumbnailsPanel();
            }
        }, 200);

    };

    var clearThumbnailsPanel = function() {
        var $contentDetails = $("div#content_details");
        $contentDetails.empty();
        $contentDetails.removeData('type');
        $contentDetails.removeData('id');
        $contentDetails.removeData('path');
        $("div#page").removeData('page');
        $contentDetails.removeData('field');
        // empty SPW 'spatial' birds eye view below tree
        if (OME.emptyWellBirdsEye) {
            OME.emptyWellBirdsEye();
        }
    };
    // Allows other web apps to access this method
    OME.clearThumbnailsPanel = clearThumbnailsPanel;

    var setThumbnailsPanel = function(type, id, path, page, field) {
        var $contentDetails = $("div#content_details");
        $contentDetails.data('type', type);
        $contentDetails.data('id', id);
        $contentDetails.data('path', JSON.stringify(path));
        $("div#page").data('page', page);
        $contentDetails.data('field', field);
    };

    var getPageOr1 = function(inst, node) {
        if ('get_page' in inst) {
            return inst.get_page(node);
        }
        return 1;
    };

    var getfieldOr0 = function(inst, node) {
        if ('get_field' in inst) {
            return inst.get_field(node);
        }
        return 0;
    };

});

</script>
