
if ( ! window.JSKitLib) JSKitLib = {};

JSKitLib.map = function(f, arr) {
	if(arr) for(var i = 0; i < arr.length; i++) f(arr[i], i, arr);
}

JSKitLib.isChildNodeOf = function(parent, child) {

  if (parent === child) 
    return false

  while (child && child !== parent) {
    child = child.parentNode;
  }

  return child === parent;
    
}

JSKitLib.addStyle = function(element, style) {
  if (typeof element.style.cssText != "undefined") {
    element.style.cssText = style;
  } else {
    element.setAttribute("style", style);
  }
}

// rounds number to x decimal places
JSKitLib.round = function(number, x) {
    x = (!x ? 2 : x);
    return Math.round(number*Math.pow(10,x))/Math.pow(10,x);
}

JSKitLib.zeroPad = function(number, x) {
  number = JSKitLib.round(number, x);
  var text = new String(number);
  var matches = text.match(/(\d*)(\.(\d*))?/) || [];
  var decimal = matches[3] || '';
  if (!decimal) {
    text += '.';
  }
  var count = x - decimal.length;
  for (var i=0; i<count; i++) {
    text += '0';
  }
  return text;
}

JSKitLib.getElementsByClass = function(node, searchClass, tag) {
    var classElements = [];
    node = node || document;
    tag = tag || '*';
    var tagElements = node.getElementsByTagName(tag);
    var regex = new RegExp("(^|\\s)" + searchClass + "(\\s|$)");
    for (var i=0, j=0; i < tagElements.length; i++) {
      if (regex.test(tagElements[i].className)) {
        classElements[j] = tagElements[i];
        j++;
      }
    }
    return classElements;
};

var JSKitGlobal = function() {

  this._appAvailable = {};
  this._appObjects = {};  // Specific objects of an application type 
  this._appObjectActions = {}; // app.object.actions

  this._isAppAvailable = function(app) {
    return (this._appAvailable[app]) ? true : false;
  }
    
  this.isRatingsAppAvailable = function() {
    return this._isAppAvailable('ratings');
  }

  this.isCommentsAppAvailable = function() {
    return this._isAppAvailable('comments');
  }

  this._setAppAvailable = function(app) {
    this._appAvailable[app] = true;
    /* index this app */
    this.indexAppObjects(app);
    /* execute any queued actions */
    this.executeAppObjectActions(app);
  }

  this.setRatingsAppAvailable = function() {
    this._setAppAvailable('ratings');
  }
  this.setCommentsAppAvailable = function() {
    this._setAppAvailable('comments');
  }

  this.indexAppObjects = function(app) {

    if (app == 'ratings') {
      var appArray = $JRA;
    } else if (app == 'comments') {
      var appArray = $JCA;
    } else {
      alert('Attempt to index invalid app type');
      return;
    }

    for (var i=0; i < appArray.length; i++) {
      // Check that it's not standalone
      if (appArray[i].isStandalone()) {
        continue;
      }
      var uniq = appArray[i].uniq;
      if ( ! this._appObjects[uniq] ) {
        this._appObjects[uniq] = {};
      }
      if ( ! this._appObjects[uniq][app]) {
        this._appObjects[uniq][app] = [];
      }
      this._appObjects[uniq][app].push(appArray[i]);
    }
  }

  this.executeAppObjectActions = function(app) {
    if (this._appObjectActions[app]) {
      for (var i=0; i < this._appObjectActions[app].length; i++) {
        var uniq = this._appObjectActions[app][i].uniq;
        if (this._getAppObject(app, uniq)) {
          this._appObjectActions[app][i].action();
        }
      }
    }
  }

  this._getAppObject = function(app, uniq) {
    if (this._appObjects[uniq] && this._appObjects[uniq][app]) {
      return this._appObjects[uniq][app][0];  // Return only the first
    }
    return null;
  }

  this.getCommentsAppObject = function(uniq) {
    return this._getAppObject('comments', uniq);
  }

  /* Returns a Ratings Object */
  this.getRatingsAppObject = function(uniq) {
    return this._getAppObject('ratings', uniq);
  }

  this.copyRatingsAppObject = function(uniq, node) {
    if ( ! this.isRatingsAppAvailable()) {
      return;
    }

    var oldObj = this.getRatingsAppObject(uniq);
    var newObj = oldObj.clone(node, { 'view':'user', 'commentprompt':'no', 'menu':'no'  } );
    return newObj;
  }

  this._tryAppObjectAction = function(app, uniq, action) {
    if (this._isAppAvailable(app)) {
      if (this._getAppObject(app, uniq)) {
        action();
      }
    } else {

      if ( ! this._appObjectActions[app]) {
        this._appObjectActions[app] = [];
      }
      this._appObjectActions[app].push( { 'uniq' : uniq, 'action' : action } );
    }
  }

  this.tryRatingsAppObjectAction = function(uniq, action) {
    this._tryAppObjectAction('ratings', uniq, action);
  }

  this.tryCommentsAppObjectAction = function(uniq, action) {
    this._tryAppObjectAction('comments', uniq, action);
  }

}

/* Singleton-like handler */
JSKitGlobal.getInstance = function() {
  if ( ! window.JSKitGlobalInstance) {
    JSKitGlobalInstance = new JSKitGlobal();
  }
  return JSKitGlobalInstance;
}



$J$PRA = [];

function JSPRC(target) {

  if (!target) { throw('JSPRC requires target'); }

  this.jpaIndex = $J$PRA.length;
  $J$PRA.push(this);  // Should i put this in the init?
  this.target = target;

  this.config = {};

  this.cr = function(tag) { return document.createElement(tag); };

  this.path = target.getAttribute('path');

  this.config.properties = (target.getAttribute('properties') || "").split(",");
  this.config.title = target.getAttribute('title') || '';

  this.display();
}

// Extracting initialize
JSPRC.init = function() {
  var els = JSKitLib.getElementsByClass(document, 'js-kit-parametric', 'div');
  if (els && els.length) {
    for (var i=0; i < els.length; i++) {
      new JSPRC(els[i]);
    }
  }
}

JSPRC.prototype.updateComposite = function() {
  var ro = this.getRatingObjects();

  var totalRating = 0;
  var userRating = 0;
  var totalCount = 0;
  var userCount = 0;

  for (var i=0; i < ro.length; i++) {
    if(ro[i].objNum) {
	    totalRating += ro[i].objEffRating;
	    totalCount += 1;
    }

    if (ro[i].userRating) {
      userRating += ro[i].userRating;
      userCount += 1;
      this.hasUserRated = true;
    }
  }

  var totalAvg = JSKitLib.zeroPad((totalRating / (totalCount || 1)) / 2, 1);
  var userAvg = JSKitLib.zeroPad((userRating / (userCount || 1)) / 2, 1);

  totalAvg = isNaN(totalAvg) ? '0.0' : totalAvg;
  userAvg = isNaN(userAvg) ? '0.0' : userAvg;

  this.setAverageText(totalAvg);
  this.setUserAverageText(userAvg);
  this.setNumVotesText(ro.length ? ro[0].objVotes : 0);
}

