/**
 * Constructor for RatingsWidget.  The config parameter is critial.
 * It determines how this widget looks and operates.  Without
 * meaningful properties set in the config object, the widget won't do
 * anything useful at all.
 *
 * @param name is a unique widget name for the current page, can only
 *             contain JavaScript legal characters for variable names
 * @param config a config object that specifies how this widget looks and operates
 */

function RatingsWidget(name, config)
{
    this.name = name;

    // Required configuration for interactive ratings
    //
    this.content_id = config.content_id;
    this.id_type = config.id_type;
    this.appcontext = config.appcontext;
    this.fromcontext = config.fromcontext;
    this.screen_name = config.screen_name;
    this.rating_handler = config.rating_handler;
    this.type = config.type;
    this.size = config.size;

    // Can ratings be changed after initially set?
    //
    this.disable_rating_change = config.disable_rating_change ? true : false;

    // Text behavior settings
    //
    this.text_align = config.text_align;
    this.rollover_stars_rlabel = config.rollover_stars_rlabel ? true : false;
    this.lock_rlabel_after_rating = config.lock_rlabel_after_rating ? true : false;

    //
    // Initialize min/max/avg/member ratings
    //

    if (config.min_rating === undefined) {
        this.min_rating = 1;
    }
    else {
        this.min_rating = config.min_rating;
    }

    if (config.max_rating === undefined) {
        this.max_rating = 5;
    }
    else {
        this.max_rating = config.max_rating;
    }

    if (config.slash_rating === undefined) {
        this.slash_rating = 0;
    }
    else {
        this.slash_rating = config.slash_rating;
    }

    if (config.avg_rating === undefined) {
        this.avg_rating = undefined;
        this.display_mode = 'rating';
    }
    else {
        this.avg_rating = config.avg_rating;
        this.display_mode = 'average';
    }

    if (config.rating === undefined) {
        this.is_rated = false;
        this.rating = undefined;
        if (this.display_mode != 'rating') {
            this.display_mode = 'average';
        }
    }
    else {
        this.is_rated = true;
        this.rating = config.rating;
        this.display_mode = 'rating';
    }

    this.is_hovering = false;

    //
    // Assign unique image and other element ids
    //

    if (this.type == 'reco') {
        this.slash_img_id = this.name + '_slash_img_id';
    }

    for (var i = this.min_rating; i <= this.max_rating; i++) {
        var img_id = 'star_img_id_' + i;
        this[img_id] = this.name + '_' + img_id;
    }

    this.rlabel_id = this.name + '_rlabel_id';
    this.tlabel_id = this.name + '_tlabel_id';
    this.submit_iframe_id = this.name + '_submit_iframe_id';
    this.form_element_id = config.form_element_id;

    //
    // Preload images
    //

    if (config.img_prefix === undefined) {
        this.img_prefix = '';
    }
    else {
        this.img_prefix = config.img_prefix;
    }


    if (config.img_star_over) {
        this.img_star_over = new Image();
        this.img_star_over.src = this.img_prefix + config.img_star_over;
    }

    if (config.img_star_on) {
        this.img_star_on = new Image();
        this.img_star_on.src = this.img_prefix + config.img_star_on;
    }

    if (config.img_star_off) {
        this.img_star_off = new Image();
        this.img_star_off.src = this.img_prefix + config.img_star_off;
    }


    if (config.img_title_textbg) {
        this.img_title_textbg = new Image();
        this.img_title_textbg.src = this.img_prefix + config.img_title_textbg;
    }

    if (config.img_cor_l) {
        this.img_cor_l = new Image();
        this.img_cor_l.src = this.img_prefix + config.img_cor_l;
    }

    if (config.img_cor_r) {
        this.img_cor_r = new Image();
        this.img_cor_r.src = this.img_prefix + config.img_cor_r;
    }

    if (config.img_cor_tl_title) {
        this.img_cor_tl_title = new Image();
        this.img_cor_tl_title.src = this.img_prefix + config.img_cor_tl_title;
    }

    if (config.img_cor_tr_title) {
        this.img_cor_tr_title = new Image();
        this.img_cor_tr_title.src = this.img_prefix + config.img_cor_tr_title;
    }

    if (config.img_cor_bl) {
        this.img_cor_bl = new Image();
        this.img_cor_bl.src = this.img_prefix + config.img_cor_bl;
    }

    if (config.img_cor_br) {
        this.img_cor_br = new Image();
        this.img_cor_br.src = this.img_prefix + config.img_cor_br;
    }

    if (this.type == 'reco') {
        if (config.img_slash_over) {
            this.img_slash_over = new Image();
            this.img_slash_over.src = this.img_prefix + config.img_slash_over;
        }

        /* Never used
        if (config.img_slash_on) {
            this.img_slash_on = new Image();
            this.img_slash_on.src = this.img_prefix + config.img_slash_on;
        }
        */

        if (config.img_slash_off) {
            this.img_slash_off = new Image();
            this.img_slash_off.src = this.img_prefix + config.img_slash_off;
        }
    }


    //
    // Set up text labels.
    //

    if (config.tlabel_text_myrating) {
        this.tlabel_text_myrating = config.tlabel_text_myrating;
    }

    if (config.tlabel_text_rateitnow) {
        this.tlabel_text_rateitnow = config.tlabel_text_rateitnow;
    }

    if (config.tlabel_text_average) {
        this.tlabel_text_average = config.tlabel_text_average;
    }

    if (config.tlabel_text_width) {
        this.tlabel_text_width = config.tlabel_text_width;
    }


    if (config.rlabel_text_seemy) {
        this.rlabel_text_seemy = config.rlabel_text_seemy;
    }

    if (config.rlabel_text_seeaverage) {
        this.rlabel_text_seeaverage = config.rlabel_text_seeaverage;
    }

    if (config.rlabel_text_clickstars) {
        this.rlabel_text_clickstars = config.rlabel_text_clickstars;
    }

    for (var i = this.min_rating; i <= this.max_rating; i++) {
        var text_id = 'rlabel_text_' + i;
        if (config[text_id]) {
            this[text_id] = config[text_id];
        }
    }

    var slash_text_id = 'rlabel_text_' + this.slash_rating;
    if (config[slash_text_id]) {
        this[slash_text_id] = config[slash_text_id];
    }

    if (config.hover_popup_text) {
        this.hover_popup_text = config.hover_popup_text;
    }

    all_widgets[this.name] = this;
}


