var _itemPageRegister = {};
var _items = {};
var _skins = {};
var _configTable = {};
var _ratingConfigCount = 0;
var _cs_del = "-|-";
var _id_del = "-x-";
var _ratingSkinPath = "/ContentRatingResourceFiles/Scripts/Simple/RatingSkin.js";
var _idAddOnImageRatings = 'RatingsImage';
// the below two variables are now getting added by the rating server control that is dropped on the master pages
//var _ratingsWebRelativeURL = "";
//var _servicePrefix;

/******************************************************************
Core UI tokens
******************************************************************/
var _totalRatingsToken = '@totalRatings#';
var _averageRoundedRatingsToken = '@averageRoundedRatings#';
var _averageRatingsToken = '@averageRating#';
var _controlIdToken = '@itemId#';
var _myRatingToken = '@myRating#';
var _configKeyToken = '@configKey#';
var _idPrefixEnableUsefulness = 'enableUsefulness';
var _idPrefixRatingDisplayAverageRating = 'ratingDisplayAverageRating';
var _idPrefixRatingDisplayTotalRatings = 'ratingDisplayTotalRatings';
var _idPrefixRatingDisplayMyRating = 'ratingDisplayMyRating';
var _idPrefixRatingDisplayPopupCommentControl = 'ratingDisplayPopupCommentControl';
var _idPrefixCommentDisplayAverageRating = 'commentDisplayAverageRating';
var _idPrefixCommentDisplayTotalRatings = 'commentDisplayTotalRatings';
var _idPrefixCommentDisplayMyRating = 'commentDisplayMyRating';

/******************************************************************
Core UI rendering functions
******************************************************************/
function AddJavaScriptRatingSkinReference(path, elementid) {
    var ns = document.createElement('script');
    ns.setAttribute('type', 'text/javascript');
    ns.setAttribute('language', 'javascript');
    ns.setAttribute('id', elementid);
    document.getElementsByTagName('head')[0].appendChild(ns);
    document.getElementById(elementid).src = path;
}
function SetRelUrl() {
    if (_ratingsWebRelativeURL == "") {
        var re = /'(.*?)'/;
        var func = WebForm_OnSubmit.toString();
        var site = func.match(re);
        _ratingsWebRelativeURL = site[0].substring(1, site[0].length - 1);
        _servicePrefix = _ratingsWebRelativeURL.replace(/\\u002f/g, "/");
        _ratingsWebRelativeURL = _servicePrefix;

        if (_servicePrefix == "/")
            _servicePrefix = "/_layouts/Service.Ratings";
        else {
            _servicePrefix = _servicePrefix + "/_layouts/Service.Ratings";
        }
    }
}

AddJavaScriptRatingSkinReference(_ratingSkinPath, 'ratingskin');


// this call is coming from a search page ns_scope
function renderRatingControls(configurationName, contentSourceId) {
    var controlid;
    var config = Config.GetInstance(configurationName, false);
    if (config.error.number > 0) { alert(config.error.message); return; }

    var configKey = contentSourceId + _cs_del + _ratingConfigCount;
    _configTable[configKey] = config;

    if (config != null) {
        var itemIds = _itemPageRegister[_ratingConfigCount];
        var list = itemIds.join(',');
        config.ratedItems = RatedItemCollection.GetInstance(contentSourceId, list, false, ""); //changed for RollUp
        config.ratings = RatingCollection.GetInstance(contentSourceId, list, true);

        for (var i = 0; i < itemIds.length; i++) {
            controlid = configKey + _id_del + itemIds[i];
            currentControl = document.getElementById(controlid);
            var ratedItem = config.ratedItems.GetItem(itemIds[i]);

            //if ratedItem not found in database, add to the ratedItems
            if (ratedItem == null) {
                ratedItem = RatedItem.GetInstance(contentSourceId, itemIds[i], _items[itemIds[i]].itemTitle, _items[itemIds[i]].itemUrl, 0, 0);
                config.ratedItems.AddItem(ratedItem);
            }
            else if (ratedItem.title == '') {
                ratedItem.title = _items[itemIds[i]].itemTitle;
                ratedItem.url = _items[itemIds[i]].itemUrl;
            }

            //Reset Rollup value from item info
            if (_configTable[configKey].EnableRollUp && _configTable[configKey].RollUpColumnName.toLowerCase() != 'None'.toLowerCase()) {
                ratedItem.rollUp = _items[itemIds[i]].itemRollUp;
            }
            else
                ratedItem.rollUp = "None";


            var averageRoundedRating = computeRoundedAverageRating(ratedItem.averageRating);
            ratedItem.controlPrefix = controlid;

            currentControl.innerHTML = tokenReplace(config.ratingSkinHtml
				, _totalRatingsToken, ratedItem.totalRatings
				, _averageRoundedRatingsToken, averageRoundedRating
				, _averageRatingsToken, ratedItem.averageRating
				, _controlIdToken, ratedItem.controlPrefix
				, _configKeyToken, configKey);

            renderRatingsImagesById(ratedItem.controlPrefix + _idAddOnImageRatings, averageRoundedRating * 2, "rated");
            applyControlMasking(ratedItem.controlPrefix);
        }
    }
    _ratingConfigCount = _ratingConfigCount + 1;
}
var _listMetadata = null;
var _fetchOnce = true;
var _listWebUrl = null;