JSPRC.prototype.getMetrics = function() {
  return this.config.properties;
}

// Return all the rating objects for this path
JSPRC.prototype.getRatingObjects = function() {

  var ro = [];

  if ($JSKitGlobal.isRatingsAppAvailable()) {
    for (var i=0; i < $JRA.length; i++) {
      if ($JRA[i].path == this.path) {
        ro.push($JRA[i]);
      }
    }
  } 
  return ro;

}

JSPRC.prototype.setText = function(node, text) {

  if ( ! node) return;

  while (node.hasChildNodes()) {
    node.removeChild(node.firstChild);
  }
  node.appendChild(document.createTextNode(text));
}

JSPRC.prototype.setAverageText = function(avg) {
  this.setText(this.avgText, avg);
}

JSPRC.prototype.setUserAverageText = function(avg) {
  this.setText(this.userAvgText, avg);
  var miniText;
  if (isNaN(avg) || avg <= 0) {
    miniText = 'Rate this company';
  } else {
    miniText = 'Your Rating: ' + avg;
  } 
  this.setText(this.userAvgText2, miniText);
}

JSPRC.prototype.setNumVotesText = function(votes) {
  switch(votes) {
  case 0:
	this.setText(this.numVotes, '(no votes yet)');
	break;
  case 1:
	this.setText(this.numVotes, 'by 1 voter');
	break;
  default:
	this.setText(this.numVotes, 'by ' + votes + ' voters');
	break;
  }
}


JSPRC.prototype.toggleMsg = function(msg) {
  this.ctls['js-paraMsgAvg'].style.display = 'none';
  this.ctls['js-paraMsgUserAvg'].style.display = 'none';
  this.ctls['js-paraMsgUserNew'].style.display = 'none';
  this.ctls['js-paraMsgThanks'].style.display = 'none';
  this.ctls[msg].style.display = '';
}

JSPRC.prototype.toggleView = function(view) {
  this.updateComposite();

  // toggle the stars
  var ro = this.getRatingObjects();
  for (var i=0; i < ro.length; i++) {
    ro[i].defaultView = view;  // TODO: turn into method
    ro[i].refreshRating();   
  }
  
}

JSPRC.prototype.toggleViewUser = function() {

  if(!this.hasOwnProperty('frozen')) {
	var ro = this.getRatingObjects();
	this.frozen = (ro.length && ro[0].config.freeze == "yes");
  } if(this.frozen) return;

  if (this.hasUserRated) {
    this.toggleMsg('js-paraMsgUserAvg');
  } else {
    this.toggleMsg('js-paraMsgUserNew');
  }
  this.toggleView('user');
}
JSPRC.prototype.toggleViewStar = function() {
  this.toggleMsg('js-paraMsgAvg');
  this.toggleView('star');
}

document.write('<style type="text/css">'
  + ".js-para { padding: .3em; -moz-user-select: none; }"
  + ".js-paraMsgWrap { float: left; margin-top:.3em; width: 35%; }"
  + ".js-paraMsg { text-align: center; height: 60px; }"
  + ".js-paraMsgAvgValue { font-size: 18pt; }"
  + ".js-paraMsgUserAvgValue { font-size: 18pt; }"
  + ".js-paraMsgUserNew { font-size: 1.2em; }"
  + ".js-paraMsgThanks { font-size: 13pt; padding-top:.2em}"
  + ".js-paraStarsWrap { float: right; margin-top:.3em; width: 65%; }"
  + ".js-paraStars { width: 90%; margin: 0 auto; }"
  + ".js-paraFooter { padding:.2em; padding-top:.5em; float: right; }"
  + ".js-paraPowered { text-decoration: none; font-size: .8em; color:#006d00 }"
  + "</style>"
);

JSPRC.prototype.dt 
  = '<div class="js-para">'
  + '  <div class="js-paraMsgWrap">'
  + '    <div class="js-paraMsg">'
  + '      <div class="js-paraMsgAvg">'
  + '        Average<br><span class="js-paraMsgAvgValue"></span><br><span class="js-paraMsgNumVotes"></span>'
  + '      </div>'
  + '      <div class="js-paraMsgUserAvg" style="display:none;">'
  + '        Your<br>Average<br><span class="js-paraMsgUserAvgValue"></span>'
  + '      </div>'
  + '      <div class="js-paraMsgUserNew" style="display:none;">'
  + '        Rate<br>this<br>company'
  + '      </div>'
  + '      <div class="js-paraMsgThanks" style="display:none;">'
  + '        Thank You!'
  + '      </div>'
  + '    </div>'
  + '  </div>'
  + '  <div class="js-paraStarsWrap">'
  + '    <div class="js-paraStars">'
  + '    </div>'
  + '  </div>'
  + '  <div style="clear:both;"></div>'
  + '  <div class="js-paraFooter">'
  + '    <span class="js-paraUserRating"></span>'
  + '    &nbsp;|&nbsp;<a class="js-paraPowered" href="http://js-kit.com/?tc40_wow" target="_blank">Powered&nbsp;by&nbsp;JS-Kit</a>'
  + '  </div>'
  + '  <div style="clear:both;"></div>'
  + '</div>'
  ;

JSPRC.prototype.html = function() {
	var div = this.cr("div");
	for(var text = '', i = 0; i < arguments.length; i++)
		text += arguments[i];
	div.innerHTML = text;
	var ch = div.firstChild;
	div = null;
	return ch;
}
JSPRC.prototype.gtmpl = function(t) {
	var lowercase = function(a, m) { return String(m).toLowerCase(); }
	t = t.replace(/^[^<]*(<.*>)[^>]*$/m, "$1");
	t = t.replace(/(<[\/]?[A-Z]+)/g, lowercase);
	return t;
}
JSPRC.prototype.tmpl = function(t, obj) {
	var self = this;
	t = self.gtmpl(t);
	var purify = function(text) {
		var text = String(text).replace(/^[ \s]+|[ \s]+$/, '');
		text = text.replace(/([^&<>\s]{12})([^&<>\s]{12})/g, '$1<wbr></wbr>$2');
		text = text.replace(/[ \t\r\n]+/g, ' ');
		return text;
	}
	t = t.replace(/{([A-Za-z0-9]+)}/g,function(a,m){return obj.hasOwnProperty(m)?purify(obj[m]):'{'+m+'}';});
	return t;
}
JSPRC.prototype.mapClass2Object = function(ctl, e) {
	if(e.className) {
		var arr = String(e.className).split(/[ ]+/);
		JSKitLib.map(function(el) { ctl[el] = e }, arr);
	}
	if(e.name) ctl[e.name] = e;
	try {
		var self = this;
		JSKitLib.map(function(child) {
			self.mapClass2Object(ctl, child);
		}, e.childNodes);
	} catch(e){}
	return ctl;
}

