﻿/// <reference name="MicrosoftAjax.js"/>
/// <reference path="~/svc/ObjectModelService.svc"/>
/// <reference path="~/js/jquery-1.2.6-vsdoc.js" />
/// <reference path="~/js/Event.js" />
/// <reference path="~/js/AdCouncilJQueryPlugins.js" />

Type.registerNamespace("AdCouncil");

/* 
* Utilities ("static class")
*/
AdCouncil.Utilities = {

    findValueInDeserializedDict: function(deserializedDict, key) {
        for (var i = 0; i < deserializedDict.length; i++) {
            if (deserializedDict[i].Key == key) return deserializedDict[i].Value;
        }
    },
    addDict: function(dictToChange, dictToAppend) {
        for (var key in dictToAppend) {
            dictToChange[key] = dictToAppend[key];
        }
    },
    htmlEncode: function(str) {
        return $('<div/>').text(str).html();
    },

    getQueryVal: function(key, defaultVal) {
        var qs = window.location.search;
        if (qs.length < 3) return defaultVal; // '?a=' is the smallest parseable querystring.
        qs = qs.slice(1);
        var pairs = qs.split('&');
        var values = [];
        for (var i = 0; i < pairs.length; i++) {
            var pair = pairs[i].split('=');
            var pairKey = unescape(pair[0]);
            if (pairKey == key) {
                values.push(unescape(pair[1]));
            }
        }
        if (values.length > 1) return values;
        else if (values.length == 1) return values[0];
        else return defaultVal;
    },

    safeEscape: function(str) {
        var output = encodeURIComponent(str);
        // encodeURIComponent doesn't handle these characters that escape will: ~!()'
        output = output.replace(/\~/g, escape('~'));
        output = output.replace(/\!/g, escape('!'));
        output = output.replace(/\(/g, escape('('));
        output = output.replace(/\)/g, escape(')'));
        output = output.replace(/\'/g, escape("'"));
        // Nothing handles the asterisk.
        output = output.replace(/\*/g, '%2A');
        return output;
    },

    getGuid: function() { return $.getGuid(); },

    postToMySpace: function(paramObj) {
        var targetUrl = 'http://www.myspace.com/index.cfm?fuseaction=postto'
            + '&t=' + this.safeEscape(paramObj.title)
            + '&c=' + this.safeEscape(paramObj.content)
            + '&u=' + this.safeEscape(paramObj.url)
            + '&l=' + this.safeEscape(paramObj.location || "");

        window.open(targetUrl);
    },

    postToFacebook: function(paramObj) {
        var targetUrl = 'http://www.facebook.com/sharer.php?u=' + this.safeEscape(paramObj.url) + '&t=' + this.safeEscape(paramObj.title);
        window.open(targetUrl);
    },

    formatQuantity: function(amount, nounSingular, nounPlural) {
        var noun = nounSingular;
        if (amount != 1) {
            noun = nounPlural || (nounSingular + "s");
        }
        return amount + " " + noun;
    },

    log: function(msg) {
        if (window.console && window.console.log) window.console.log(msg);
    }
};

/*
* Callout Cards controller
*/

AdCouncil.CalloutCardsController = function(options) {
    this._formatHandler = null;

    this.initialize(options);
}

AdCouncil.CalloutCardsController.prototype = {
    _options: null,

    _getDefaultOptions: function() {
        return ({ formatHandler: null });
    },

    _service: null,
    _get_service: function() {
        if (this._service == null) {
            this._service = new AdCouncil.Services.ObjectModelService();
        }
        return this._service;
    },

    initialize: function(options) {
        this._setOptions(options);
    },

    populateCards: function(tag) {
        tag = tag || "";
        this._get_service().GetCalloutCards(tag, Function.createDelegate(this, this.populateCards_callback), null, null);
    },

    populateCards_callback: function(results, response, userContext) {
        this._formatHandler(results);
    },

    _setOptions: function(options) {
        this._options = this._getDefaultOptions();
        AdCouncil.Utilities.addDict(this._options, options);
        this._formatHandler = this._options.formatHandler;
    }
}

AdCouncil.CalloutCardsController.registerClass('AdCouncil.CalloutCardsController');

/*
* Comments
*/

AdCouncil.CommentController = function(options) {
    this.initialize(options);
};

AdCouncil.CommentController.prototype = {
    cCommentSuccessMessage: 'Your comment has been submitted. There may be a delay before it appears below.',
    cYouTubePopupTemplate: (
    '<div class="youtube-popup" id="divYouTubePopup_{0}">' +
        '<div style="position:relative;float:left;"><div class="youtube-popup-bg">' +
            '<p>You\'ll be briefly redirected to YouTube to log in or create an account before you post your comment. Then you\'ll be sent right back. Sorry for the inconvenience.</p>' +
            '<ul>' +
                '<li><a href="#" id="ancYouTubeLoginDecline_{0}"><img src="img/popup-nothanks.gif" width="58" height="18" border="0" alt="no thanks" title="no thanks" /></a></li>' +
                '<li><a href="#" id="ancYouTubeLoginAccept_{0}"><img src="img/popup-ok.gif" width="38" height="18" border="0" alt="OK" title="OK" /></a></li>' +
            '</ul>' +
        '</div></div>' +
    '</div>'
        ),

    videoID: null,
    guid: null,
    $commentTextField: null,
    $commentSubmitButton: null,
    $ancPrevious: null,
    $ancNext: null,
    $commentsContainer: null,
    $youTubeLoginPopup: null,
    currentIndex: 1,
    _options: null,

    getDefaultOptions: function() {
        return {
            videoID: null,
            idCommentTextField: null,
            idCommentSubmitButton: null,
            selAncPrevious: null,
            selAncNext: null,
            idCommentsContainer: null,
            numCommentsPerPage: 25,
            template: null,
            commentDateFormatter: Function.createDelegate(this, this.formatCommentDate),
            onRenderComplete: null,
            isLoggedIn: false,
            youTubeSignInUrl: null,
            trackingBase: ""
        };
    },

    initialize: function(options) {
        this.setProperties(options);
        this.loadComments();
        this.enableCommenting();
        this.handleCommentPrePosted();
    },

    setProperties: function(options) {
        this._options = this.getDefaultOptions();
        AdCouncil.Utilities.addDict(this._options, options);

        this.videoID = this._options.videoID;

        this.$commentTextField = $('#' + this._options.idCommentTextField);
        this.$commentTextField.click(Function.createDelegate(this, this.onCommentTextFieldClicked));

        this.$commentSubmitButton = $('#' + this._options.idCommentSubmitButton);
        this.$commentSubmitButton.click(Function.createDelegate(this, this.onCommentSubmitted));

        this.$ancPrevious = $(this._options.selAncPrevious);
        this.$ancPrevious.click(Function.createDelegate(this, this.onPreviousClicked));

        this.$ancNext = $(this._options.selAncNext);
        this.$ancNext.click(Function.createDelegate(this, this.onNextClicked));

        this.$commentsContainer = $('#' + this._options.idCommentsContainer);

        this.guid = AdCouncil.Utilities.getGuid();
    },

    loadComments: function(startIndex) {
        startIndex = Math.max((startIndex ? startIndex : 1), 1);
        var delegate = Function.createDelegate(this, this.loadComments_onFadedOut);
        var callback = Function.createCallback(delegate, { startIndex: startIndex });
        this.$commentsContainer.fadeOut('fast', callback);
    },

    handleCommentPrePosted: function() {
        var videoID = AdCouncil.Utilities.getQueryVal('commentPostedTo', '');
        if (videoID == this.videoID) {
            var response = eval('(' + AdCouncil.Utilities.getQueryVal('commentResponse', "") + ')');
            if (response && response != "") {
                this.disableCommenting();
                this.onCommentPostSuccess(response);
            }
        }
    },

    loadComments_onFadedOut: function(context) {
        this.currentIndex = context.startIndex;

        var onSuccess = Function.createDelegate(this, this.onCommentsLoaded);
        var onFail = Function.createDelegate(this, this.onCommentsLoadFailed);

        // NOTE: We load numCommentsPerPage+1 comments, but display numCommentsPerPage.  This way we can tell if there's another page to retrieve
        // without looking at the untrustworthy YouTubeEntry.Comments.CountHint property.

        AdCouncil.Services.ObjectModelService.GetComments(this.videoID, this.currentIndex, this._options.numCommentsPerPage + 1, onSuccess, onFail);
    },

    onPreviousClicked: function(event) {
        if (!eval($(event.target).attr('disabled'))) {
            this.loadComments(Math.max(1, this.currentIndex - this._options.numCommentsPerPage));
        }
        else $(event.target).blur();
        return false;
    },

    onNextClicked: function(event) {
        if (!eval($(event.target).attr('disabled'))) {
            this.loadComments(this.currentIndex + this._options.numCommentsPerPage);
        }
        else $(event.target).blur();
        return false;
    },

    onCommentTextFieldClicked: function(event) {
        if (this.$commentTextField.attr('disabled') && eval(this.$commentTextField.attr('disabled'))) return false;
        if (this.$commentTextField.val() == this.cCommentSuccessMessage) this.$commentTextField.val('');
    },

    onCommentsLoaded: function(comments) {
        var template = "";
        if (this._options.template) {
            template = this._options.template.toString();
        }
        else {
            var sb = new Sys.StringBuilder();
            sb.appendLine('<div class="comment">');
            sb.appendLine('<p class="comment-header"><strong><a href="http://www.youtube.com/user/{author}">{author}</a></strong> <em>({publishdate})</em></p>');
            sb.appendLine('<p style="overflow:hidden;text-overflow:ellipsis">{commentText}</p>');
            sb.appendLine('</div>');
            template = sb.toString();
        }
        var output = new Sys.StringBuilder();
        var i = 0;
        while (i < this._options.numCommentsPerPage && i < comments.length) {
            var currentTemplate = template;
            var comment = comments[i];

            currentTemplate = currentTemplate.replace('{publishdate}', this._options.commentDateFormatter(comment.Published));
            currentTemplate = currentTemplate.replace('{commentText}', AdCouncil.Utilities.htmlEncode(comment.Content));
            currentTemplate = currentTemplate.replace(/{author}/g, AdCouncil.Utilities.htmlEncode(comment.Author));

            output.append(currentTemplate.toString());

            i++;
        }

        this.$commentsContainer.html(output.toString()).fadeIn('fast');

        var isFirstPage = (this.currentIndex == 1);
        var isLastPage = (comments.length <= this._options.numCommentsPerPage);

        this.setupNavigationLinks(isFirstPage, isLastPage);
        if (this._options.onRenderComplete) this._options.onRenderComplete();
    },

    onCommentsLoadFailed: function() {
        this.setupNavigationLinks(true, true);
        this.$commentsContainer.html('<div class="comment"><p>Comments are temporarily unavailable for this item.</p></div>');
        if (this._options.onRenderComplete) this._options.onRenderComplete();
    },

    setupNavigationLinks: function(isFirstPage, isLastPage) {
        this.$ancPrevious.each(function() {
            $(this).attr('disabled', isFirstPage);
            if (isFirstPage) $(this).addClass('disabled');
            else $(this).removeClass('disabled');
        });

        this.$ancNext.each(function() {
            $(this).attr('disabled', isLastPage);
            if (isLastPage) $(this).addClass('disabled');
            else $(this).removeClass('disabled');
        });
    },

    onCommentSubmitted: function(event) {
        var commentText = this.$commentTextField.val();
        if (commentText == this.cCommentSuccessMessage) {
            this.$commentTextField.val("");
            return false;
        }

        if (commentText.trim() == "") return false;

        if (this._options.isLoggedIn) {
            this.postCommentDirectly();
        }
        else {
            this.showYoutubeLoginWarning();
        }
        return false;
    },

    showYoutubeLoginWarning: function() {
        if (!this.$youTubeLoginPopup) {
            this.createYoutubeLoginPopup();
        }

        this.$youTubeLoginPopup.showModal();
    },

    createYoutubeLoginPopup: function() {
        var divSelector = '#divYouTubePopup_' + this.guid;
        if ($(divSelector).length <= 0) {
            var html = String.format(this.cYouTubePopupTemplate, this.guid);
            $('body').append(html);
            this.$youTubeLoginPopup = $(divSelector);
            if (this.$youTubeLoginPopup.length <= 0) { AdCouncil.Utilities.log('popup not found!'); return false; }
            $('#ancYouTubeLoginAccept_' + this.guid, this.$youTubeLoginPopup).click(Function.createDelegate(this, this.onYouTubeLoginAcceptClick));
            $('#ancYouTubeLoginDecline_' + this.guid, this.$youTubeLoginPopup).click(Function.createDelegate(this, this.onYouTubeLoginDeclineClick));
        }
    },

    onYouTubeLoginAcceptClick: function(evt) {
        this.postCommentViaYoutubeLogin();
        return false;
    },

    onYouTubeLoginDeclineClick: function(evt) {
        this.$youTubeLoginPopup.hideModal();
        return false;
    },

    postCommentDirectly: function() {
        var commentText = this.$commentTextField.val();
        var onSuccess = Function.createDelegate(this, this.onCommentPostSuccess);
        var onFail = Function.createDelegate(this, this.onCommentPostFailure);

        this.$commentTextField.val('Sending comment...');
        this.disableCommenting();

        AdCouncil.Services.ObjectModelService.PostComment(this.videoID, commentText, onSuccess, onFail);
    },

    postCommentViaYoutubeLogin: function() {
        var commentText = this.$commentTextField.val();
        var nextLoc = this._options.youTubeSignInUrl.toString();

        var pathEncoded = AdCouncil.Utilities.safeEscape(location.pathname);
        var insertText = pathEncoded + AdCouncil.Utilities.safeEscape("?commentText_" + this.videoID + "=" + AdCouncil.Utilities.safeEscape(commentText))

        // Option 1: the path has a qs, so it ends with an encoded '?'.
        var pathWithQuestionMark = pathEncoded + AdCouncil.Utilities.safeEscape("?");
        if (nextLoc.indexOf(pathWithQuestionMark) > -1) {
            nextLoc = nextLoc.replace(pathWithQuestionMark, insertText + AdCouncil.Utilities.safeEscape("&"));
        }
        // Option 2: the path has no qs, so it ends with an UNENCODED '&'.
        else if (nextLoc.indexOf(pathEncoded + "&") > -1) {
            nextLoc = nextLoc.replace(pathEncoded + "&", insertText + "&");
        }

        location.href = nextLoc;
    },

    disableCommenting: function() {
        this.setElementsDisabled(true, [this.$commentTextField, this.$commentSubmitButton]);
    },

    enableCommenting: function() {
        this.setElementsDisabled(false, [this.$commentTextField, this.$commentSubmitButton]);
    },

    setElementsDisabled: function(disabled, elementList) {
        for (var i = 0; i < elementList.length; i++) {
            elementList[i].attr('disabled', disabled);
        }
    },

    onCommentPostSuccess: function(results) {
        if (results.Success) {
            this.$commentTextField.val(this.cCommentSuccessMessage);
            this.enableCommenting();
            this.fireCommentPostSuccessEvent();
        }
        else this.onCommentPostFailure(results.ErrorMessage, results);
    },

    onCommentPostFailure: function(error, results) {
        this.$commentTextField.val('Your comment could not be posted' + (error ? ': ' + error : '.'));
        if (results && results.ErrorDetail) AdCouncil.Utilities.log(results.ErrorDetail);
    },

    formatCommentDate: function(dt) {
        dt = new Date(dt);
        var oneMinute = 60000;
        var oneHour = oneMinute * 60;
        var oneDay = oneHour * 24;
        var oneWeek = oneDay * 7;

        var nextMonth = new Date(dt.getTime());
        if (nextMonth.getMonth() == 11) {
            nextMonth.setMonth(0);
            nextMonth.setFullYear(dt.getFullYear() + 1);
        }
        else {
            nextMonth.setMonth(dt.getMonth() + 1);
        }
        var oneMonth = nextMonth.getTime() - dt.getTime();

        var nextYear = new Date(dt.getTime());
        nextYear.setFullYear(nextYear.getFullYear() + 1);
        var oneYear = nextYear.getTime() - dt.getTime();

        var currentDate = new Date();
        var milliDifference = currentDate.getTime() - dt.getTime();


        if (milliDifference < oneMinute) {
            return "less than 1 minute ago";
        }
        else if (milliDifference < oneHour) {
            return AdCouncil.Utilities.formatQuantity(Math.floor(milliDifference / oneMinute), "minute") + " ago";
        }
        else if (milliDifference < oneDay) {
            return AdCouncil.Utilities.formatQuantity(Math.floor(milliDifference / oneHour), "hour") + " ago";
        }
        else if (milliDifference < oneWeek) {
            return AdCouncil.Utilities.formatQuantity(Math.floor(milliDifference / oneDay), "day") + " ago";
        }
        else if (milliDifference < oneMonth) {
            return AdCouncil.Utilities.formatQuantity(Math.floor(milliDifference / oneWeek), "week") + " ago";
        }
        else if (milliDifference < oneYear) {
            var monthDifference = currentDate.getMonth() - dt.getMonth();
            if (monthDifference < 0) monthDifference += 12;

            return AdCouncil.Utilities.formatQuantity(Math.max(1, monthDifference), "month") + " ago";
        }
        else {
            var yearDifference = currentDate.getFullYear() - dt.getFullYear();
            return AdCouncil.Utilities.formatQuantity(Math.max(1, yearDifference), "year") + " ago";
        }
    },

    fireCommentPostSuccessEvent: function() {
        RGA.Event.fire(gTrackEvent, String.format(this._options.trackingBase, "comment"));
    }
};

AdCouncil.CommentController.registerClass('AdCouncil.CommentController');


AdCouncil.StarRater = function(options) {
    this.initialize(options);
};



AdCouncil.StarRater.prototype = {
    $starContainer: null,
    guid: null,
    rating: null,

    _options: null,

    getDefaultOptions: function() {
        return {
            videoID: null,
            videoRatingAverage: null,
            starContainerID: null,
            starFullImgSrc: null,
            starEmptyImgSrc: null,
            starHalfImgSrc: null,
            isLoggedIn: false,
            youTubeSignInUrl: null,
            trackingBase: ""
        };
    },

    initialize: function(options) {
        this.setProperties(options);
        this.drawStarRating();
    },

    setProperties: function(options) {
        this._options = this.getDefaultOptions();
        AdCouncil.Utilities.addDict(this._options, options);
        this.$starContainer = $('#' + this._options.starContainerID);
        this.$starContainer.css('cursor', 'pointer');
        this.guid = AdCouncil.Utilities.getGuid();
        this.rating = this._options.videoRatingAverage;
    },

    drawStarRating: function(ratingSubmitted) {
        this.$starContainer.children().remove();
        for (var i = 1; i <= 5; i++) {
            var $star = this.getStarImg(i);
            if (this._options.isLoggedIn) {
                if (!ratingSubmitted) {
                    $star.data("origSrc", $star.attr('src'));
                    $star.data("starNum", i);
                    $star.hover(Function.createDelegate(this, this.onStarHover), Function.createDelegate(this, this.onStarUnhover));
                    $star.click(Function.createDelegate(this, this.onStarClick));
                }
                else {
                    var thanksStr = 'Thank you for your rating!';
                    $star.attr('title', thanksStr).attr('alt', thanksStr);
                }
            }
            this.$starContainer.append($star);
        }
        if (ratingSubmitted) {
            this.$starContainer.append('<span style="font-size:smaller">&nbsp;thanks for rating!</span>');
        }
        if (!this._options.isLoggedIn) {
            var youTubeSignInUrl = this._options.youTubeSignInUrl;
            this.$starContainer.click(function() { location.href = youTubeSignInUrl; });
            this.$starContainer.data('hoverOutHtml', this.$starContainer.html());
            this.$starContainer.hover(
                function() {
                    $(this).html('Log into YouTube to rate.');
                    $(this).css("text-decoration", 'underline').css('color', '#2E3790');
                },
                function() {
                    $(this).html($(this).data('hoverOutHtml'));
                    $(this).css("text-decoration", '').css('color', '');
                }
                );
        }
    },

    getStarImg: function(starNum) {
        var starID = this.makeStarID(starNum);
        var imgSrc = this.getStarImgSrc(starNum);
        var $img = $('<img src="' + imgSrc + '" id="' + starID + '" style="z-index:99999">');
        return $img;
    },

    makeStarID: function(starNum) {
        return "star" + starNum + "_" + this.guid;
    },

    getStarImgSrc: function(starNum) {
        var avg = this.rating;
        if (starNum < avg) {
            return this._options.starFullImgSrc;
        }
        else if (starNum - avg < 0.25) {
            return this._options.starFullImgSrc;
        }
        else if (starNum - avg < 0.75) {
            return this._options.starHalfImgSrc;
        }
        else {
            return this._options.starEmptyImgSrc;
        }
    },

    onStarHover: function(evt) {
        var $star = $(evt.target);
        var starNum = $star.data('starNum');
        for (var i = 1; i <= 5; i++) {
            var selector = '#' + this.makeStarID(i);
            var $curStar = $(selector);
            $curStar.attr('src', (i <= starNum ? this._options.starFullImgSrc : this._options.starEmptyImgSrc));
        }
    },
    onStarUnhover: function(evt) {
        for (var i = 1; i <= 5; i++) {
            var selector = '#' + this.makeStarID(i);
            var $curStar = $(selector);
            $curStar.attr('src', $curStar.data('origSrc'));
        }
    },

    onStarClick: function(evt) {
        var $star = $(evt.target);
        var ratingVal = $star.data('starNum');
        this.$starContainer.append('<span style="font-size:smaller">&nbsp;rating...</span>');

        $('img', this.$starContainer).unbind('mouseover').unbind('mouseout');

        if (this._options.isLoggedIn) {
            var userContext = { ratingVal: ratingVal };
            var onSuccess = Function.createDelegate(this, this.onRatingSuccess);
            var onFailure = Function.createDelegate(this, this.onRatingFailure);
            AdCouncil.Services.ObjectModelService.PostRating(this._options.videoID, ratingVal, onSuccess, onFailure, userContext);
        }
        else {
            var nextLoc = this._options.youTubeSignInUrl.toString();
            var pathEncoded = AdCouncil.Utilities.safeEscape(location.pathname + "?");
            if (nextLoc.indexOf(pathEncoded) > -1) {
                nextLoc = nextLoc.replace(pathEncoded, pathEncoded + AdCouncil.Utilities.safeEscape("commentText_" + this.videoID + "=" + AdCouncil.Utilities.safeEscape(commentText) + "&"));
            }
            location.href = nextLoc;
        }
    },

    onRatingSuccess: function(response, userContext) {
        if (!response.Success) this.onRatingFailure(response);
        this.finalizePostedRating(userContext.ratingVal);
        this.fireRatingEvent();
    },
    onRatingFailure: function(response, userContext) {
        // Note the error if we're debugging.
        AdCouncil.Utilities.log('rating failed: ' + response.ErrorMessage);
        // Pretend it worked.
        this.finalizePostedRating(userContext.ratingVal);
    },

    finalizePostedRating: function(ratingVal) {
        this.rating = ratingVal;
        this.drawStarRating(true);
    },

    fireRatingEvent: function() {
        RGA.Event.fire(gTrackEvent, String.format(this._options.trackingBase, "rate"));
    }
};

AdCouncil.StarRater.registerClass('AdCouncil.StarRater');


// Notify ScriptManager that this is the end of the script.
if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();