/**
 * Returns the HTML id/name of a ratings star image with the given
 * value.
 */

RatingsWidget.prototype.getStarImgId = function(idx)
{
    return this['star_img_id_' + idx];
}


/**
 * Returns the HTML id/name of the slash rating image.
 */

RatingsWidget.prototype.getSlashImgId = function()
{
    return this['slash_img_id'];
}

/**
 * Returns the HTML id/name of the ratings text label string.
 */

RatingsWidget.prototype.getRatingLabelId = function()
{
    return this['rlabel_id'];
}

/**
 * Returns the HTML id/name of the ratings title label string.
 */

RatingsWidget.prototype.getTitleLabelId = function()
{
    return this['tlabel_id'];
}

/**
 * Returns the HTML id/name of the submit iframe.
 */

RatingsWidget.prototype.getSubmitIframeId = function()
{
    return this['submit_iframe_id'];
}


/**
 * Paints the ratings widget by changing the images to those appropriate
 * for the widget's current state.
 */

RatingsWidget.prototype.paint = function()
{
    //
    // Paint rating images (slash and stars)
    //

    // Show the slash for reco type widgets
    //
    if (this.type == 'reco') {
        var slash_img_src = '';

        if (this.is_hovering) {
            if (this.hovering_at == this.slash_rating) {
                slash_img_src = this.img_slash_over.src;
            }
        }
        else if (this.display_mode == 'average') {
            slash_img_src = this.img_slash_off.src;
        }
        else if (this.is_rated) {
            if (this.rating == this.slash_rating) {
                slash_img_src = this.img_slash_over.src;
            }
        }

        if (slash_img_src == '') {
            slash_img_src = this.img_slash_off.src;
        }

        document[this.getSlashImgId()].src = slash_img_src;
    }

    // Show rating stars
    //
    for (var i = this.min_rating; i <= this.max_rating; i++) {
        var star_img_src = '';

        if (this.is_hovering) {
            if (this.hovering_at != this.slash_rating) {
                if (i <= this.hovering_at) {
                    star_img_src = this.img_star_over.src;
                }
            }
            else {
                star_img_src = this.img_star_off.src;
            }
        }
        else if (this.display_mode == 'average') {
            if (i <= this.avg_rating) {
                star_img_src = this.img_star_on.src;
            }
        }
        else if (this.is_rated) {
            if (i <= this.rating && this.rating != this.slash_rating) {
                star_img_src = this.img_star_over.src;
            }
        }

        if (star_img_src == '') {
            star_img_src = this.img_star_off.src;
        }

        document[this.getStarImgId(i)].src = star_img_src;
    }

    //
    // Paint text labels
    //

    if (this.text_align) {
        var rlabel = '';
        var tlabel = '';

        if (this.is_hovering) {
            if (this.is_rated) {
                if (this.lock_rlabel_after_rating) {
                    if (this.display_mode == 'average' && this.is_rated) {
                        rlabel = this.rlabel_text_seemy;
                    }
                    else {
                        rlabel = this.rlabel_text_seeaverage;
                    }
                }
                else {
                    rlabel = this['rlabel_text_' + this.hovering_at];
                }
            }
            else {
                rlabel = this['rlabel_text_' + this.hovering_at];
            }

            tlabel = this.tlabel_text_myrating;
        }
        else if (this.display_mode == 'average') {
            if (this.is_rated) {
                rlabel = this.rlabel_text_seemy;
            }
            else {
                rlabel = this.rlabel_text_clickstars;
            }
            tlabel = this.tlabel_text_average;
        }
        else {
            rlabel = this.rlabel_text_seeaverage;

            if (this.is_rated) {
                tlabel = this.tlabel_text_myrating;
            }
            else {
                tlabel = this.tlabel_text_rateitnow;
            }
        }

        if (this.text_align != 'combined') {
            if (this.is_hovering && this.rollover_stars_rlabel) {
                document.getElementById(this.getTitleLabelId()).innerHTML = rlabel;
            }
            else {
                document.getElementById(this.getTitleLabelId()).innerHTML = tlabel;
            }
        }
        else {
            var rlabel_el = document.getElementById(this.getRatingLabelId());
            if (rlabel_el) {
                rlabel_el.innerHTML = rlabel;
            }

            var tlabel_el = document.getElementById(this.getTitleLabelId());
            if (tlabel_el) {
                tlabel_el.innerHTML = tlabel;
            }
        }
    }
}


