/**

 * Voting Star Object.

 * 

 * Tested on IE6 + FF > 2 + Opera 9.21 

 * 

 * TODO:

 * 1) Memory Leaks in IE 6

 * 2) Test in Safari and IE 7

 */







/**

 * Main votin star object.

 * 

 * @param voteHiddenFeildId - id of hidden feild to insert value onchange.

 * @param containerId - id of container to create the stars in.

 * 

 * Emaple of usage: 

 * <script type="text/javascript">

 *   var starVoting = new VotingStars("starInput", "container");

 * </script>

 * 

 */

function VotingStars (voteHiddenFeildId, containerId, params) {

  

  /** Nubmer of Stars. */

  this.numStars = 5;

  

  /** Star weights (Sorted lower to heigher!). */

  this.starStateValues = [0, 1];

  

  /** Star Images (must correlate with weights by index). */

  this.starStateImagePaths = ["http://www.ewol.com.ua/images/star_0.png",

                              "http://www.ewol.com.ua/images/star_1.png"];

                              

                              

  /** Whether to show toolTips or not. */

  this.showToolTips = true;                

  

  /** ToolTip captions (Must have length of ((this.numStars * (this.starStateValues - 1)) + 1)). */

  this.toolTipCaptions = ["Ужасно",

                          "Плохо",

                          "Нормально",

                          "Понравилось",

                          "Великолепно!"];

  

  /** CSS Class for Tool Tip.*/

  this.toolTipClassName = "toolTip";                 

   

  /** Default Star State Value. */

  this.defaultStarStateValue = 0;

  

  /** Number Of Pixels between stars. */                           

  this.pixBetweenStars = 0;

  

  /** Star Width (!!! Important !!!). */

  this.starWidth = 16;

  

  /** Mouse out timeout before star reset (Milis) */

  this.starResetTimeOut = 0;  

  if (params && params.onclickHandler) {
    this.onclickHandler = params.onclickHandler;
  }
  
  /** Internal Vaiables [Do not Change]. */
  this.voteHiddenFeild = document.getElementById(voteHiddenFeildId);

  this.container = document.getElementById(containerId);
  this.currentValue = 0;
  this.currentStarNum = 0;
  this.currentStarInnerOffset = 0;
  this.savedStarNum = 0;
  this.savedStarInnerOffset = 0;  
  this.stars = [];
  this.createStarsEl();
}



/**

 * VotingStars prototype.

 */