// called when a new rating loads
JSPRC.prototype.onRate = function() {
  var self = this;
  self.updateComposite();

  if (self.onRateScheduled)
    clearTimeout(self.onRateScheduled);

  self.toggleMsg('js-paraMsgThanks');
  self.onRateScheduled = setTimeout(function() {
    self.toggleMsg('js-paraMsgUserAvg');
  }, 2500);

}

JSPRC.prototype.display = function() {

  var pdiv = this.html(this.tmpl(this.dt, {}));
  pdiv.onselectstart = function() { return false; }
  var ctls = this.mapClass2Object({}, pdiv);
  this.ctls = ctls;

  var metrics = this.getMetrics();

  var stars = this.cr('div');

  for (var i=0; i < metrics.length; i++) {
    var rdiv = this.cr('div');
    rdiv.className = "js-kit-rating";
    rdiv.setAttribute('path', this.path);
    rdiv.setAttribute('title', this.config.title);
    rdiv.setAttribute('property', metrics[i]);
    rdiv.setAttribute('menu', "no");
    rdiv.setAttribute('subtext', "no");

    var wrap = this.cr('div');

    var text = this.cr('div');
    JSKitLib.addStyle(text, 'float: left; line-height: 18px; height:18px; padding-top:2px;'); 
    JSKitLib.addStyle(rdiv, 'clear: both; float: left; width: 86px; height:20px;'); 
    text.appendChild(document.createTextNode(metrics[i]));

    wrap.appendChild(rdiv);
    wrap.appendChild(text);

    stars.appendChild(wrap);
  }

  // handling mouseover for user/community view
  var self = this;

  this.target.onmouseover = function(e) {  
    // TODO: extract to lib
    if (!e) { e = window.event; }
    var relTarg = e.relatedTarget || e.fromTarget
    if (relTarg == self.target || JSKitLib.isChildNodeOf(self.target, relTarg) ) {
    } else {
      self.toggleViewUser();
    }
  };
  this.target.onmouseout = function(e) {  
    // TODO: extract to lib
    if (!e) { e = window.event; }
    var relTarg = e.relatedTarget || e.fromTarget
    if (relTarg == self.target || JSKitLib.isChildNodeOf(self.target, relTarg) ) {
    } else {
      self.toggleViewStar();
    }
  };

  //this.ctls['js-paraStars'].appendChild(stars);
  this.ctls['js-paraStars'].insertBefore(stars, this.ctls['js-paraStars'].firstChild);

  // all users average rating
  this.avgText = this.ctls['js-paraMsgAvgValue'];
  this.userAvgText = this.ctls['js-paraMsgUserAvgValue'];
  this.userAvgText2 = this.ctls['js-paraUserRating'];
  this.numVotes = this.ctls['js-paraMsgNumVotes'];

  // display
  this.target.appendChild(pdiv);

}

$JSKitGlobal = JSKitGlobal.getInstance();

JSPRC.init();

//---
if ( ! window.$JRA) {
  /* Global JS Ratings Array */
  var $JRA = [];
  var $JRH = {};

  var $JRLT = {
    yourRatingTitleCase: 'Your Rating',
    yourRating: 'Your rating',
    vote: 'vote',
    votes: 'votes',
    unrated: 'Unrated',
    rateThis: 'Rate this',
    avgRating: 'avg rating',
    poweredBy: 'Powered by',
    youHaveNotRatedYet: 'You have not rated yet',
    addACommentToYourRating: 'Add a comment to your rating',
    noVotesReceivedYet: 'No votes received yet',
    beTheFirstToRate: 'Be the first to rate!',
    ratingsDisabled: 'Ratings have been disabled',
    thankYou: 'Thank you!'
  };

  var $JRL = function(t) {
    return $JRLT[t] || t;
  };
}

JSKitLib.isPreIE7 = function() {
	if (document.body.filters && parseInt(navigator.appVersion.split("MSIE")[1]) < 7)
		return true;
}

JSKitLib.addPNG = function(node, imageURL) {
	if (JSKitLib.isPreIE7()) {
		node.runtimeStyle.filter
			= "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"
			+ imageURL + "', sizingMethod='crop')"
	} else {
		node.style.backgroundImage = 'url(' + imageURL + ')';
		node.style.backgroundRepeat = 'no-repeat';        
	}
	return node;
}

JSKitLib.preloadImg = function(imgURL) { 

  if (!JSKitLib.preloadImgList) JSKitLib.preloadImgList = {};

  if (!JSKitLib.preloadImgList[imgURL]) {
    (new Image()).src = imgURL; 
    JSKitLib.preloadImgList[imgURL] = true;
  }
};


JSKitLib.visible = function(element) {
  return element.style.display != 'none';
}

JSKitLib.show = function(element) {
  element.style.display = '';
}

JSKitLib.hide = function(element) {
  element.style.display = 'none';
}

JSKitLib.toggle = function(element) {
  (element.style.display == 'none') ? JSKitLib.show(element) :  JSKitLib.hide(element);
}

JSKitLib.addStyle = function(element, style) {
  if (typeof element.style.cssText != "undefined") {
    element.style.cssText = style;
  } else {
    element.setAttribute("style", style);
  }
}

JSKitLib.findPos = function(obj) {
    var curleft = curtop = 0;
    if (obj.offsetParent) {
        curleft = obj.offsetLeft;
        curtop = obj.offsetTop;
        while (obj = obj.offsetParent) {
            curleft += obj.offsetLeft;
            curtop += obj.offsetTop;
        }
    }
    return [curleft,curtop];
}