/**
 * Called when the user's mouse enters a rating star.
 */

RatingsWidget.prototype.ratingOver = function(element, value)
{
    if (this.is_rated && this.disable_rating_change) {
        // No pointer cursor on rated widgets when rating change is
        // disabled.
        //
        element.style.cursor = '';
    }
    else {
        element.style.cursor = 'pointer';
        this.is_hovering = true;
        this.hovering_at = value;
    }
    this.paint();
    return true;
}


/**
 * Called when the user's mouse leaves a rating star.
 */

RatingsWidget.prototype.ratingOut = function(element, value)
{
    this.is_hovering = false;
    this.paint();
    return true;
}


/**
 * Called when the user clicks on a rating star.
 */

RatingsWidget.prototype.ratingUp = function(element, value)
{
    var old_rating;

    // Ratings are disabled on rated widgets when rating change is
    // disabled.
    //
    if (! (this.is_rated && this.disable_rating_change)) {
        if (this.is_rated) {
            old_rating = this.rating;
        }

        this.is_rated = true;
        this.rating = parseInt(value);
        this.display_mode = 'rating';

        // Only submit rating to backend if rating changed.
        //
        if (this.rating != old_rating) {
            this.submitRating();
        }
    }

    this.paint();
    return true;
}


/**
 * Called when the user's mouse enters the text field.
 */