VotingStars.prototype = {
  /**

   * On Mouse Move Handler. 

   */

  onMouseMove : function(evt) {

    //alert("onMouseMove");

    var reletiveMouseOffset;

    var pageX;

    if (!evt) {

      evt = window.event;

      pageX = evt.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;

    } else {

	    pageX = evt.pageX;

    }

    var targ;

		if (evt.currentTarget) targ = evt.currentTarget;

		else if (evt.srcElement) targ = evt.srcElement;

		if (targ.nodeType == 3) // defeat Safari bug

			targ = targ.parentNode;



    if (targ.nodeName == "IMG") {

      targ = targ.parentNode;

    }

	  if (targ.getBoundingClientRect) {

		  var obj = targ.getBoundingClientRect();

	  }

		if (obj) {

      var left = obj.left;

      reletiveMouseOffset = (pageX - left);

		} else {

		  reletiveMouseOffset = (pageX - targ.offsetLeft);

		}

		

		if (evt.preventDefault) {

	    evt.preventDefault();

		} 

		if (evt.stopPropagation) {

	    evt.stopPropagation();

		}

		targ.votingObject.proccessMouseMove(reletiveMouseOffset);

  },

  

  /**

   * On Mouse Click Handler. 

   */

  onMouseClick: function(evt) {

    if (!evt) {

      evt = window.event;

    }

    var targ;

		if (evt.currentTarget) targ = evt.currentTarget;

		else if (evt.srcElement) targ = evt.srcElement;

		if (targ.nodeType == 3) // defeat Safari bug

			targ = targ.parentNode;

    if (targ.nodeName == "IMG") {

      targ = targ.parentNode;

    }

    var curStarNum = targ.votingObject.currentStarNum;

    

    targ.votingObject.savedStarNum = curStarNum;	    

    targ.votingObject.savedStarInnerOffset = targ.votingObject.currentStarInnerOffset;

    

    var lastStarValue = targ.votingObject.stars[curStarNum - 1].getCurrentState().getValue();

    var valueToSave = targ.votingObject.savedStarNum;

    if (lastStarValue < 1) {

      valueToSave -= lastStarValue;

    }

    //alert("valueToSave = " + valueToSave);
    //alert(targ.votingObject);
    targ.votingObject.voteHiddenFeild.value = valueToSave;
    
    if (targ.votingObject.onclickHandler) {
      targ.votingObject.onclickHandler();
    }
  },



  /**

   * On Mouse Out Handler. 

   */

  onMouseOut: function(evt) {

    //alert("onMouseOut");

    if (!evt) {

      evt = window.event;

    }

    var targ;

		if (evt.currentTarget) targ = evt.currentTarget;

		else if (evt.srcElement) targ = evt.srcElement;

		if (targ.nodeType == 3) // defeat Safari bug

			targ = targ.parentNode;

    if (targ.nodeName == "IMG") {

      targ = targ.parentNode;

    }	

    targ.votingObject.mouseMoved = false;

    timeOutFlag = setTimeout(targ.votingObject.mouseOutProcces, targ.votingObject.starResetTimeOut);

		if (evt.preventDefault) {

	    evt.preventDefault();

		} 

		if (evt.stopPropagation) {

	    evt.stopPropagation();

		}    

  },

  

  

  mouseOutProcces: function() {

    var wraper = document.getElementById("wraper");

    var votingObject = wraper.votingObject;

    if (!votingObject.mouseMoved) {

      if (votingObject.savedStarNum > 0) {

        votingObject.redrawStars(votingObject.savedStarNum, votingObject.savedStarInnerOffset);

      } else {

        for (var i = 0; i < votingObject.numStars; i++) {

          votingObject.stars[i].changeState(0);

        }

      }

    }

  }, 

  

  

  onStarMouseMove: function (evt) {

    //alert("onStarMouseMove");

    clearTimeout(timeOutFlag);

    if (!evt) {

      evt = window.event;

    }

    var targ;

		if (evt.currentTarget) targ = evt.currentTarget;

		else if (evt.srcElement) targ = evt.srcElement;

		if (targ.nodeType == 3) // defeat Safari bug

			targ = targ.parentNode;

    if (targ.nodeName == "IMG") {

      targ = targ.parentNode;

    }		

    

    //alert(this.starWidth - (starCoord - offset));

		targ.votingObject.mouseMoved = true;	    

  },
 

  onMouseOver: function (evt) {

    clearTimeout(timeOutFlag);

    if (!evt) {

      evt = window.event;

    }

    var targ;

		if (evt.currentTarget) targ = evt.currentTarget;

		else if (evt.srcElement) targ = evt.srcElement;

		if (targ.nodeType == 3) // defeat Safari bug

			targ = targ.parentNode;

    if (targ.nodeName == "IMG") {

      targ = targ.parentNode;

    }		

		targ.votingObject.mouseMoved = true;	    

  },



  /**

   * Procceses Mouse move. 

   */

  proccessMouseMove: function(offset) {

    //alert("offset = " + offset);

    clearTimeout(timeOutFlag);

    this.mouseMoved = true;

    var foundStar = false;

    var starNum = 1;

    var starCoord = 0;

    while (!foundStar) {

      if (starNum >= 2) {

        starCoord += this.pixBetweenStars;// * this.pixBetweenStars;

      }

      starCoord += this.starWidth;

      //alert("starCoord = " + starCoord);

      if (offset <= starCoord) {

        foundStar = true;

      } else {        

        starNum += 1;

        if (starNum > this.numStars) {

          starNum = this.numStars;

        }

      }

    }

    var starInnerOffset = 0;

    if (starNum >= 2) {

      starInnerOffset = offset - (starCoord - this.starWidth);

    } else {

      starInnerOffset = offset;

    }

    //alert("Star offset = " + starInnerOffset);

    

    this.currentStarNum = starNum;

    this.currentStarInnerOffset = starInnerOffset;

    this.redrawStars(starNum, starInnerOffset);

  },

  

  /**

   * Redraws stars.

   * 

   * @param lastActiveStarNum - index of last star that should be active.

   */

  redrawStars : function(lastActiveStarNum, starInnerOffset) {

    //alert(lastActiveStarNum);

    var prevStarNum = lastActiveStarNum - 1;

    //alert("Prev = " + prevStarNum); 

    for (var i = 0; i < prevStarNum; i++) {

      this.stars[i].changeState(1);

    }

    for (var j = lastActiveStarNum; j < this.stars.length; j++) {

      this.stars[j].changeState(0);

    }    

     this.stars[prevStarNum].changeStateByInnerOffset(starInnerOffset);

  },

  

  /**

   * Creates Star Elements.

   */

  createStarsEl: function() {

    var starWraper = document.createElement("DIV");

    starWraper.style.float = "left";

    var starStateValue = 0; 

    for (var i = 0; i < this.numStars; i++) {

      var star = new Star(this.createStarEl(i) , this.starWidth, this.showToolTips);

      for (var j = 0; j < this.starStateValues.length; j++) {

        if (this.starStateValues[j] > 0) {

         var toolTipCaption =  this.toolTipCaptions[starStateValue]

         starStateValue++;

        }

        var state = new StarState(this.starStateImagePaths[j], this.starStateValues[j], toolTipCaption);

        if (this.toolTipClassName) {

          state.setToolTipCssClass(this.toolTipClassName);

        }

        star.addState(state);

      } 

      star.changeState(this.defaultStarStateValue);

      star.getStarImgEl().onmousemove = this.onStarMouseMove;

      starWraper.appendChild(star.getStarImgEl());

      this.stars[this.stars.length] = star;

    }

   

    starWraper.onclick = this.onMouseClick;

    starWraper.onmousemove = this.onMouseMove;

    starWraper.onmouseout = this.onMouseOut;

    starWraper.onmouseover = this.onMouseOver;

    starWraper.style.cursor = "pointer";

    starWraper.votingObject = this;

    starWraper.id = "wraper";

    this.container.appendChild(starWraper);

    var containerWidth = 0;

    for (var i = 0; i < this.numStars; i++) {    

      containerWidth += this.starWidth;

      if (i > 0) {

        containerWidth += this.pixBetweenStars;

      }    

    }

    starWraper.style.width = containerWidth + "px";

  },

  

  /**

   * Creates one Star Element.

   */  

  createStarEl: function(starNum) {  

    var starImg = document.createElement("IMG");

    starImg.border = "0";

    starImg.style.float = "left";

    starImg.style.display = "inline";    

    if (starNum > 0) {

      starImg.style.marginLeft = this.pixBetweenStars + "px";

    }      

    return starImg;

  }

  

}  