var JSKitGlobal = function() {

  this._appAvailable = {};
  this._appObjects = {};  // Specific objects of an application type 
  this._appObjectActions = {}; // app.object.actions

  this._isAppAvailable = function(app) {
    return (this._appAvailable[app]) ? true : false;
  }
    
  this.isRatingsAppAvailable = function() {
    return this._isAppAvailable('ratings');
  }

  this.isCommentsAppAvailable = function() {
    return this._isAppAvailable('comments');
  }

  this._setAppAvailable = function(app) {
    this._appAvailable[app] = true;
    /* index this app */
    this.indexAppObjects(app);
    /* execute any queued actions */
    this.executeAppObjectActions(app);
  }

  this.setRatingsAppAvailable = function() {
    this._setAppAvailable('ratings');
  }
  this.setCommentsAppAvailable = function() {
    this._setAppAvailable('comments');
  }

  this.indexAppObjects = function(app) {

    if (app == 'ratings') {
      var appArray = $JRA;
    } else if (app == 'comments') {
      var appArray = $JCA;
    } else {
      alert('Attempt to index invalid app type');
      return;
    }

    for (var i=0; i < appArray.length; i++) {
      // Check that it's not standalone
      if (appArray[i].isStandalone()) {
        continue;
      }
      var uniq = appArray[i].uniq;
      if ( ! this._appObjects[uniq] ) {
        this._appObjects[uniq] = {};
      }
      if ( ! this._appObjects[uniq][app]) {
        this._appObjects[uniq][app] = [];
      }
      this._appObjects[uniq][app].push(appArray[i]);
    }
  }

  this.executeAppObjectActions = function(app) {
    if (this._appObjectActions[app]) {
      for (var i=0; i < this._appObjectActions[app].length; i++) {
        var uniq = this._appObjectActions[app][i].uniq;
        if (this._getAppObject(app, uniq)) {
          this._appObjectActions[app][i].action();
        }
      }
    }
  }

  this._getAppObject = function(app, uniq) {
    if (this._appObjects[uniq] && this._appObjects[uniq][app]) {
      return this._appObjects[uniq][app][0];  // Return only the first
    }
    return null;
  }

  this.getCommentsAppObject = function(uniq) {
    return this._getAppObject('comments', uniq);
  }

  /* Returns a Ratings Object */
  this.getRatingsAppObject = function(uniq) {
    return this._getAppObject('ratings', uniq);
  }

  this.copyRatingsAppObject = function(uniq, node) {
    if ( ! this.isRatingsAppAvailable()) {
      return;
    }

    var oldObj = this.getRatingsAppObject(uniq);
    var newObj = oldObj.clone(node, { 'view':'user', 'commentprompt':'no', 'menu':'no'  } );
    return newObj;
  }

  this._tryAppObjectAction = function(app, uniq, action) {
    if (this._isAppAvailable(app)) {
      if (this._getAppObject(app, uniq)) {
        action();
      }
    } else {

      if ( ! this._appObjectActions[app]) {
        this._appObjectActions[app] = [];
      }
      this._appObjectActions[app].push( { 'uniq' : uniq, 'action' : action } );
    }
  }

  this.tryRatingsAppObjectAction = function(uniq, action) {
    this._tryAppObjectAction('ratings', uniq, action);
  }

  this.tryCommentsAppObjectAction = function(uniq, action) {
    this._tryAppObjectAction('comments', uniq, action);
  }

}

/* Singleton-like handler */
JSKitGlobal.getInstance = function() {
  if ( ! window.JSKitGlobalInstance) {
    JSKitGlobalInstance = new JSKitGlobal();
  }
  return JSKitGlobalInstance;
}

/* JS Rating Class */
function JSRC() {

  this.jraIndex = $JRA.length;
  $JRA.push(this);
  var self = this;

  this.cr  = function(tag) { return document.createElement(tag) };

  this.pathOverride = '';
  this.config = {};
  this.raterInc = 2;  // Increment ratio of rateable v. displayable
  this.scale    = 10; // Points on rating scale

  this.onRate = []; // Callbacks for post rating processing

  this.isStandalone = function() {
    return (this.config.standalone == 'yes') ? true : false;
  }

  this.starWidth       = 16;
  this.starHeight      = 15;
  this.miniStarWidth   = 9;
  this.miniStarHeight  = 9;
  this.totalWidth; //The total width of the visible widget

  var wl = window.location;

  var idName = 'js-kit-rating';

  var target = arguments.length ? arguments[0] : document.getElementById(idName);
  var options = arguments[1] || {};

  if (target) {

    this.target = target;

    // Handling user configuration settings
    this.config.path = options.path || target.getAttribute('path');
    this.config.uniq = options.uniq || target.getAttribute('uniq') || '';
    this.config.standalone = options.standalone || target.getAttribute('standalone') || 'no';
    this.config.view = options.view || target.getAttribute('view') || 'combo';
    this.config.commentprompt = options.commentprompt || target.getAttribute('commentprompt') || true;
    this.config.starcolor = options.starcolor || (target.getAttribute('starcolor')||"").toLowerCase();
    this.config.usercolor = options.usercolor || (target.getAttribute('usercolor')||"").toLowerCase();
    this.config.imageurl  = options.imageurl  || target.getAttribute('imageurl');
    this.config.imagesize = options.imagesize || (target.getAttribute('imagesize')||"");
    this.config.title = options.title || target.getAttribute('title') || '';
    this.config.notop = options.notop || target.getAttribute('notop') || '';
    this.config.permalink = options.permalink || target.getAttribute('permalink') || '';
    this.config.freeze = options.freeze || target.getAttribute('freeze') || 'no';
    this.config.menu = options.menu || target.getAttribute('menu') || 'no';
    this.config.subtext = options.subtext || target.getAttribute('subtext') || 'yes';
    this.config.property = options.property || target.getAttribute('property');

    if(this.config.imageurl && this.config.imagesize) {
	var dim = self.config.imagesize.match(/(\d+)([^\d]+(\d+))?/);
	if(dim) {
		self.starWidth = dim[1];
		self.starHeight = dim[3] || self.starWidth;
	}
    }
    this.ratingBarWidth  = this.scale / this.raterInc * this.starWidth; 
    this.ratingBarHeight = this.starHeight;

    if (this.config.path) {
        var path = String(this.config.path);
        var ar = path.match(/^https?:\/\/[^\/]+(.*)/);
        if(ar) this.pathOverride = ar[1];
        else this.pathOverride = path.replace(/^([^\/]+)/, wl.pathname + "/$1");
    }

    this.path = this.pathOverride || wl.pathname;
    this.uniq = this.config.uniq || this.path;
    if ( ! $JRH[this.uniq]) {
      $JRH[this.uniq] = [];
    }
    $JRH[this.uniq].push(this);

    this.defineIcons();
    JSKitLib.preloadImg(JSRC.WINDOW_BG_IMG);
    JSKitLib.preloadImg(JSRC.INFO_IMG);

    if (options.newRating) {
        //TODO
        this.newRating({ Sum: options.newRating.objSum, Num: options.newRating.objNum, Votes: options.newRating.objVotes }, { Sum: options.newRating.userRating});
    }

    this.myref = function() {
	if(arguments.length) return self.path;
	return encodeURIComponent(wl.protocol + "//" + wl.host
          + (self.pathOverride.length ? "/" : wl.pathname));
    }

    this.server = function(ext, data) {
      var sc = self.cr("script");
      sc.setAttribute("charset", "utf-8");
      sc.src = JSRC.URI + ext + self.pathOverride
		+ "?ref=" + self.myref() + "&" + data;
      self.target.appendChild(sc);
      return false;
    }
    if(options.autorequest) {
	var mr = this.myref('path');
	this.server('-data.js', 'p[0]=' + encodeURIComponent(mr)
		+ ((mr == this.uniq) ? ''
			: ('&u[0]=' + encodeURIComponent(this.uniq)))
		+ (this.config.property ? '&pr[0]=' + encodeURIComponent(this.config.property) : '')
		+ '&jx[0]=' + this.jraIndex);
    }
  } else {

    /* Iterate and find all rating divs */
    var els = document.getElementsByTagName('div');
    if (els && els.length) {
      $JRA.shift();
      var multiQ = '';
      var multiI = 0;
      var reqMulti = function(atext) {
        if(!atext.length) return;
	var sc = self.cr("script");
        sc.src = JSRC.URI + "-data.js?ref="
	  + encodeURIComponent(wl.protocol + "//" + wl.host + wl.pathname)
	  + atext;

        $JRA[0].target.appendChild(sc);

      }
      for (var i=0; i < els.length; i++) {
        if (els[i].className.match(/js-kit-rating/)) {
          var r = new JSRC(els[i]);
	  var mr = r.myref('path');
	  multiQ += "&p["+multiI+"]=" + encodeURIComponent(mr)
			+ ((mr == r.uniq) ? ''
			    : ("&u["+multiI+"]=" + encodeURIComponent(r.uniq)))
			+ (r.config.property ? "&pr["+multiI+"]=" + encodeURIComponent(r.config.property) : '')
			+ "&jx[" + multiI + "]=" + r.jraIndex;
	  if(multiQ.length > 700) {
		reqMulti(multiQ);
		multiQ = '';
		multiI = 0;
	  } else {
		multiI ++;
	  }
        }
      }
      reqMulti(multiQ);
      if ($JRA.length) {
        return;
      }
    }
    /* Handling for single line entry */
  }

}

