/**
 * Updates the Hanging Protocol Select2 Input
 */
function updateProtocolSelect() {
    // Loop through the available HangingProtocols
    // to create an array with the protocols that includes
    // a property labelled 'text', so that Select2 has something
    // to display
    var protocols = HangingProtocols.find().map(function(protocol) {
        protocol.text = protocol.name;
        return protocol;
    });

    // Select the Protocol select DOM element
    var protocolSelect = $('#protocolSelect');

    // Empty the element using Select2 for rerendering
    protocolSelect.select2().empty();

    // Initialize the select element with Select2 using the
    // array of protocols
    protocolSelect.select2({
        data: protocols
    });

    // Update the ProtocolSelector to display the current active Protocol
    protocolSelect.select2().val(ProtocolEngine.protocol.id).trigger('change');
}

Template.protocolEditor.onRendered(function() {
    this.timeAgoInterval = Meteor.setInterval(function() {
        // Run this every minute
        Session.set('timeAgoVariable', new Date());
    }, 60000);

    // Subscribe to the Hanging Protocols Collection
    this.subscribe('hangingprotocols', function() {
        // Update the Protocol select box when the Collection is ready
        updateProtocolSelect();
    });
});

Template.protocolEditor.onDestroyed(function() {
    Meteor.clearInterval(this.timeAgoInterval);
});

Template.protocolEditor.helpers({
    /**
     * Reactively updates the active Protocol
     *
     * @returns {*} The currently active Protocol Model
     */
    activeProtocol: function() {
        // Whenever the Layout Manager is updated, trigger this helper
        Session.get('LayoutManagerUpdated');

        // If no ProtocolEngine, protocol, or stage is defined, stop here
        if (!ProtocolEngine ||
            !ProtocolEngine.protocol ||
            ProtocolEngine.stage === undefined) {
            return;
        }

        // Update the Protocol Select box
        updateProtocolSelect();

        // Find the protocol in the database
        var protocolInDatabase = HangingProtocols.findOne({
            id: ProtocolEngine.protocol.id
        });

        // Give the current Protocol an _id property from the Database
        if (protocolInDatabase) {
            ProtocolEngine.protocol._id = protocolInDatabase._id;
        }

        // Make sure that the number of referenced priors is correct
        ProtocolEngine.protocol.updateNumberOfPriorsReferenced();
        
        // Otherwise, return the active Hanging Protocol
        return ProtocolEngine.protocol;
    },
    /**
     * Reactively updates the active Protocol Stage
     *
     * @returns {*} The current Protocol's active Stage model
     */
    activeStage: function() {
        // Whenever the Layout Manager is updated, trigger this helper
        Session.get('LayoutManagerUpdated');

        // If no ProtocolEngine, protocol, or stage is defined, stop here
        if (!ProtocolEngine ||
            !ProtocolEngine.protocol ||
            ProtocolEngine.stage === undefined) {
            return;
        }

        // Retrieve the Stage Model for the current Protocol's active Stage
        var stage = ProtocolEngine.getCurrentStageModel();
        if (!stage) {
            return;
        }

        // Update active Stage's layout template and properties based on the displayed
        // layout properties. This is used to update the Stage Model when the user modifies
        // the layout in the viewer
        stage.viewportStructure.layoutTemplateName = layoutManager.layoutTemplateName;
        stage.viewportStructure.properties = layoutManager.layoutProps;

        // If there is a discrepancy between the Stage's number of viewports and the
        // the number of required viewports given the properties above, rectify it
        // by removing or adding Viewports to the stage
        //
        // First, calculate the difference, if any exists
        var difference = stage.viewportStructure.getNumViewports() - stage.viewports.length;

        if (difference < 0) {
            // Make the viewport difference into a positive value
            var absDifference = Math.abs(difference);

            // If there are more Viewports defined than necessary, remove the extraneous Viewports
            var position = stage.viewports.length - absDifference;

            // Splice extra viewports from the Stage's viewports array
            stage.viewports.splice(position, absDifference);
        } else if (difference > 0) {
            // If there are less Viewports defined than necessary, add viewports until we reach the
            // required amount

            // Count up until the difference in number of Viewports
            for (var i = 0; i < difference; i++) {
                // Instantiate a new Viewport Model
                var viewport = new HP.Viewport();

                // Add new Viewports to the Stage's viewports array
                stage.viewports.push(viewport);
            }
        }
        
        // Return the current Stage model for the active Protocol
        return ProtocolEngine.getCurrentStageModel();
    },
    activeViewportUndefined: function() {
        return (Session.get('activeViewport') === undefined);
    }
});