/**

 * Object that defines a star state.

 * 

 * @param imagePath - path to image that represents this state.

 * @param value - vlaue of this state.

 */

function StarState(imagePath, value, toolTipCaption) {
	

  this.imagePath = imagePath;

  this.value = value;  

  this.toolTipCaption = toolTipCaption;

}



/**

 * Star State prototype.

 */

StarState.prototype = {



  /**

   * Getter method for imagePath.

   * @return imagePath.

   */  

  getImagePath : function() {

    return this.imagePath;

  },

  

  /**

   * Getter method for value.

   * @return value.

   */   

  getValue : function() {

    return this.value;

  },

  

  /**

   * Getter method for toolTipCaption.

   * @return toolTipCaption.

   */   

  getToolTipCaption : function() {

    return this.toolTipCaption;

  },  

  

  setToolTipEl: function(toolTipEl) {

    this.toolTipEl = toolTipEl;

  },

  

  getToolTipEl: function() {

    return this.toolTipEl;

  },

  

  setToolTipCssClass: function(toolTipCss) {

    this.toolTipCss = toolTipCss;

  },

  

  getToolTipCssClass: function() {

    return this.toolTipCss;

  }  

  

}





/**

 * Object that defines a star.

 * 

 * @param starImgEl - DOM Img element to bind this object with.

 */