/* Constants */
JSRC.DOMAIN = (window.location.protocol.substr(0, 4) != 'http' ? 'http:' : '')
		+ '//js-kit.com';
JSRC.URI = JSRC.DOMAIN + '/tc40/rating';
JSRC.BASE_STAR_URI = JSRC.DOMAIN + '/images/stars/';
JSRC.WINDOW_BG_IMG = JSRC.DOMAIN + '/images/1px90pct.png';
JSRC.INFO_IMG = JSRC.DOMAIN + '/images/i-wg.png';


JSRC.prototype.defineIcons = function() {

  var self = this;
  this.fullStar  = [];
  this.halfStar  = [];
  this.emptyStar = [];
  this.miniFullStar  = [];
  this.miniEmptyStar = [];

  var genstar = function(confColor, defColor, type) {
	var acceptedColors = { blue:1, yellow:1, gold:1, golden:1,
			green:1, violet:1, emerald:1, indigo:1, red:1, ruby:1 };
	var color = (confColor && acceptedColors[confColor])
			? confColor : defColor;
	var starURI = JSRC.BASE_STAR_URI;
	if(self.config.imageurl) {
		starURI = self.config.imageurl + '/';
		color = type;
	}
	var size = '';

	self.fullStar[type]  = starURI + color + size + '.png';
	self.halfStar[type]  = starURI + color + size + '-half.png';
	self.emptyStar[type] = starURI + size + 'gray.png';

	if ( ! self.config.imageurl) {
		self.miniFullStar[type]  = starURI + color + '-tiny.png';
		self.miniEmptyStar[type] = starURI + 'gray-tiny.png';
		self.miniStarWidth = 9;
		self.miniStarHeight = 9;
	} else {
		self.miniFullStar[type]  = self.fullStar[type];
		self.miniEmptyStar[type] = self.emptyStar[type];
		self.miniStarWidth = self.starWidth;
		self.miniStarHeight = self.starHeight;
	}

	JSKitLib.preloadImg(self.fullStar[type]);
	JSKitLib.preloadImg(self.halfStar[type]);
	JSKitLib.preloadImg(self.emptyStar[type]);
	JSKitLib.preloadImg(self.miniFullStar[type]);
	JSKitLib.preloadImg(self.miniEmptyStar[type]);

  }

  genstar(this.config.starcolor, 'ruby', 'star');
  genstar(this.config.usercolor, 'gold', 'user');
}

/* Create our global JSKit object */
$JSKitGlobal = JSKitGlobal.getInstance();

/* Init a single JSRC object */
if ( ! $JRA.length) {
  new JSRC();
  $JSKitGlobal.setRatingsAppAvailable();
}


/* CSS Stylings */
document.write('<style type="text/css">'
  + '.js-rating-labelText { padding-top: 2px; font-size: 11px; text-align: center; cursor: default }'
  + '.js-rating-splitObjectRating { margin-right: 10px; }'
  + '.js-rating-afterRating { width: 100px; font-size: 12px; text-align: center; padding: .3em;}'
  + '.js-rating-windowWrapper { border: 1px solid #999; }'
  + '.js-rating-window { border: 1px solid #ccc; padding: .3em; background-image:url(' + JSRC.WINDOW_BG_IMG + ')}'
  + '.js-rating-menuArrow { position: absolute; right: -20px; width:15px; height:15px; cursor:pointer; z-index:100; }'
  + '.js-rating-infoBox { color: black; padding: .3em; text-align:left; }'
  + '.js-rating-infoBoxStats { padding-bottom: 1em; line-height: 12pt;  }'
  + '.js-rating-infoBoxText { font-size: 9pt; }'
  + '.js-rating-infoBoxTextEm { font-size: 9pt; color: #a00; }'
  + '</style>'
)

JSRC.prototype.html = function(text) {
	var div = this.cr("div");
	div.innerHTML = text;
	var ch = div.firstChild;
	div = null;
	return ch;
}

/* Will add a callback for post rating processing */
JSRC.prototype.addOnRate = function(action) {
  this.onRate.push(action);
}

JSRC.prototype.processOnRate = function() {
  for (var i=0; i < this.onRate.length; i++) {
    this.onRate[i]();
  }
}

