﻿// Copyright 2007-2010 Panopto, Inc.
// All rights reserved.  Reuse and redistribution strictly prohibited.

/// <reference path="~/Scripts/MicrosoftAjax/Start.js" />
/// <reference path="~/Scripts/jQuery/jquery-1.6.1.js" />

/// <reference path="~/Scripts/Panopto/GlobalResources.js"/>
/// <reference path="~/Scripts/Panopto/Data.js"/>
/// <reference path="~/Scripts/Panopto/Events.js"/>
/// <reference path="~/Scripts/Panopto/Util.js"/>

Type.registerNamespace("Panopto");

Panopto.Application = function ()
{
    // Initialize Sys.Component base class.
    Panopto.Application.initializeBase(this);

    // Cache static ref to default instance.
    Panopto.Application.defaultInstance = this;

    // Handle framework "navigate" event to dynamically update state.
    Sys.Application.add_navigate(Function.createDelegate(this, this._handleNavigate));
}

Panopto.Application.prototype =
{
    // Store current state
    _state: {},

    init: function ()
    {
        // Instantiate modal popup control.
        new Panopto.ModalPopup();

        // Wire up search controls if present.
        if ($get("searchQuery"))
        {
            $get("searchQuery").blur();

            // Set up default search watermark ("Search all sessions...").
            this._searchWatermark = Sys.create.watermark("#searchQuery", Panopto.GlobalResources.SearchWatermark, "ghosted");

            // Submit search on [Enter]
            $addHandler("#searchQuery", "keydown", Function.createDelegate(this, function (e)
            {
                if (e.keyCode == Sys.UI.Key.enter)
                {
                    this._handleSearchEntry(e);
                }
            }));

            // Submit search when search icon is clicked.
            $addHandler("#searchImage", "click", Function.createDelegate(this, this._handleSearchEntry));

            // Cancel search button
            $addHandler("#cancelSearch", "click", Function.createDelegate(this, this._handleSearchCancel));
        }

        // Wire up login link and body.
        $addHandler("#loginLink", "click", function (event)
        {
            if ((event.target == this) && !$("#loginDropdown").is(":visible"))
            {
                $('#loginDropdown').show();
                event.preventDefault();
                event.stopPropagation();
            }
        });

        // Wire up a handler to tell when the login box has focus
        // so that we don't accidentally close it.
        var loginBoxHasFocus = false;
        $addHandler("#loginDropdown", "click", function (event)
        {
            loginBoxHasFocus = true;
        });

        // Wire up support link.
        $addHandler("#supportLink", "click", function (event)
        {
            if ((event.target == this) && !$("#supportDropdown").is(":visible"))
            {
                $('#supportDropdown').show();
                event.preventDefault();
                event.stopPropagation();
            }
        });

        // hide dropdowns on blur
        $('body').click(function ()
        {
            if (loginBoxHasFocus)
            {
                loginBoxHasFocus = false;
            }
            else
            {
                $('#loginDropdown').hide();
            }

            $('#supportDropdown').hide();
        });

        // Wire up download recorder link.
        $addHandler("#downloadRecorder", "click", function (e)
        {
            Panopto.Application.defaultInstance.updateState({
                modalPage: "#recorderPopup",
                modalHeader: "Download Recorder",
                modalParams: null
            });

            e.preventDefault();
        });

        // Wire up feedback link.
        $addHandler("#feedback", "click", Function.createDelegate(this, function (e)
        {
            Panopto.Application.defaultInstance.updateState({
                modalPage: "#feedbackPopup",
                modalHeader: "Send Feedback to Panopto",
                modalParams: Panopto.Util.serializeObjectToQueryString({ url: window.location.href })
            });

            e.preventDefault();
        }));

        // Styling tweaks for Mobile Safari
        if (Panopto.browser.isMobileSafari)
        {
            $(".leftcolumn")
                .css("height", "auto")
                .css("background", "inherit");
            $("#content")
                .css("border-left", "1px solid #989898");
            $(".pagination")
                .css("bottom", "inherit")
                .css("border-left", "1px solid #989898")
                .css("margin-left", "-1px");
        }
    },

    // Update application state by merging in the passed values.
    updateState: function (newState)
    {
        // Merge new values into state.
        // Only overwrites properties that are specified in newState.
        $.extend(this._state, newState);

        // History can't safely store objects in the state object
        // Serialize state values into strings
        for (prop in this._state)
        {
            if (this._state[prop] != null)
            {
                this._state[prop] =
                    Sys.Serialization.JavaScriptSerializer.serialize(this._state[prop]);
            }
        }

        // Create a history point for the current state.
        // Triggers updates via "navigate" event.
        Sys.Application.addHistoryPoint(this._state);
    },

    /* Handle Sys.Application.navigate event */
    _handleNavigate: function (sender, args)
    {
        // Store current state.
        this._state = args.get_state();

        // History can't safely store objects in the state object
        // Deserialize state values from strings
        for (prop in this._state)
        {
            if (this._state[prop] != null)
            {
                try
                {
                    this._state[prop] =
                        Sys.Serialization.JavaScriptSerializer.deserialize(this._state[prop]);
                }
                catch (e)
                {
                    // Handle "bare" state strings gracefully.
                    // This should not happen unless there are user-entered values.
                }
            }
        }

        // Fire off our own "navigate" event to listeners.
        this._navigate(sender, args);
    },

    /* Panopto.Application "navigate" event */

    // Custom event handlers.
    add_navigate: function (handler)
    {
        this.get_events().addHandler("navigate", handler);

        // Fire the handler with current state on add.
        // This allows listeners to catch up to state loaded from bookmarks, e.g.
        handler(this, new Sys.HistoryEventArgs(this._state));
    },
    remove_navigate: function (handler)
    {
        this.get_events().removeHandler("navigate", handler);
    },

    // Raise "navigate" event.
    _navigate: function (sender, args)
    {
        var handler = this.get_events().getHandler("navigate");

        // Delegate to listener(s) if present.
        if (handler)
        {
            handler(this, args);
        }
    },

    /* searchSubmit event */

    // Framework boilerplate to add/remove custom event handlers.
    add_searchSubmit: function (handler)
    {
        this.get_events().addHandler("searchSubmit", handler);
    },
    remove_searchSubmit: function (handler)
    {
        this.get_events().removeHandler("searchSubmit", handler);
    },

    // Raise "searchSubmit" event.
    _searchSubmit: function (query)
    {
        var handler = this.get_events().getHandler("searchSubmit");

        // Delegate to listener(s) if present.
        if (handler)
        {
            handler(this, new Panopto.Events.SubmitSearchEventArgs(query));
        }
        // Use default behavior if no listeners.
        else
        {
            location.href = Panopto.Application.getBookmarkURL(Panopto.appRoot + "/Pages/Sessions/List.aspx",
            {
                query: query
            });
        }
    },

    // Handle search submit from icon or [Enter] key.
    _handleSearchEntry: function (e)
    {
        var query = this._searchWatermark ? this._searchWatermark.get_Text() : $get("searchQuery").value;

        // Fire "searchSubmit" event (convert "" to null).
        this._searchSubmit(query || null);

        // Don't submit form.
        e.preventDefault();
    },

    _handleSearchCancel: function (e)
    {
        // Don't outline search cancel image.
        $get("cancelSearch").blur();

        // Clear search box.
        this.setSearchText("");

        // Handle empty search.
        this._handleSearchEntry(e);
    },

    /* Watermark extender for header search box */

    _searchWatermark: null,

    setSearchWatermarkText: function (searchWatermarkText)
    {
        this._searchWatermark.set_WatermarkText(searchWatermarkText);
    },
    setSearchText: function (searchText)
    {
        this._searchWatermark.set_Text(searchText);
    }
} // End Panopto.Application.prototype

// Create a bookmark URL for deep-linking into a page with predefined client-side state.
Panopto.Application.getBookmarkURL = function (url, state)
{
    var bookmarkURL = url;

    // Make sure we have a state object before attempting to serialize
    if (typeof (state) == "object")
    {
        bookmarkURL += "#";

        var stateStrings = [];

        // History can't safely store objects in the state object
        // Serialize state values into strings
        for (prop in state)
        {
            if (state[prop] != null)
            {
                var value = Sys.Serialization.JavaScriptSerializer.serialize(state[prop]);

                // URL-escape state string.
                var stateString = prop + "=" + encodeURIComponent(value);

                stateStrings.push(stateString);
            }
        }

        // Join state strings into URL with "&" separator.
        bookmarkURL += stateStrings.join("&");
    }

    return bookmarkURL;
};

Panopto.Application.registerClass("Panopto.Application", Sys.Component);

// Make sure the class hasn't already been instantiated, then instantiate our singleton class.
// We instantiate early to catch history navigation events from the framework at load time.
if (!Panopto.Application.defaultInstance)
{
    new Panopto.Application();
}