function Star(starImgEl, width, showToolTip) {

  this.states = [];  

  this.currentState = null;

  this.starImgEl = starImgEl;

  this.width = width;

  this.showToolTipFlag = showToolTip;

}



/**

 * Star prototype.

 */

Star.prototype = {

  

  /**

   * Adds a state to this star.

   * @param starState - state to add.

   */

  addState : function(starState) {

    this.states[this.states.length] = (starState);

  },

  

  /**

   * Changes the state of this star.

   * @param value of state to change to.

   */

  changeState : function(stateValue) {

    for (var i = 0; i < this.states.length; i++) {

      var starState =  this.states[i];

      if (starState.getValue() == stateValue) {

        if (this.showToolTipFlag) {

         this.hideToolTip();    

        }    

        this.starImgEl.src = starState.getImagePath();

        this.currentState = starState;

        break;

      }

    }

  },

  

  changeStateByInnerOffset: function(innerOffset) {

    if (innerOffset < 0) {

      this.changeState(this.states[1]);

      return;

    }

    

    for (var i = 0; i < this.states.length; i++) {

      var starState =  this.states[i];

      if (innerOffset < (starState.getValue() * this.width)) {

        this.changeState(starState.getValue());

        if (this.showToolTipFlag) {

          this.showToolTip();

        }

        return;

      }

    }

    

  },   

  

  

  showToolTip: function() {

    if (!this.currentState.getToolTipEl()) {

      var imgEl = this.getStarImgEl();

      var imgLeft = 0;

      var imgTop = 0;

      if (imgEl.getBoundingClientRect) {

  		  var obj = imgEl.getBoundingClientRect();

  	  }

  	  

  		if (obj) {

  		imgLeft = obj.left;
		var imgTop = imgEl.offsetTop;
		while((imgEl = imgEl.offsetParent) != null) {
		imgTop += imgEl.offsetTop;
		}  

  		} else {

  		  imgTop = imgEl.offsetTop;

  		  imgLeft = imgEl.offsetLeft;

  		}

  		

      var toolTip = document.createElement("DIV");

      toolTip.style.position = "absolute";

      toolTip.style.top = (imgTop - 20) + "px";

      toolTip.style.left = imgLeft + "px";

      toolTip.innerHTML = this.currentState.getToolTipCaption();

      toolTip.className = this.currentState.getToolTipCssClass();

  		document.body.appendChild(toolTip);

  		this.currentState.setToolTipEl(toolTip);  		

    } else {

      this.currentState.getToolTipEl().style.display = "block";

    }

  },

  

  

  hideToolTip: function() {

    if (this.currentState && this.currentState.getToolTipEl()) {

      this.currentState.getToolTipEl().style.display = "none";

    }

  },

  

  

  /**

   * Getter method for current star state.

   * @return currentState.

   */

getCurrentState : function() {

    return this.currentState;

  },

  

  /**

   * Getter method for starImgEl.

   * @return starImgEl.

   */

  getStarImgEl : function () {

    return this.starImgEl;

  }

  

}



var timeOutFlag = false;