JSRC.prototype.display = function() {

  var self = this;

  // wrapper for our floated elements
  var wrapper = this.cr('div');
  wrapper.style.margin = '3px';
  wrapper.style.position = 'relative';
  wrapper.onselectstart = function() { return false; }

  var actionable = (this.config.freeze == "yes") ? false : true;

  if (this.config.view.match(/(combo|user)/) && this.config.freeze == "yes") {
      this.userRatingBar = this.initRating(this.objEffRating, 'star', false);
  } else {
      this.userRatingBar = this.initRating(this.userRating, 'user', actionable);
  }

  this.userRatingDiv = this.cr('div');
  this.userRatingDiv.appendChild(this.userRatingBar);

if (this.config.subtext != 'no') {
  this.textTotal = this.cr('div');
  this.textTotal.className = 'js-rating-labelText';
  this.refreshTextTotal();
}

  if (this.config.view.match(/split/)) {
    // split view : community and user ratings
    this.defaultView = 'user';

    var starRatingBar = this.initRating(this.objEffRating, 'star', false);
    var starRatingDiv = this.cr('div');
        starRatingDiv.className = 'js-rating-splitObjectRating';
        starRatingDiv.style.cssFloat = 'left';
        starRatingDiv.style.styleFloat = 'left';
        starRatingDiv.style.width = this.ratingBarWidth + 'px';
        starRatingDiv.appendChild(starRatingBar);
        starRatingDiv.appendChild(this.textTotal);

    wrapper.appendChild(starRatingDiv);

    this.userRatingDiv.style.cssFloat = 'left';
    this.userRatingDiv.style.styleFloat = 'left';
    this.userRatingDiv.style.width = this.ratingBarWidth + 'px';

if (this.config.subtext != 'no') {
    this.textRating = this.cr('div');
    this.textRating.className = 'js-rating-labelText';
    this.refreshTextRating();
    this.userRatingDiv.appendChild(this.textRating);

    this.activeText = this.textRating;
}
    this.totalWidth = this.ratingBarWidth + this.ratingBarWidth + 10;

    wrapper.appendChild(this.userRatingDiv);

  } else if (this.config.view.match(/user/)) {
    // single star set, only shows current user's rating
    this.defaultView = 'user';

    this.userRatingDiv.style.cssFloat = 'left';
    this.userRatingDiv.style.styleFloat = 'left';

if (this.config.subtext != 'no') {
    this.textRating = this.cr('div');
    this.textRating.className = 'js-rating-labelText';
    this.refreshTextRating();
    this.userRatingDiv.appendChild(this.textRating);

    this.activeText = this.textRating;
}

    this.totalWidth = this.ratingBarWidth;
    wrapper.appendChild(this.userRatingDiv);

  } else {
    // single star set, defaults to community rating
    this.defaultView = 'star';

    this.userRatingDiv.style.cssFloat = 'left';
    this.userRatingDiv.style.styleFloat = 'left'; 

if (this.config.subtext != 'no') {
    this.userRatingDiv.appendChild(this.textTotal);
    this.activeText = this.textTotal;
}

    this.totalWidth = this.ratingBarWidth;

    wrapper.appendChild(this.userRatingDiv);
  }

  // Set our total width
  wrapper.style.width = this.totalWidth + 'px';

  // Set the target width
  var targetMinWidth = this.totalWidth + 6;
  var targetWidth = this.target.style.width || targetMinWidth;
  if (parseInt(targetWidth) <= targetMinWidth) {
    this.target.style.width = targetMinWidth + 'px';
  }

  /* Rating Menu */
  if (this.config.menu != 'no') {
    var menuArrow = this.createMenuArrow();
    wrapper.appendChild(menuArrow);

    wrapper.onmouseover = function() { 
      clearTimeout(self.ratingMenuTimer);
      JSKitLib.show(menuArrow);
    }
    
    wrapper.onmouseout = function() {
      self.ratingMenuTimer = setTimeout(function() {
        self.ratingMenuTimer = null;
          JSKitLib.hide(menuArrow);
          self.hideInfoBox();
      }, 1500);
    };

  }

  if (( ! this.isStandalone()) && this.config.commentprompt != 'no') {

    var addCommentPrompt = function() {

      var afterRatingA = document.createElement('a');
      afterRatingA.appendChild(document.createTextNode($JRL('addACommentToYourRating')));
      afterRatingA.onclick = function() { 
        self.getCommentsAppObject().ShowCommentDialog(null);
        return false;
      };
      afterRatingA.href = 'javascript:void(0);';
  
      var afterRatingDiv = document.createElement('div');
      afterRatingDiv.appendChild(afterRatingA);
      afterRatingDiv.className = 'js-rating-afterRating';

      var afterRating = self.createWindow(afterRatingDiv, {header:false});
      afterRating.style.position ='absolute';
      afterRating.style.left = (self.totalWidth + 5) + 'px';
      afterRating.style.top = '-4px';
      afterRating.style.zIndex = '110'; // above menuArrow
      JSKitLib.hide(afterRating);

      self.addOnRate(function() { 
        JSKitLib.show(afterRating);
        setTimeout(function() { JSKitLib.hide(afterRating); }, 5000);
      });

  
      wrapper.appendChild(afterRating);
    }
    $JSKitGlobal.tryCommentsAppObjectAction(this.uniq, addCommentPrompt); 
  }

  // Clear our floats
  var clear = this.cr('div');
  clear.style.clear = 'left';

  var infoBox = this.cr('div');
  this.infoBox = infoBox;


  this.target.appendChild(wrapper); // stars
  this.target.appendChild(clear);   // clear

  if ( ! this.config.view.match(/split/)) {
    this.refreshRating();  
  }
}

JSRC.prototype.createMenuArrow = function() {
  var div = document.createElement('div');
  div.className = 'js-rating-menuArrow';
  JSKitLib.hide(div);
  JSKitLib.addPNG(div, JSRC.INFO_IMG);

  this.infoBoxImg = div;
  var self = this;
  div.onclick = function() { 
    self.toggleInfoBox();
  }

  return div;
}

JSRC.prototype.showInfoBox = function() {
  var infoBox = this.createInfoBox();
  this.infoBox.appendChild(infoBox);
}

JSRC.prototype.hideInfoBox = function() {
  while (this.infoBox.hasChildNodes()) {
    this.infoBox.removeChild(this.infoBox.firstChild);
  }
}

JSRC.prototype.toggleInfoBox = function() {
  if (this.infoBox.hasChildNodes()) {
    this.hideInfoBox();
  } else {
    this.showInfoBox();
  }
}

JSRC.prototype.refreshInfoBox = function() {
  if (this.infoBox.hasChildNodes()) {
    this.hideInfoBox();
    this.showInfoBox();
  }
}


JSRC.prototype.createWindow = function(content, opts) {

  if (typeof opts != 'object') opts = {};

  var wrapper = document.createElement('div');
  wrapper.className = 'js-rating-windowWrapper';

  var box = document.createElement('div');
  box.className = 'js-rating-window';
  
  if (typeof content == 'string') {
    box.appendChild(this.html(content));

  } else {
    box.appendChild(content);
  }

  wrapper.appendChild(box);

  return wrapper;

}