function renderListRatingControl(listGuid, ratingContent, itemId, title, url, configurationName, webId) {
    if (ratingContent == "")
        ratingContent = "0,0";
    var AverageRating = parseNumber(ratingContent.split(",")[0]);
    var TotalRatings = parseNumber(ratingContent.split(",")[1]);
    var contentSourceId = null;
    var configKey = null;
    var config = null;

    if (_listMetadata == null || _listMetadata[listGuid + _ratingConfigCount] == null) {
        _listMetadata = {};
        _listMetadata[listGuid + _ratingConfigCount] = {};
        if (webId == null) {
            var indexVtiBin = ctx.HttpPath.indexOf('_vti_bin');
            _listWebUrl = ctx.HttpPath.substring(1, indexVtiBin);
            contentSourceId = (replaceString('/', _id_del, _listWebUrl) + "@" + listGuid);
            config = Config.GetInstance(contentSourceId, true);
            webId = "{" + config.webId + "}";
        }
        else
            config = Config.GetInstance(configurationName, false);

        if (config.error.number > 0) { alert(config.error.message); return; }

        _listMetadata[listGuid + _ratingConfigCount].contentSourceId = (webId + "@" + listGuid);
        configKey = _listMetadata[listGuid + _ratingConfigCount].contentSourceId + _cs_del + _ratingConfigCount;
        _configTable[configKey] = config;
    }

    contentSourceId = _listMetadata[listGuid + _ratingConfigCount].contentSourceId;
    configKey = contentSourceId + _cs_del + _ratingConfigCount;

    var ratedItem;

    if (_configTable[configKey].EnableRollUp && _configTable[configKey].RollUpColumnName.toLowerCase() != 'None'.toLowerCase()) {
        ratedItem = RatedItem.GetInstance(contentSourceId, itemId, title, url, AverageRating, TotalRatings, _configTable[configKey].RollUpColumnName);

    }
    else {
        ratedItem = RatedItem.GetInstance(contentSourceId, itemId, title, url, AverageRating, TotalRatings);

    }	

    ratedItem.controlPrefix = contentSourceId + _cs_del + _ratingConfigCount + _id_del + itemId;
    _configTable[configKey].ratedItems.AddItem(ratedItem);
    _configTable[configKey].ratings.contentSourceId = contentSourceId;
    _configTable[configKey].ratings.AddItemId(itemId);
    
    //alert(ratedItem.controlPrefix.toString());
    

    var averageRoundedRating = computeRoundedAverageRating(ratedItem.averageRating);

    var renderedHtml = tokenReplace(_configTable[configKey].ratingSkinHtml
    								, _totalRatingsToken, TotalRatings
    								, _averageRoundedRatingsToken, averageRoundedRating
    								, _averageRatingsToken, AverageRating
    								, _controlIdToken, ratedItem.controlPrefix
    								, _configKeyToken, configKey);
    document.write("<div id='" + ratedItem.controlPrefix + "'>" + renderedHtml + "</div>");

    renderRatingsImagesById(ratedItem.controlPrefix + _idAddOnImageRatings, averageRoundedRating * 2, "rated");
    applyControlMasking(ratedItem.controlPrefix);
    
    var userRated = _configTable[configKey].ratings.GetRating(itemId);
	if (userRated == null) 
	{
		//alert("unrated");
	}
	else 
	{
		//alert("rated");
		ShowAlreadyRated(ratedItem.controlPrefix.toString());
	}
}

function ShowAlreadyRated(lblId)
{
	var statusLabel = document.getElementById("label" + lblId);
	if (statusLabel != null)
	{
		statusLabel.innerHTML = "Already Rated";
		statusLabel.id = "removedLabel" + lblId;
	}
	//else
	//alert("WHYYY? " + lblId);
}