Template.protocolEditor.events({
    /**
     * Creates a new Hanging Protocol and displays it in the Viewer
     */
    'click #newProtocol': function() {
        // Clone the default Protocol
        var protocol = HP.defaultProtocol.createClone();

        // Change the Protocol name to state that it is New, and give it a timestamp
        protocol.name = 'New (created ' + moment().format('h:mm:ss a') + ')';

        // Change the Protocol ID from the default value
        protocol.id = uuid.new();

        // Insert the Protocol into the HangingProtocols Collection
        HangingProtocols.insert(protocol);

        // Activate the new Protocol using the ProtocolEngine
        ProtocolEngine.setHangingProtocol(protocol);

        // Update the protocol selector to display the new Protocols
        updateProtocolSelect();
    },
    /**
     * Rename the current Protocol
     */
    'click #renameProtocol': function() {
        var selectedProtocol = this;
        if (selectedProtocol.locked) {
            return;
        }

        // Define some details for the text entry dialog
        var title = 'Rename Protocol';
        var instructions = 'Enter a new name';
        var currentValue = selectedProtocol.name;

        // Open the text entry dialog with the details above
        // and fire the callback function when finished.
        openTextEntryDialog(title, instructions, currentValue, function(value) {
            // Update the name with the entered text
            HangingProtocols.update(selectedProtocol._id, {
                $set: {
                    name: value
                }
            });

            selectedProtocol.name = value;
        });
    },
    /**
     * Triggers a custom event when for the HTML5 File input when files are selected
     *
     * @param event The Change event for the input
     */
    'change .btn-file :file': function(event) {
        // http://www.abeautifulsite.net/whipping-file-inputs-into-shape-with-bootstrap-3/

        // Find the Input in the DOM
        var input = $(event.currentTarget);

        // Get the number of selected files
        var numFiles = input.get(0).files ? input.get(0).files.length : 1;

        // Get the label of the file
        var label = input.val().replace(/\\/g, '/').replace(/.*\//, '');

        // Trigger our custom event with the number of files and label
        input.trigger('fileselect', [numFiles, label]);
    },
    /**
     * Imports files selected by the user into the Hanging Protocols Collection
     *
     * @param event The custom fileselect event
     */
    'fileselect .btn-file :file': function(event) {
        // Retreieve the FileList
        var files = event.target.files;

        // Create an HTML5 File Reader
        var reader = new FileReader();

        reader.onload = function() {
            var text = reader.result;

            // POST the file to our protocol-import Route
            // for it to be parsed and included in the
            // HangingProtocols Collection
            $.post('/protocol-import', {
                protocol: text
            }, function(resp, text, xhr) {
                if (xhr.status !== 200) {
                    // If the server returns an error during importing, alert the user

                    // TODO: Use a custom dialog box, rather than "alert"
                    alert('Protocol import failed.');
                }
            });
        };

        // Instruct the FileReader to read the (first) selected file
        // TODO: Update to allow batch uploads?
        reader.readAsText(files[0], 'utf-8');
    },
    /**
     * Set the Hanging Protocol when the select box is changed
     *
     * @param event The select2:select event
     */
    'select2:select #protocolSelect': function(event) {
        // Retrieve the protocolId
        var protocolId = event.params.data.id;

        // Retrieve the Protocol from the HangingProtocols Collection
        var selectedProtocol = HangingProtocols.findOne({
            id: protocolId
        });

        // If it doesn't exist, stop here
        if (!selectedProtocol) {
            return;
        }

        // Set the current Hanging Protocol to the user-specified Protocol
        ProtocolEngine.setHangingProtocol(selectedProtocol);
    },
    /**
     * Allow the Protocols / Stage navigation tabs to toggle the
     * 'active' class when clicked
     */
    'click .navigationButtons a': function() {
        $(this).addClass('active').siblings().removeClass('active');
    },
    /**
     * Update the HangingProtocols Collection with the latest changes to the current Protocol
     */
    'click #saveProtocol': function() {
        var selectedProtocol = this;
        if (selectedProtocol.locked) {
            return;
        }

        // Store the ID for the update call
        var id = selectedProtocol._id;

        // Remove the MongoDB _id property so that we can
        // simplify the $set value
        delete selectedProtocol._id;

        // Update the Protocol's modifiedDate and modifiedBy User details
        selectedProtocol.protocolWasModified();

        // Update the current Protocol in the database with the latest changes
        HangingProtocols.update(id, {
            $set: selectedProtocol
        });
    },
    /**
     * Save the current Protocol as a new document in the HangingProtocols Collection
     */
    'click #saveAsProtocol': function() {
        var selectedProtocol = this;

        // Define some details for the text entry dialog
        var title = 'Save Protocol As';
        var instructions = 'Enter a new name';
        var currentValue = selectedProtocol.name;

        // Open the text entry dialog with the details above
        // and fire the callback function when finished.
        openTextEntryDialog(title, instructions, currentValue, function(value) {
            // Erase the MongoDB _id
            delete selectedProtocol._id;

            // Create a new ID for the protocol
            selectedProtocol.id = uuid.new();

            // Update the name with the entered text
            selectedProtocol.name = value;

            // Update the Protocol's modifiedDate and modifiedBy User details
            selectedProtocol.protocolWasModified();

            // Insert the new Protocol
            HangingProtocols.insert(selectedProtocol);
        });
    },
    /**
     * Export the currently selected Protocol as a JSON file
     */
    'click #exportJSON': function() {
        // Tell the User's Browser to download the JSON file by routing a hidden iframe to our
        // protocol-export Route. This prevents the tab from changing its current content.
        var selectedProtocol = this;
        document.getElementById('download_iframe').src = '/protocol-export/' + selectedProtocol.id;
    },
    /**
     * Delete the currently selected Protocol
     */
    'click #deleteProtocol': function() {
        var selectedProtocol = this;
        if (selectedProtocol.locked) {
            return;
        }

        var options = {
            title: 'Delete Protocol',
            text: 'Are you sure you would like to remove this Protocol? This cannot be reversed.'
        };

        showConfirmDialog(function() {
            // Send a call to remove the Protocol from the HangingProtocols Collection on the server
            Meteor.call('removeHangingProtocol', selectedProtocol._id);

            // Reset the ProtocolEngine to the next best match
            ProtocolEngine.reset();

            // Update the protocol selector
            updateProtocolSelect();
        }, options);
    }
});