JSRC.prototype.createInfoBox = function() {

  var INFOBOX_WINDOW_WIDTH = 170;
  var RATING_ARROW_OFFSET = 20;

  var pos = JSKitLib.findPos(this.infoBoxPosition);
  var html = '<div class="js-rating-infoBox">';

  html += '<div class="js-rating-infoBoxStats js-rating-infoBoxText">';

  if (this.config.freeze == 'yes') {
    html += '<span class="js-rating-infoBoxTextEm">' + $JRL('ratingsDisabled') + '</span><br>';
  }

  if (this.objNum) {
    html += this.getTextForTotalVotes(this.objNum);
    html += ' <span style="white-space: nowrap">(' + JSKitLib.zeroPad(this.objAvgStarRating, 2) + '&nbsp;' + $JRL('avgRating') + ')</span><br>';
  } else {
    if (this.config.freeze != 'yes') {
      html += $JRL('noVotesReceivedYet') + '<br>';
    }
  }

  if (this.userRating) {
    html += $JRL('yourRating') + ': ';
    html += (this.userRating / this.raterInc);
  } else {
    if (this.config.freeze != 'yes') {
      if (this.objNum) {
        html += $JRL('youHaveNotRatedYet');
      } else {
        html += $JRL('beTheFirstToRate');
      }
    }
  }
  html += '</div>';

  html += '<span class="js-rating-infoBoxText">' + $JRL('poweredBy') + ' <a href="http://js-kit.com/ratings/?wow" class="js-rating-infoBoxText" target="_blank">JS-Kit</a></span>';
  html += '</div>';
  var self = this;
  var closeInfoBox = function() {
    self.hideInfoBox();
  }
  var node = this.createWindow(html, {header:false, onclose:closeInfoBox});
  node.style.position = 'absolute';

  node.style.left = pos[0] + 'px';
  node.style.top  = pos[1] + 'px';

  // If rating widget is too close to left side, show on the right side
  if (pos[0] > INFOBOX_WINDOW_WIDTH || this.totalWidth >= INFOBOX_WINDOW_WIDTH) {
      node.style.left = (pos[0] + this.totalWidth - INFOBOX_WINDOW_WIDTH + RATING_ARROW_OFFSET) + 'px';
  }
  node.style.width = INFOBOX_WINDOW_WIDTH + 'px';

  node.style.zIndex = '1000';
  return node;
}

/* Process all rating objects with the same ID */
JSRC.prototype.processSiblings = function(handler) {
  for (var i=0; i < $JRH[this.uniq].length; i++) {
    // property must match as well
    if (this.config.property || $JRH[this.uniq][i].config.property) {
      if ($JRH[this.uniq][i].config.property == this.config.property) {
        handler($JRH[this.uniq][i]);
      }
    } else {
        handler($JRH[this.uniq][i]);
    }
  }
}

JSRC.prototype.rate = function(givenRating) {
  var oldRating = this.userRating;
  this.setUserRating(givenRating);
  var objSum = this.objSum;
  var objNum = this.objNum;
  var objVotes = this.objVotes;
  if(oldRating) {
    objSum -= oldRating;
    objNum --;
  }
  this.setTmpText($JRL('thankYou'));

  // Update all ratings for this ID
  this.processSiblings(function(sibling) {
    //TODO: determine if current user increments objVotes count
    sibling.newRating({ Sum: objSum + givenRating, Num: objNum + 1, Votes: objVotes }, { Sum: givenRating });
  });

  // Refresh the InfoBox 
  this.refreshInfoBox();

  // Handle any callbacks
  this.processOnRate();

  // TODO: parametric rating
  if (window.$J$PRA && typeof $J$PRA == 'object') {
    for (var i=0; i < $J$PRA.length; i++) {
      if ($J$PRA[i].path == this.path) {
        $J$PRA[i].onRate();
      }
    }
  }

  var title = this.config.title || "";
  this.server(".put", "rating=" + givenRating
    + (this.config.property ? "&property=" + this.config.property : "")
	+ (title ? ("&title=" + encodeURIComponent(title)) : "")
	+ (this.config.notop ? "&notop=true" : "")
	+ (this.config.permalink ? "&permalink=" + encodeURIComponent(this.config.permalink) : "")
	);
}

JSRC.prototype.setUserRating = function(rating) {
  this.userRating = rating;
}

// Returns: an array of actionable rating icons 
JSRC.prototype.getRatingIcons = function() {

  if (this._ratingIcons && this._ratingIcons.length > 0) {
    return this._ratingIcons;
  }

  this._ratingIcons = this._getIcons('js-kit-rater');
  return this._ratingIcons;
}

JSRC.prototype.getObjIcons = function() {

  if (this._objIcons && this._objIcons.length > 0) {
    return this._objIcons;
  }

  this._objIcons = this._getIcons('js-kit-objIcon');
  return this._objIcons;
}

JSRC.prototype._getIcons = function(iconClass) {

  var divs = this.target.getElementsByTagName('div');
  var icons = [];
  for (var i=0; i < divs.length; i++) {
    if (divs[i].className && divs[i].className.indexOf(iconClass) >= 0) {
      icons.push(divs[i]);
    }
  }
  return icons;
}

JSRC.prototype.getTextForTotalVotes = function(votes) {
  var text;
  switch(votes) {
    case  1: text = votes + ' ' + $JRL('vote');  break;
    default: text = votes + ' ' + $JRL('votes'); break;
  }
  return text;
}

JSRC.prototype.getTextForUserRating = function(rating) {
  var text = $JRL('yourRatingTitleCase') + ': ' + rating;
  return text;
}

JSRC.prototype.refreshTextTotal = function() {
  var text = (this.objNum) ? this.getTextForTotalVotes(this.objNum) : $JRL('unrated');
  this.setTextTotal(text);
}

JSRC.prototype.refreshTextRating = function(text) {
  if (this.userRating) {
    var text = this.getTextForUserRating(this.userRating / this.raterInc);
  } else { 
    var text = $JRL('yourRatingTitleCase');
  }
  this.setTextRating(text);
}

JSRC.prototype.setTextRating = function(text) {
  this._setText(this.textRating, text);
}

JSRC.prototype.setTextTotal = function(text) {
  this.lastSetText = text;
  if(this.tmpTextTimer)
	return;
  this._setText(this.textTotal, text);
}

JSRC.prototype.setActiveText = function(text) {
  this._setText(this.activeText, text);
}