function LoadContentRatingReview(parentConfiguration, skinType, webPartId, querystringParameterNameContentSourceId, querystringParameterNameItemId,
							contentSourceId, itemId, averageRating, totalRatings, providerWebPartId) {
    var ratedItem = null;
    var ratings;
    computeQueryString();

    var wepPart = document.getElementById(webPartId);

    var config = Config.GetInstance(parentConfiguration, false);
    if (config.error.number > 0) { alert(config.error.message); return; }
    config.providerWebPartId = providerWebPartId;

    var contentNamespace = (contentSourceId) ? contentSourceId : qsParm[querystringParameterNameContentSourceId];
    var configKey = contentNamespace + _cs_del + _ratingConfigCount;
    _configTable[configKey] = config;

    var configRollUpColumnName = "None";
    if (_configTable[configKey].EnableRollUp && _configTable[configKey].RollUpColumnName.toLowerCase() != 'None'.toLowerCase())
        configRollUpColumnName = _configTable[configKey].RollUpColumnName;

    //remove all children
    if (wepPart.hasChildNodes())
        while (wepPart.childNodes.length >= 1)
        wepPart.removeChild(wepPart.firstChild);

    if (contentSourceId != null && itemId != null && averageRating != null && totalRatings != null) {
        ratedItem = RatedItem.GetInstance(contentSourceId, itemId, document.nameProp, window.location.href.replace(window.location.search, ""), averageRating, totalRatings);
        ratedItem.controlPrefix = contentSourceId + _cs_del + _ratingConfigCount + _id_del + itemId;
        ratings = RatingCollection.GetInstance(contentSourceId, itemId, true);

        ratedItem.rollUp = configRollUpColumnName; // used for internal items, column's display name is passed
    }
    else if (qsParm[querystringParameterNameContentSourceId] != null && qsParm[querystringParameterNameItemId] != null) {
        ratedItem = RatedItem.GetInstance(qsParm[querystringParameterNameContentSourceId], qsParm[querystringParameterNameItemId]);
        ratedItem.controlPrefix = ratedItem.contentSourceId + _cs_del + _ratingConfigCount + _id_del + ratedItem.itemId;
        ratings = RatingCollection.GetInstance(ratedItem.contentSourceId, ratedItem.itemId, true);

        if (configRollUpColumnName != "None" && configRollUpColumnName.length > 0) {
            if (typeof qsParm[configRollUpColumnName] != "undefined")
                ratedItem.rollUp = qsParm[configRollUpColumnName]; // used for external items, column's value gets passed.
            else {
                ratedItem.rollUp = "None";
                alert("RollUp Column configuration is not defined correctly.");
            }
        }
    }
    else if (qsParm["averageRating"] != null && qsParm["totalRatings"] != null) {
        ratedItem = RatedItem.GetInstance(parentConfiguration, webPartId, "dummyTitle", window.location.href, qsParm["averageRating"], qsParm["totalRatings"]);
        document.getElementById(webPartId).innerHTML = "<div><b>AverageRating and TotalRatings consumed from QueryString</b></div></br>";
        ratedItem.controlPrefix = _ratingConfigCount + _id_del + webPartId;
    }
    else {
        ratedItem = RatedItem.GetInstance(parentConfiguration, webPartId, "dummyTitle", "dummyUrl", 3.5, 88);
        document.getElementById(webPartId).innerHTML = "<div><b>Avg. and Total Dummy Values</b></div></br>";
        ratedItem.controlPrefix = _ratingConfigCount + _id_del + webPartId;
    }

    config.ratedItems.AddItem(ratedItem);
    config.ratings = ratings;


    hideDisplayUsefullness(providerWebPartId, contentSourceId, configKey);


    var averageRoundedRating = computeRoundedAverageRating(ratedItem.averageRating);

    if (skinType == "Combined") {
        var divElement = document.createElement("DIV");
        divElement.id = ratedItem.controlPrefix;
        divElement.innerHTML = tokenReplace(_configTable[configKey].ratingSkinHtml
                                    , _totalRatingsToken, ratedItem.totalRatings
                                    , _averageRoundedRatingsToken, averageRoundedRating
                                    , _averageRatingsToken, ratedItem.averageRating
                                    , _controlIdToken, ratedItem.controlPrefix
                                    , _configKeyToken, ratedItem.controlPrefix.split(_id_del)[0]);
        wepPart.appendChild(divElement);
        renderRatingsImagesById(ratedItem.controlPrefix + _idAddOnImageRatings, averageRoundedRating * 2, "rated");
        applyControlMasking(ratedItem.controlPrefix);

        divElement = document.createElement("DIV");
        divElement.id = 'divcommentBaked' + ratedItem.controlPrefix;
        divElement.innerHTML = tokenReplace(_configTable[configKey].commentSkinHtml
                                    , _totalRatingsToken, ratedItem.totalRatings
                                    , _averageRoundedRatingsToken, averageRoundedRating
                                    , _averageRatingsToken, ratedItem.averageRating
                                    , _controlIdToken, 'divcommentBaked' + ratedItem.controlPrefix
                                    , _configKeyToken, ('divcommentBaked' + ratedItem.controlPrefix).split(_id_del)[0]);
        wepPart.appendChild(divElement);
        applyControlMasking('divcommentBaked' + ratedItem.controlPrefix);
        _configTable[configKey].controls = "Combined";
    }
    else if (skinType == "Rating") {
        var divElement = document.createElement("DIV");
        divElement.id = ratedItem.controlPrefix;
        divElement.innerHTML = tokenReplace(_configTable[configKey].ratingSkinHtml
                                    , _totalRatingsToken, ratedItem.totalRatings
                                    , _averageRoundedRatingsToken, averageRoundedRating
                                    , _averageRatingsToken, ratedItem.averageRating
                                    , _controlIdToken, ratedItem.controlPrefix
                                    , _configKeyToken, ratedItem.controlPrefix.split(_id_del)[0]);
        wepPart.appendChild(divElement);
        renderRatingsImagesById(ratedItem.controlPrefix + _idAddOnImageRatings, averageRoundedRating * 2, "rated");
        applyControlMasking(ratedItem.controlPrefix);
        _configTable[configKey].controls = "Rating";
    }
    else {
        var divElement = document.createElement("DIV");
        ratedItem.controlPrefix = 'divcomment' + ratedItem.controlPrefix;
        divElement.id = ratedItem.controlPrefix;
        divElement.innerHTML += tokenReplace(_configTable[configKey].commentSkinHtml
                                    , _totalRatingsToken, ratedItem.totalRatings
                                    , _averageRoundedRatingsToken, averageRoundedRating
                                    , _averageRatingsToken, ratedItem.averageRating
                                    , _controlIdToken, ratedItem.controlPrefix
                                    , _configKeyToken, ratedItem.controlPrefix.split(_id_del)[0]);
        wepPart.appendChild(divElement);
        applyControlMasking(ratedItem.controlPrefix);
        _configTable[configKey].controls = "Comment";
    }
    _ratingConfigCount++;
}

function tokenReplace(html) {
    var controlHtml = html;
    for (var i = 1; i < arguments.length - 1; i += 2) {
        controlHtml = replaceString(arguments[i], arguments[i + 1], controlHtml);
    }
    return controlHtml;
}

function replaceString(oldString, newString, str) {
    var reg = new RegExp('(' + oldString + ')', 'gi');
    return str.replace(reg, newString);
}
//debugger;
function AddRatingsControl(contentSourceId, itemId, title, url) {
    if (typeof (_itemPageRegister[_ratingConfigCount]) == 'undefined') {
        _itemPageRegister[_ratingConfigCount] = [];
        _items = {};
    }
    _itemPageRegister[_ratingConfigCount].push(itemId);

    var cid = _ratingConfigCount + _id_del + itemId;
    _items[itemId] = { itemUrl: url, itemTitle: title };
    document.write('<div id=' + contentSourceId + _cs_del + cid + '></div>');
}