RatingsWidget.prototype.textOver = function(element)
{
    if (this.is_rated) {
        element.style.cursor = 'pointer';
    }
    return true;
}


/**
 * Called when the user's mouse leaves the text field.
 */

RatingsWidget.prototype.textOut = function(element)
{
    return true;
}


/**
 * Called when the user clicks on the text field.
 */

RatingsWidget.prototype.textUp = function(element)
{
    if (this.display_mode == 'average' && this.is_rated) {
        this.display_mode = 'rating';
    }
    else {
        this.display_mode = 'average';
    }
    this.paint();
    
    return true;
}


/**
 * This method is a workaround for Mozilla wanting to start a text
 * selection when the rating text is clicked.  Yes, the paint is
 * needed here (unless you can think of something better.
 */

RatingsWidget.prototype.textDown = function(element)
{
    this.paint();
    return true;
}


/**
 * Submits the rating to the backend server.
 */

RatingsWidget.prototype.submitRating = function()
{
    // Need to verify that this method of changing an iframe's source
    // works on all target platforms.
    //
    var iframe = frames[this.getSubmitIframeId()];

    if (iframe) {
        // The URL that handles the ratings takes two arguments, a screen
        // name and a ratings list.  The ratings list contains the id of
        // the thing being rated and its rating.
        //
        var args = new Object();
        args.sn = this.screen_name;
		args.appcontext = this.appcontext;
		args.fromcontext = this.fromcontext;
        args.idspace = this.id_type;

        // The extra comma at the end is a placeholder review text in the
        // future.
        //
        args.ratings = '(' + this.content_id + ',' + this.rating + ',)';

        var qs = buildQueryString(args);
        iframe.location.href = this.rating_handler + '?' + qs;
    }

    // If a form element ID specified, also store the rating in there.
    var form_element = document.getElementById(this.form_element_id);
    if (form_element) {
        form_element.value = this.rating;
    }

    return true;
}


RatingsWidget.prototype.getAllHtml = function()
{
    return this.getWidgetHtml() + this.getIframeHtml();
}


/**
 * Returns the HTML that displays the rating widget.
 */