JSRC.prototype.setTmpText = function(text) {
  var self = this;
  if(this.tmpTextTimer)
    clearTimeout(this.tmpTextTimer);
  this.tmpTextTimer = setTimeout(function() {
	self.tmpTextTimer = null;
	self.setTextTotal(self.lastSetText);
    }, 1000);
  this._setText(this.textTotal, text);
}

JSRC.prototype._setText = function(node, text) {
  if ( ! node) {
    return;
  }
  while (node.hasChildNodes()) {
    node.removeChild(node.firstChild);
  }
  node.appendChild(document.createTextNode(text));
}

JSRC.prototype.setImage = function(star, imageURL) {
	if(star.imageURL == imageURL)
		return;	// Already set and we know it
	star.imageURL = imageURL;

	JSKitLib.addPNG(star, imageURL);    
}

// Handles the hover state for the actionable stars
JSRC.prototype.hover = function(index) {

  if(this.tmpTextTimer) return;

  // The text which is under the hover state
  this.setActiveText($JRL('rateThis') + ': ' + (index / this.raterInc));

  var icons = this.getRatingIcons();
  for (var i=0; i < icons.length; i++) {
    if (index > (i * this.raterInc)) {
	this.setImage(icons[i], this.fullStar['user']);
    } else {
	this.setImage(icons[i], this.emptyStar['user']);
    }
  }
}

JSRC.prototype.refreshObjRating = function() {
  var icons = this.getObjIcons();
  this._refreshRating('star', this.objEffRating, icons);
}

// Resets the user rating view to their actual rating
JSRC.prototype.refreshRating = function() {

  if (this.defaultView == 'star') {
    var type = 'star';
    var comparison = this.objEffRating;
  } else {
    var type = 'user';
    var comparison = this.userRating;
  }

  var icons = this.getRatingIcons();

  this._refreshRating(type, comparison, icons);

  if (this.defaultView == 'star') {
    this.refreshTextTotal();
  } else {
    this.refreshTextRating();
  }
}

JSRC.prototype._refreshRating = function(type, comparison, icons) {

  for (var i=0; i < icons.length; i++) {
    if (comparison > (i * this.raterInc)) {
      if (i * this.raterInc + (this.raterInc / 2) == comparison) {
        this.setImage(icons[i], this.halfStar[type]);
      } else {
        this.setImage(icons[i], this.fullStar[type]);
      }
    } else {
      this.setImage(icons[i], this.emptyStar[type]);
    }
  }
}  

JSRC.prototype.initRating = function(rating, type, actionable) {
  var self = this;
  var node = this.cr('div');
  node.style.width = this.ratingBarWidth + 'px';
  node.style.height = this.ratingBarHeight + 'px';

  var inf = function() {
	if(self.refreshScheduled)
		clearTimeout(self.refreshScheduled);
  }
  var outf = function() {
	if(self.refreshScheduled)
		clearTimeout(self.refreshScheduled);
	self.refreshScheduled = setTimeout(
		function(){self.refreshScheduled=null;
		self.refreshRating()}, 300);
  }

  node.onmouseover = function() {
			if(self.refreshScheduled)
				clearTimeout(self.refreshScheduled);
		}
  node.onmouseout = outf;

  /* Increment by Full Star Ratings */
  for (var i=this.raterInc; i <= this.scale; i += this.raterInc) {

    var star = this.cr('div');

    star.style.cssFloat   = 'left';
    star.style.styleFloat = 'left';
    star.style.width    = this.starWidth + 'px';
    star.style.height   = this.starHeight + 'px';

    if (rating + this.raterInc > i) {
      if (rating + this.raterInc - i >=  this.raterInc) {
	this.setImage(star, this.fullStar[type]);
      } else {
	this.setImage(star, this.halfStar[type]);
      }
    } else {
      this.setImage(star, this.emptyStar[type]);
    }

    if (actionable) {
     (function(i) {
      star.className += ' js-kit-rater';
      star.onmouseover = function() { inf(); self.hover(i); }
      star.onmouseout  = outf;
      star.onclick     = function() { self.rate(i); }
     })(i);
    } else {
      star.className += ' js-kit-objIcon';
    }
    node.appendChild(star);
  }

  if (actionable) {
    node.style.cursor = 'pointer';
  }

  return node;
}


JSRC.prototype.getCommentsAppObject = function() {
  if (this.isStandalone()) {
    return null; 
  } else {
    return $JSKitGlobal.getCommentsAppObject(this.uniq);
  }
}

JSRC.prototype.hasCommentsAppObject = function() {
  return this.getCommentsAppObject() ? true : false;
}

JSRC.prototype.clone = function(node, options) {
  if ( ! options) {
    options = {};
  }

  var clone = new JSRC(node, {
    'newRating' : {
      'objSum' : this.objSum,
      'objNum' : this.objNum,
      'userRating' : this.userRating
    },
    'path' : options.path || this.config.path,
    'uniq' : options.uniq || this.config.uniq,
    'view' : options.view || this.config.view,
    'notop' : options.notop || this.config.notop,
    'commentprompt' : options.commentprompt || this.config.commentprompt,
    'starcolor' : options.starcolor || this.config.starcolor,
    'usercolor' : options.usercolor || this.config.usercolor,
    'imageurl' : options.imageurl || this.config.imageurl,
    'imagesize' : options.imagesize || this.config.imagesize,
    'menu' : options.menu || this.config.menu

  });

  return clone;
}

/*
 * TODO: make backwards compatible to old method call:
 *   JSRC.prototype.newRating = function(sum, num, userRating) 
 */
JSRC.prototype.newRating = function() {
  var args = arguments;
  if(typeof args[0] != 'object')
    args = [ args[3], args[4] || {} ];
  var community = args[0];
  var user = args[1] || { Sum: 0 };

  if(user.frozen) this.config.freeze = "yes";

  this.objSum = community.Sum;
  this.objNum = community.Num;
  this.objVotes = community.Votes || community.Num;
  this.userRating = user.Sum;
  this.objAvgStarRating = JSKitLib.round((this.objSum / this.objNum) / this.raterInc, 1);
  this.objEffRating = Math.round(this.objSum / this.objNum) || 0;  // Used for star display purposes

  if(this.refreshScheduled) {
	clearTimeout(this.refreshScheduled);
	this.refreshScheduled = null;
  }

  if (this.constructed) {
    this.refreshTextTotal();
    this.refreshObjRating();
    this.refreshRating();
  } else {
    this.constructed = true;
    this.display();
  }

  // TODO: use JSKitGlobal
  if (window.$J$PRA && typeof $J$PRA == 'object') {
    for (var i=0; i < $J$PRA.length; i++) {
        $J$PRA[i].updateComposite();
    }
  }


}