function AddRatingsControl(contentSourceId, itemId, title, url, rollUp) {
    if (typeof (_itemPageRegister[_ratingConfigCount]) == 'undefined') {
        _itemPageRegister[_ratingConfigCount] = [];
        _items = {};
    }
    _itemPageRegister[_ratingConfigCount].push(itemId);

    var cid = _ratingConfigCount + _id_del + itemId;
    _items[itemId] = { itemUrl: url, itemTitle: title, itemRollUp: rollUp };
    document.write('<div id=' + contentSourceId + _cs_del + cid + '></div>');
}


function applyControlMasking(controlId, isConfigPage, configKey) {
    var comp;
    if (isConfigPage == null)
        comp = controlId.split(_id_del);
    else if (isConfigPage)
        comp = controlId.split(_cs_del);
    if (configKey == null)
        configKey = comp[0];

    applyMasking(_idPrefixEnableUsefulness + controlId, "EnableUsefulness", configKey);
    applyMasking(_idPrefixRatingDisplayAverageRating + controlId, "RatingDisplayAverageRating", configKey);
    applyMasking(_idPrefixRatingDisplayTotalRatings + controlId, "RatingDisplayTotalRatings", configKey);
    applyMasking(_idPrefixRatingDisplayMyRating + controlId, "RatingDisplayMyRating", configKey);
    applyMasking(_idPrefixRatingDisplayPopupCommentControl + controlId, "RatingDisplayPopupCommentControl", configKey);
    applyMasking(_idPrefixCommentDisplayTotalRatings + controlId, "CommentDisplayTotalRatings", configKey);
    applyMasking(_idPrefixCommentDisplayAverageRating + controlId, "CommentDisplayAverageRating", configKey);
    applyMasking(_idPrefixCommentDisplayMyRating + controlId, "CommentDisplayMyRating", configKey);
}

function applyMasking(controlId, configProperty, configKey) {
    if (document.getElementById(controlId) != null)
        if (!_configTable[configKey][configProperty])
        document.getElementById(controlId).style.display = "none";
    else
        document.getElementById(controlId).style.display = "inline";
}

/******************************************************************
End core UI rendering functions
******************************************************************/


/******************************************************************************
//Core rating objects
******************************************************************************/
function addMethod(object, name, fn) {
    var old = object[name];
    object[name] = function() {
        if (fn.length == arguments.length)
            return fn.apply(this, arguments);
        else if (typeof old == 'function')
            return old.apply(this, arguments);
    };
}