RatingsWidget.prototype.getWidgetHtml = function()
{
    // Set up hard-coded styles so that document styles won't override
    // this stuff.
    //
    var compacted_style = 'padding: 0px; margin: 0px; border: none; ';
    var center_style = 'text-align: center; ';

    var bgcolor_style;
    if (this.type == 'static') {
        bgcolor_style = '';
    }
    else {
        bgcolor_style = 'background-color: white; ';
    }

    var table_attr = 'style="' + compacted_style + '"';
    var title_td_attr = table_attr;
    var title_img_attr = table_attr;
    var td_attr = 'style="' + compacted_style + '"';
    var tr_attr = td_attr;
    var img_attr = td_attr;
    var stars_tr_attr = 'style="' + compacted_style + bgcolor_style + '"';
    var stars_td_attr = 'style="' + compacted_style + bgcolor_style + center_style + '"';

    var html = '';

    if (this.text_align == 'vertical' || this.text_align == 'horizontal') {
        html += '<table ' + table_attr + ' cellpadding="0" cellspacing="0" border="0" class="ratings_widget">';
        html += '<tr>';

        var text_style =
            compacted_style +
            'font-size: 11px; white-space: nowrap; ';
        if (this.text_align == 'vertical') {
            text_style += center_style;
        }
        else {
            text_style += 'text-align: right; width: ' + this.tlabel_text_width + 'px; ';
        }

        html +=
            '<td ' +
            ' style="' + compacted_style + '"' +
            '>';
        html +=
            '<div' +
            ' style="' + text_style + '"' +
            ' id="' + this.getTitleLabelId() + '"' +
            ' name="' + this.getTitleLabelId() + '"' +
            '>';
        html += '</div>';
        html += '</td>';

        if (this.text_align == 'vertical') {
            html += '</tr>';
            html += '<tr>';
        }

        html += '<td ' + td_attr + '>';
    }


    html +=
        '<table ' +
        table_attr +
        ' class="ratings_widget ratings_widget_' + this.name + '"' +
        //' style="display: inline;"' +
        ' cellpadding="0"' +
        ' cellspacing="0"' +
        ' border="0"' +
        '>';


    if (this.type == 'static') {
        html += '<tr>';
        html += '<td>';
    }
    else if (this.text_align == 'combined') {
        // Top border and title
        //
        html += '<tr>';
        html += '<td style="heightx: 14px; background: url(\'' + this.img_cor_tl_title.src + '\') no-repeat left top; padding: 0 0 0 4px; white-space: nowrap">';
        html += '<div style="background: url(\'' + this.img_cor_tr_title.src + '\') no-repeat right top; text-align: center; padding: 0 4px 0 0;">';

        // Title text
        //
        html +=
            '<span' +
            ' id="' + this.getTitleLabelId() + '"' +
            ' name="' + this.getTitleLabelId() + '"' +
            ' style="font-size: 11px; font-family: arial, sans-serif; color: #000000; font-weight: bold; background-image: url(\'' + this.img_title_textbg.src + '\'); padding: 0 1px;"' +
            '>';
        html += '</span>';

        html += '</div>';
        html += '</td>';
        html += '</tr>';

        // Rating text
        //
        html += '<tr>';
        html += '<td style="background: url(\'' + this.img_cor_bl.src + '\') no-repeat bottom left; padding: 0 0 0 4px; white-space: nowrap">';
        html += '<div style="background: url(\'' + this.img_cor_br.src + '\') no-repeat bottom right; text-align: center; padding: 0 4px 3px 0;">';

        html +=
            '<div' +
            ' id="' + this.getRatingLabelId() + '"' +
            ' name="' + this.getRatingLabelId() + '"' +
            ' style="font-size: 9px; font-family: arial, sans-serif; color: #1C5BB0; line-height: 9px; text-align: center; padding: 1px 2px 1px 0;"' +
            ' onmouseover="all_widgets.' + this.name + '.textOver(this);"' +
            ' onmouseout="all_widgets.' + this.name + '.textOut(this);"' +
            ' onmouseup="all_widgets.' + this.name + '.textUp(this);"' +
            ' onmousedown="all_widgets.' + this.name + '.textDown(this);"' +
            '>';
        html += '</div>';
    }
    else {
        var td_padding;
        var div_padding;
        if (this.size == 'small') {
            td_padding = 'padding: 0px 0px 0px 3px';
            div_padding = 'padding: 2px 3px 2px 0px';
        }
        else {
            td_padding = 'padding: 0px 0px 0px 4px';
            div_padding = 'padding: 3px 4px 3px 0px';
        }

        html += '<tr>';
        html += '<td style="background: url(\'' + this.img_cor_l.src + '\') no-repeat top left; ' + td_padding + '; white-space: nowrap;">';
        html += '<div style="background: url(\'' + this.img_cor_r.src + '\') no-repeat top right; text-align: center; ' + div_padding + ';">';
    }

    //
    // At this point, a tr, td, and div should be open to contain the
    // rating stars.
    //

    // Show the "Don't recommend" slash before the rating stars.
    //
    if (this.type == 'reco') {
        html +=
            '<img ' +
            img_attr +
            ' border="0"' +
            ' name="' + this.getSlashImgId() + '"' +
            ' id="' + this.getSlashImgId() + '"';

        // Set hover text
        //
        html += ' title="' + this['rlabel_text_' + this.slash_rating] + '"';

        html +=
            ' onmouseover="all_widgets.' + this.name + '.ratingOver(this, ' + squote(this.slash_rating) + ');"' +
            ' onmouseout="all_widgets.' + this.name + '.ratingOut(this, ' + squote(this.slash_rating) + ');"' +
            ' onmouseup="all_widgets.' + this.name + '.ratingUp(this, ' + squote(this.slash_rating) + ');"' +
            '/>';
    }

    // The rating stars
    //
    for (var i = this.min_rating; i <= this.max_rating; i++) {
        html +=
            '<img ' +
            img_attr +
            ' border="0"' +
            ' name="' + this.getStarImgId(i) + '"' +
            ' id="' + this.getStarImgId(i) + '"';

        // Set hover text
        //
        html += ' title="' + this['rlabel_text_' + i] + '"';

        // Don't give the "average" type widget rollover functionality.
        //
        if (this.type != 'static') {
            html +=
                ' onmouseover="all_widgets.' + this.name + '.ratingOver(this, ' + squote(i) + ');"' +
                ' onmouseout="all_widgets.' + this.name + '.ratingOut(this, ' + squote(i) + ');"' +
                ' onmouseup="all_widgets.' + this.name + '.ratingUp(this, ' + squote(i) + ');"';
        }

        html += '/>';
    }

    if (this.type != 'static') {
        html += '</div>';
    }

    html += '</td>';
    html += '</tr>';
    html += '</table>';


    if (this.text_align == 'horizontal' || this.text_align == 'vertical') {
        html += '</td></tr></table>';
    }

    // Call paint() to display all the images for the widget's initial
    // state.
    //
    html +=
        '<script>' +
        'all_widgets.' + this.name + '.paint();' +
        '</script>';


    return html;
}