Serializable = function() { }
Serializable.prototype.Type = function() {
    re = /\/\/\[Type:\w*/;
    var arr = this.constructor.toString().match(re);
    return arr[0].split(":")[1];
}
Serializable.prototype.SerializableProperties = function() {
    var re = /\/\/\[Serializable:\[(.*?)\]/;
    var arr = this.constructor.toString().match(re);
    return eval(arr[0].split(":")[1]);
}

Serializer = function() { }
Serializer.prototype.Deserialize = function(o, node) {
    var p = o.SerializableProperties();
    for (var i = 0; i < p.length; i++) {
        o[p[i]] = this.Deserialize2(o[p[i]], node.selectSingleNode(p[i]));
    }
    return o;
}
Serializer.prototype.Deserialize2 = function(prop, node) {
    switch (typeof (prop)) {
        case "string":
            return node.text;
        case "number":
            return parseNumber(node.text);
        case "boolean":
            return node.text == 'false' ? false : true;
        case "object":
            //Array
            if (prop.constructor.toString().indexOf("function Array()") > -1) {
                for (var i = 0; i < node.childNodes.length; i++) {
                    var mem = InitValue(prop.Type); //TODO
                    mem = this.Deserialize(mem, node.childNodes[i]);
                    prop.push(mem);
                }
                return prop;
            }
            else if (prop.constructor.toString().indexOf("function Date()") > -1) {
                return new Date(parseNumber(node.text))
            }
            else {
                //object
                return this.Deserialize(prop, node)
            }
    }
}
Serializer.prototype.Serialize = function(o, name) {
    var xml = "<" + name + ">";
    switch (typeof (o)) {
        case "string":
            xml += "<![CDATA[" + o + "]]>";
            break;
        case "number":
        case "boolean":
            xml += o;
            break;
        case "object":
            //Array
            if (o.constructor.toString().indexOf("function Array()") > -1) {
                for (var i = 0; i < o.length; i++) {
                    if (typeof (o[i]) == 'object') {
                        xml += this.Serialize(o[i], o[i].Type());
                    }
                    else {
                        xml += this.Serialize(o[i], typeof (o[i]));
                    }
                }
            }
            else if (o.constructor.toString().indexOf("function Date()") > -1) {
                xml += o.getTime();
        }
            else //object
            {
                var p = o.SerializableProperties();
                for (var j = 0; j < p.length; j++) {
                    xml += this.Serialize(o[p[j]], p[j]);
                }
            }
    }
    xml += "</" + name + ">";
    return xml;
}
var s = new Serializer();
function parseNumber(n) {
    if (n.toString().indexOf("."))
        return parseFloat(n);
    else
        return parseInt(n);
}
function InitValue(t) {
    switch (t) {
        case "string":
            return '';
        case "number":
            return 0;
        case "boolean":
            return false;
        default:
            return eval("new " + t + "()");
    }
}

//== base class ==
function Service() {
    this.xmlhttp = null;
    this.xmldoc = null;
    this.serviceUri = '';
    this.error = new RatingServiceError();
    this.OnUpdate = [];
    this.Load = function() {
        s.Deserialize(this, this.xmldoc);
    }
    this.getResponse = function() {
        if (this.xmlhttp.readyState == 4) {
            this.xmldoc = this.xmlhttp.responseXML.documentElement;
            this.Load();
            for (var i = 0; i < this.OnUpdate.length; i++)
                this.OnUpdate[i](this);
        }
    };
}
Service.FirstRequest = true;
Service.prototype = new Serializable;
Service.prototype.constructor = Service;
Service.prototype.Call = function(verb, msg, async) {
    if (verb.toLowerCase() != 'get') {
        if (Service.FirstRequest) {
            UpdateFormDigest(_ratingsWebRelativeURL, 0);
            Service.FirstRequest = false;
        }
        else
            UpdateFormDigest(_ratingsWebRelativeURL, 1440000);

        //Adds new form digest to body of the message of XMLHttp object
        msg += "&__REQUESTDIGEST=" + document.forms[0]["__REQUESTDIGEST"].value;

    }
    if (window.XMLHttpRequest) //IE7
    {
        this.xmlhttp = new XMLHttpRequest();
    }
    else //IE5, IE6
    {
        var ua = navigator.userAgent.toLowerCase();
        if (ua.indexOf('msie 5') == -1)
            this.xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
        else
            this.xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }


    if (async) {
        var r = this.closure(this);
        this.xmlhttp.open(verb, this.serviceUri, async);
        this.xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        this.xmlhttp.onreadystatechange = r;
        this.xmlhttp.send(msg);
    }
    else {
        this.xmlhttp.open(verb, this.serviceUri, async);
        this.xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        this.xmlhttp.send(msg);
        this.xmldoc = this.xmlhttp.responseXML.documentElement;
        if (this.xmlhttp.status != 200)
            if (this.xmldoc != null)
            s.Deserialize(this.error, this.xmldoc);
        else {
            this.error.number = 4005;
            //alert('You must be signed in to rate this item.');
        }
    }
}
Service.prototype.closure = function(ob) {
    return function() { ob.getResponse(); }
}
Service.prototype.Xml = function() {
    return s.Serialize(this, this.Type());
}
//== end base class ==

function RatingServiceError() {
    //[Type:RatingServiceError]
    //[Serializable:["number", "message", "url"]]
    this.number = 0;
    this.message = '';
    this.url = '';
}
RatingServiceError.prototype = new Serializable;
RatingServiceError.prototype.constructor = RatingServiceError;

function Config() {
    //[Type:Config]
    //[Serializable:["EnableRerating", "EnableUsefulness", "RatingDisplayTotalRatings", "RatingDisplayAverageRating", "RatingDisplayMyRating", "RatingDisplayPopupCommentControl", "CommentDisplayTotalRatings", "CommentDisplayAverageRating", "CommentDisplayMyRating", "RaterSkin", "CommentSkin", "Namespace", "isDefault", "ratingSkinHtml", "commentSkinHtml", "webId", "RollUpColumnName", "EnableRollUp"]]
    this.EnableRerating = false;
    this.EnableUsefulness = false;
    this.RatingDisplayTotalRatings = false;
    this.RatingDisplayAverageRating = false;
    this.RatingDisplayMyRating = false;
    this.RatingDisplayPopupCommentControl = false;
    this.CommentDisplayTotalRatings = false;
    this.CommentDisplayAverageRating = false
    this.CommentDisplayMyRating = false;
    this.RaterSkin = '';
    this.CommentSkin = '';
    this.Namespace = '';
    this.isDefault = false;
    this.ratingSkinHtml = '';
    this.commentSkinHtml = '';
    this.webId = '';
    this.RollUpColumnName = '';
    this.EnableRollUp = false;

    this.ratedItems = new RatedItemCollection();
    this.ratings = new RatingCollection();
    this.configId;
}
Config.prototype = new Service;
Config.prototype.constructor = Config;
Config.prototype.Update = function(async) {
    this.serviceUri = _servicePrefix + "/Config/?url=" + encodeURIComponent(this.Namespace);
    var msg = "xml=" + encodeURIComponent(this.Xml());
    this.Call("POST", msg, async);
    if (this.error.number > 0) return;
    if (!async) s.Deserialize(this, this.xmldoc);
}
Config.prototype.Fetch = function(configurationId, isListId, async) {
    this.Namespace = configurationId;
    this.serviceUri = _servicePrefix + "/Config/" + encodeURIComponent(configurationId) + "/?isListId=" + isListId;
    this.Call("Get", "", async);
    if (this.error.number > 0) return;
    if (!async) s.Deserialize(this, this.xmldoc);
}
addMethod(Config, "GetInstance", function(node) {
    var o = new Config();
    o.xmldoc = node;
    s.Deserialize(o, o.xmldoc);
    return o;
});
addMethod(Config, "GetInstance", function() {
    var o = new Config();
    return o;
});
addMethod(Config, "GetInstance", function(configurationName, isList) {
    var o = new Config();
    o.Fetch(configurationName, isList, false);
    return o;
});

function Skin() {
    //[Type:Skin]
    //[Serializable:["html"]]
    this.html = '';
    this.name = '';
    this.skinType = '';
}
Skin.prototype = new Service();
Skin.prototype.constructor = Skin;
Skin.prototype.Fetch = function(async) {
    this.serviceUri = _servicePrefix + "/skins/" + this.skinType + "/" + encodeURIComponent(this.name);
    this.Call("Get", "", false);
    if (this.error.number > 0) return;
    if (!async) s.Deserialize(this, this.xmldoc);
}
addMethod(Skin, "GetInstance", function(skinName, skinType) {
    var o = new Skin();
    o.name = skinName;
    o.skinType = skinType;
    o.Fetch(false);
    return o;
});


function RatedItem() {
    //[Type:RatedItem]
    //[Serializable:["contentSourceId", "itemId", "title", "url", "averageRating", "totalRatings", "rollUp"]]
    this.contentSourceId = '';
    this.itemId = '';
    this.title = '';
    this.url = '';
    this.averageRating = 0;
    this.totalRatings = 0;
    this.rollUp = '';
    this.controlPrefix = '';
}
RatedItem.prototype = new Service;
RatedItem.prototype.constructor = RatedItem;
RatedItem.prototype.Update = function(async) {
    this.serviceUri = _servicePrefix + "/rateditems/" + encodeURIComponent(this.contentSourceId) + "/" + this.itemId;
    var msg = "xml=" + encodeURIComponent(this.Xml());
    this.Call("POST", msg, false);
    if (this.error.number > 0) return;
    if (!async) this.Load();
}
RatedItem.prototype.Fetch = function(async) {
    this.serviceUri = _servicePrefix + "/rateditems/" + encodeURIComponent(this.contentSourceId) + "/" + this.itemId;
    this.error.number = 0;
    this.Call("GET", "", async);
    if (this.error.number > 0) return;
    if (!async) this.Load();
}
addMethod(RatedItem, "GetInstance", function(node) {
    var o = new RatedItem();
    o.xmldoc = node;
    o.Load();
    return o;
});
addMethod(RatedItem, "GetInstance", function(contentSourceId, itemId, title, url, averageRating, totalRatings) {
    var o = new RatedItem();
    o.contentSourceId = contentSourceId
    o.itemId = itemId;
    o.title = title;
    o.url = url;
    o.averageRating = averageRating;
    o.totalRatings = totalRatings;
    return o;
});
addMethod(RatedItem, "GetInstance", function(contentSourceId, itemId, title, url, averageRating, totalRatings, rollUp) {
    var o = new RatedItem();
    o.contentSourceId = contentSourceId
    o.itemId = itemId;
    o.title = title;
    o.url = url;
    o.averageRating = averageRating;
    o.totalRatings = totalRatings;
    o.rollUp = rollUp;
    return o;
});
addMethod(RatedItem, "GetInstance", function(contentSourceId, itemId) {
    var o = new RatedItem();
    o.contentSourceId = contentSourceId;
    o.itemId = itemId
    o.Fetch(false);
    return o;
});
addMethod(RatedItem, "GetInstance", function(contentSourceId, itemId, callback) {
    var o = new RatedItem();
    o.contentSourceId = contentSourceId;
    o.itemId = itemId
    o.OnUpdate.push(callback);
    o.Fetch(true);
    return o;
});

function Rating() {
    //[Type:Rating]
    //[Serializable:["contentSourceId", "itemId", "ratingid", "rating", "comment", "positiveevals", "totalevals", "totalcomments","createdDate", "userAccount"]]
    this.contentSourceId = '';
    this.itemId = '';
    this.ratingid = 0;
    this.rating = 0;
    this.comment = '';
    this.positiveevals = 0;
    this.totalevals = 0;
    this.totalcomments = 0;
    this.createdDate = new Date();
    this.userAccount = new UserAccount();
}
Rating.prototype = new Service;
Rating.prototype.constructor = Rating;
Rating.prototype.Update = function(async) {
    this.serviceUri = _servicePrefix + "/rateditems/" + encodeURIComponent(this.contentSourceId) + "/" + this.itemId + "/user";
    var msg = "xml=" + encodeURIComponent(this.Xml());
    this.Call("POST", msg, false);
    if (this.error.number > 0){return false;}
    if (!async) this.Load();
}
Rating.prototype.Fetch = function(async) {
    this.serviceUri = _servicePrefix + "/rateditems/" + encodeURIComponent(this.contentSourceId) + "/" + this.itemId + "/user";
    this.Call("GET", "", async);
    if (this.error.number > 0) return;
    if (!async) this.Load();
}
Rating.prototype.AddEval = function(async, val) {
    this.serviceUri = _servicePrefix + "/rateditems/" + encodeURIComponent(this.contentSourceId) + "/" + this.itemId + "/" + this.ratingid + "/eval/" + val.toString();
    var msg = "xml=" + encodeURIComponent("<RatingEval>" + val + "</RatingEval>");
    this.Call("POST", msg, false);
    if (this.error.number > 0) return;
    if (!async) this.Load();
}
addMethod(Rating, "GetInstance", function(node) {
    var o = new Rating();
    o.xmldoc = node;
    s.Deserialize(o, o.xmldoc);
});
addMethod(Rating, "GetInstance", function(contentSourceId, itemId, ratingid, rating, comment, positiveevals, totalevals, totalcomments, accountId, lobUserId, displayName, jobRole) {
    var o = new Rating();
    o.contentSourceId = contentSourceId
    o.itemId = itemId;
    o.ratingid = ratingid;
    o.rating = rating;
    o.comment = comment;
    o.positiveevals = positiveevals;
    o.totalevals = totalevals;
    o.totalcomments = totalcomments;
    o.userAccount = UserAccount.GetInstance(accountId, lobUserId, displayName, jobRole);
    return o;
});
addMethod(Rating, "GetInstance", function(contentSourceId, itemId) {
    var o = new Rating();
    o.contentSourceId = contentSourceId;
    o.itemId = itemId
    o.Fetch(false);
    return o;
});
addMethod(Rating, "GetInstance", function(contentSourceId, itemId, callback) {
    var o = new Rating();
    o.contentSourceId = contentSourceId;
    o.itemId = itemId
    o.OnUpdate.push(callback);
    o.Fetch(true);
    return o;
});
addMethod(Rating, "GetInstance", function(contentSourceId, itemId, ratingid, rating, comment) {
    var o = new Rating();
    o.contentSourceId = contentSourceId
    o.itemId = itemId;
    o.ratingid = ratingid;
    o.rating = rating;
    o.comment = comment;
    o.userAccount = UserAccount.GetInstance(0, '', '', '');
    return o;
});

function UserAccount() {
    //[Type:UserAccount]
    //[Serializable:["accountId", "lobUserId", "displayName", "jobRole"]]
    this.accountId = 0;
    this.lobUserId = '';
    this.displayName = '';
    this.jobRole = '';
}
UserAccount.prototype = new Service;
UserAccount.prototype.constructor = UserAccount;
addMethod(UserAccount, "GetInstance", function(node) {
    var o = new UserAccount();
    o.xmldoc = node;
    s.Deserialize(o, o.xmldoc);
    return o;
});
addMethod(UserAccount, "GetInstance", function(accountId, lobUserId, displayName, jobRole) {
    var o = new UserAccount();
    o.accountId = accountId;
    o.lobUserId = lobUserId;
    o.displayName = displayName;
    o.jobRole = jobRole;
    return o;
});

function RatedItemCollection() {
    //[Type:RatedItemCollection]
    //[Serializable:["ratedItems"]]
    this.ratedItems = new Array();
    this.ratedItems.Type = "RatedItem";
    this.contentSourceId = '';
    this.idList = '';
    this.ratedItemsHT = {};
    this.byRollUp = false;
    this.rollUp = "";

    this.Load = function() {
        s.Deserialize(this, this.xmldoc);
        for (var i = 0; i < this.ratedItems.length; i++) {
            this.ratedItemsHT[this.ratedItems[i].itemId.toString()] = this.ratedItems[i];
        }
    }
}
RatedItemCollection.prototype = new Service;
RatedItemCollection.prototype.constructor = RatedItemCollection;
RatedItemCollection.prototype.Fetch = function(async) {
    if (this.byRollUp) {
        this.serviceUri = _servicePrefix + "/rateditems/" + encodeURIComponent(this.contentSourceId) + "/?object=rateditem&rollUp=" + this.rollUp;
    }
    else {
        this.serviceUri = _servicePrefix + "/rateditems/" + encodeURIComponent(this.contentSourceId) + "/?object=rateditem&itemids=" + this.idList;
    }
    this.Call("GET", "", async);
    if (this.error.number > 0) return;
    if (!async) this.Load();
}
RatedItemCollection.prototype.AddItemId = function(id) {
    if (this.idList != 0)
        this.idList += ',' + id;
    else
        this.idList = id;
}
RatedItemCollection.prototype.AddItem = function(ratedItem) {
    var l = this.ratedItems.length;
    this.ratedItems[l] = ratedItem;
    this.ratedItemsHT[this.ratedItems[l].itemId.toString()] = this.ratedItems[l];
}
RatedItemCollection.prototype.GetItem = function(itemId) {
    return this.ratedItemsHT[itemId.toString()];
}

addMethod(RatedItemCollection, "GetInstance", function(contentSourceId, idList, byRollUp, rollUp) {
    var o = new RatedItemCollection();
    o.contentSourceId = contentSourceId;
    if (byRollUp)
        o.rollUp = rollUp;
    else
        o.idList = idList;
    o.Fetch(false);
    return o;
});
addMethod(RatedItemCollection, "GetInstance", function(contentSourceId, idList, byRollUp, rollUp, callback) {
    var o = new RatedItemCollection();
    o.contentSourceId = contentSourceId;
    if (byRollUp)
        o.rollUp = rollUp;
    else
        o.idList = idList;
    o.OnUpdate.push(callback);
    o.Fetch(true);
    return o;
});


function RatingCollection() {
    //[Type:RatingCollection]
    //[Serializable:["ratings"]]
    this.ratings = [];
    this.ratings.Type = "Rating";
    this.contentSourceId = '';
    this.idList = '';
    this.ratingsHT = {};
    this.fetched = false;
    this.forUser = true;

    this.Load = function() {
        s.Deserialize(this, this.xmldoc);
        if (this.forUser) {
            for (var i = 0; i < this.ratings.length; i++) {
                this.ratingsHT[this.ratings[i].itemId] = this.ratings[i];
            }
        }
        else {
            for (var i = 0; i < this.ratings.length; i++) {
                this.ratingsHT[this.ratings[i].ratingid.toString()] = this.ratings[i];
            }
        }
        this.fetched = true;
    }
}
RatingCollection.prototype = new Service;
RatingCollection.prototype.constructor = RatingCollection;
RatingCollection.prototype.FetchAllForCurrentUser = function(async) {
    this.serviceUri = _servicePrefix + "/rateditems/" + encodeURIComponent(this.contentSourceId) + "/?object=rating&itemids=" + this.idList;
    this.Call("GET", "", async);
    if (this.error.number > 0) return;
    if (!async) this.Load();
}
RatingCollection.prototype.FetchAllForItem = function(async) {
    this.serviceUri = _servicePrefix + "/rateditems/" + encodeURIComponent(this.contentSourceId) + "/" + this.idList + "/";
    this.Call("GET", "", async);
    if (this.error.number > 0) return;
    if (!async) this.Load();
}
RatingCollection.prototype.AddItemId = function(id) {
    if (this.idList != 0)
        this.idList += ',' + id;
    else
        this.idList = id;
}
RatingCollection.prototype.AddRating = function(rating) {
    var l = this.ratings.length;
    this.ratings[l] = rating;
    if (this.forUser)
        this.ratingsHT[this.ratings[l].itemId] = this.ratings[l];
    else
        this.ratingsHT[this.ratings[l].ratingid.toString()] = this.ratings[l];
}
RatingCollection.prototype.GetRating = function(id) {
    if (!this.fetched)
        if (this.forUser)
        this.FetchAllForCurrentUser(false);
    else
        this.FetchAllForItem(false);
    return this.ratingsHT[id];
}
addMethod(RatingCollection, "GetInstance", function(contentSourceId, idList, forUser) {
    var o = new RatingCollection();
    o.contentSourceId = contentSourceId;
    o.idList = idList;
    o.forUser = forUser;
    if (forUser)
        o.FetchAllForCurrentUser(false);
    else
        o.FetchAllForItem(false);

    return o;
});
addMethod(RatingCollection, "GetInstance", function(contentSourceId, idList, forUser, callback) {
    var o = new RatingCollection();
    o.contentSourceId = contentSourceId;
    o.idList = idList;
    o.forUser = forUser;
    o.OnUpdate.push(callback);
    if (forUser)
        o.FetchAllForCurrentUser(true);
    else
        o.FetchAllForItem(true);

    return o;
});
addMethod(RatingCollection, "GetInstance", function(xml, forUser) {
    var o = new RatingCollection();
    o.forUser = forUser;
    var doc = new ActiveXObject("MSXML2.DOMDocument");
    doc.loadXML(xml);
    o.xmldoc = doc.documentElement
    o.Load();
    return o;
});

/******************************************************************************
End Core rating objects
******************************************************************************/

// =========== Common ===================================

function sortDropDownList(id) {
    var obj = document.getElementById(id);
    var values = new Array();
    var hashtable = new Object();
    var selectedValue = null;

    for (var i = 0; i < obj.options.length; i++) {
        if (obj.options[i].selected)
            selectedValue = obj.options[i].value;
        values.push(obj.options[i].innerHTML);
        hashtable[obj.options[i].innerHTML] = obj.options[i].value;
    }

    values = values.sort();
    for (var j = 0; j < values.length; j++) {
        obj.options[j].innerHTML = values[j];
        obj.options[j].value = hashtable[values[j]];
        if (values[j] == selectedValue)
            obj.options[j].selected = true;
    }
}

function uiGetAbsoluteX(eltIn) {
    if (eltIn.offsetParent == null)
        return eltIn.offsetLeft;
    else
        return eltIn.offsetLeft + uiGetAbsoluteX(eltIn.offsetParent);
}

function uiGetAbsoluteY(eltIn) {
    if (eltIn.offsetParent == null)
        return eltIn.offsetTop;
    else
        return eltIn.offsetTop + uiGetAbsoluteY(eltIn.offsetParent);
}

function addOption(selectbox, text, value) {
    var optn = document.createElement("OPTION");
    optn.text = text;
    optn.value = value;
    selectbox.options.add(optn);
}

function removeSelectedOptions(selectbox) {
    var i;
    for (i = selectbox.options.length - 1; i >= 0; i--) {
        if (selectbox.options[i].selected)
            selectbox.remove(i);
    }
}

function XmlXsltTransform(xmlString, xsltString) {
    try {
        xmlString = decodeURIComponent(xmlString);
    }
    catch (e) { }
    xsltString = decodeURIComponent(xsltString);

    var xmlDoc = new ActiveXObject("MSXML2.DOMDocument");
    xmlDoc.loadXML(xmlString);
    var xsltDoc = new ActiveXObject("MSXML2.DOMDocument");
    xsltDoc.loadXML(xsltString);

    var transform = null
    try {
        transform = xmlDoc.transformNode(xsltDoc);
    }
    catch (e) {
        return e.description;
    }
    return transform;
}

function AddStyleSheetReference(styleSheetHref) {
    var ns = document.createElement('link');
    ns.setAttribute('type', 'text/css');
    ns.setAttribute('id', 'RatingCss');
    ns.setAttribute('rel', 'stylesheet');
    document.getElementsByTagName('head')[0].appendChild(ns);
    document.getElementById('RatingCss').href = styleSheetHref;
}

var qsParm = null;
function computeQueryString() {
    qsParm = new Array();
    var query = window.location.search.substring(1);
    var parms = query.split('&');
    for (var i = 0; i < parms.length; i++) {
        var pos = parms[i].indexOf('=');
        if (pos > 0) {
            var key = parms[i].substring(0, pos);
            var val = parms[i].substring(pos + 1);
            qsParm[key] = URLDecode(val);
        }
    }
}

function applyConfigOnRatingControl(ratedItem) {
    var aveRating = computeRoundedAverageRating(ratedItem.averageRating);
    renderRatingsImagesById(ratedItem.controlPrefix + _idAddOnImageRatings, aveRating * 2, "rated");
    applyControlMasking(ratedItem.controlPrefix);
}

function LowerCaseFirstCharacter(mystring) {
    return mystring.substring(0, 1).toLowerCase() + mystring.substring(1, mystring.length);
}