RatingsWidget.prototype.getIframeHtml = function(height, width)
{
    if (this.type == 'static') {
        return '';
    }

    if (height === undefined) {
        height = 0;
    }
    if (width === undefined) {
        width = 0;
    }

    var frameborder = 1;
    if (height == 0 && width == 0) {
        frameborder = 0;
    }

    var html = '';
    html += 
        '<iframe' +
        //' style="display: none;"' +
        ' width="' + width + '"' +
        ' height="' + height + '"' +
        ' frameborder="' + frameborder + '"' +
        ' name="' + this.getSubmitIframeId() + '"' +
        ' id="' + this.getSubmitIframeId() + '"' +
        '></iframe>';

    return html;
}


/**
 * CVS version
 */

RatingsWidget.version =
    "$Revision: 1.11.2.3 $".replace(/\$\Revision:\s*(.+?)\s*\$/, "$1");


/**
 * Global associative array containing all widget objects on this page
 * by name.  Widgets are indexed by name.  For example, a widget named
 * 'w1' can be found via 'all_widgets.w1'.
 */

all_widgets = new Object();


//
// Utility functions
//

function squote(s)
{
    // !!! should regexp replace all ' in s
    //
    return "'" + s + "'";
}


function buildQueryString(args)
{
    var qs = '';
    for (var i in args) {
        qs += (qs == '') ? '': '&';
        qs += escape(i) + '=' + escape(args[i]);
    }
    return qs;
}


function parseQueryString(str)
{
    str = str ? str : location.search;
    var query = str.charAt(0) == '?' ? str.substring(1) : str;
    var args = new Object();
    if (query) {
        var fields = query.split('&');
        for (var f = 0; f < fields.length; f++) {
            var field = fields[f].split('=');
            args[unescape(field[0].replace(/\+/g, ' '))] = 
                unescape(field[1].replace(/\+/g, ' '));
        }
    }
    return args;
}


function cloneObject(o)
{
    var o2 = new Object();
    for (i in o) {
        o2[i] = o[i];
    }
    return o2;
}

RatingsWidget.getSNSPreAuthHTML = function (rwScriptDir, ratingsHandler, debug)
{
	if (!debug || debug == '') debug = false;
	//else ratingsHandler = 'debug.html';

	RatingsWidget.SNSPreAuthURL = ratingsHandler;

	// First, create the div that hides the frames and create the outer-most frame inside the div.
	var html = '<div id="rwsnspreauth" style="'+(debug?'':'visibility: hidden; position: absolute;')+'"><iframe width="'+(debug?'500':'0')+'" height="'+(debug?'300':'0')+'" src="'+rwScriptDir+'/rwsnspreauth1.html"></iframe></div>';

	return html;
}

//
// end of ratings_widget.js
//
