function sack(file) {
  this.xmlhttp = null;

  this.resetData = function() {
    this.method = "POST";
      this.queryStringSeparator = "?";
    this.argumentSeparator = "&";
    this.URLString = "";
    this.encodeURIString = true;
      this.execute = false;
      this.element = null;
    this.elementObj = null;
    this.requestFile = file;
    this.vars = new Object();
    this.responseStatus = new Array(2);
    };

  this.resetFunctions = function() {
      this.onLoading = function() { };
      this.onLoaded = function() { };
      this.onInteractive = function() { };
      this.onCompletion = function() { };
      this.onError = function() { };
    this.onFail = function() { };
  };

  this.reset = function() {
    this.resetFunctions();
    this.resetData();
  };

  this.createAJAX = function() {
    try {
      this.xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e1) {
      try {
        this.xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
      } catch (e2) {
        this.xmlhttp = null;
      }
    }

    if (! this.xmlhttp) {
      if (typeof XMLHttpRequest != "undefined") {
        this.xmlhttp = new XMLHttpRequest();
      } else {
        this.failed = true;
      }
    }
  };

  this.setVar = function(name, value){
    this.vars[name] = Array(value, false);
  };

  this.encVar = function(name, value, returnvars) {
    if (true == returnvars) {
      return Array(encodeURIComponent(name), encodeURIComponent(value));
    } else {
      this.vars[encodeURIComponent(name)] = Array(encodeURIComponent(value), true);
    }
  }

  this.processURLString = function(string, encode) {
    encoded = encodeURIComponent(this.argumentSeparator);
    regexp = new RegExp(this.argumentSeparator + "|" + encoded);
    varArray = string.split(regexp);
    for (i = 0; i < varArray.length; i++){
      urlVars = varArray[i].split("=");
      if (true == encode){
        this.encVar(urlVars[0], urlVars[1]);
      } else {
        this.setVar(urlVars[0], urlVars[1]);
      }
    }
  }

  this.createURLString = function(urlstring) {
    if (this.encodeURIString && this.URLString.length) {
      this.processURLString(this.URLString, true);
    }

    if (urlstring) {
      if (this.URLString.length) {
        this.URLString += this.argumentSeparator + urlstring;
      } else {
        this.URLString = urlstring;
      }
    }

    // prevents caching of URLString
    this.setVar("rndval", new Date().getTime());

    urlstringtemp = new Array();
    for (key in this.vars) {
      if (false == this.vars[key][1] && true == this.encodeURIString) {
        encoded = this.encVar(key, this.vars[key][0], true);
        delete this.vars[key];
        this.vars[encoded[0]] = Array(encoded[1], true);
        key = encoded[0];
      }

      urlstringtemp[urlstringtemp.length] = key + "=" + this.vars[key][0];
    }
    if (urlstring){
      this.URLString += this.argumentSeparator + urlstringtemp.join(this.argumentSeparator);
    } else {
      this.URLString += urlstringtemp.join(this.argumentSeparator);
    }
  }

  this.runResponse = function() {
    eval(this.response);
  }

  this.runAJAX = function(urlstring) {
    if (this.failed) {
      this.onFail();
    } else {
      this.createURLString(urlstring);
      if (this.element) {
        this.elementObj = document.getElementById(this.element);
      }
      if (this.xmlhttp) {
        var self = this;
        if (this.method == "GET") {
          totalurlstring = this.requestFile + this.queryStringSeparator + this.URLString;
          this.xmlhttp.open(this.method, totalurlstring, true);
        } else {
          this.xmlhttp.open(this.method, this.requestFile, true);
          try {
            this.xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
          } catch (e) { }
        }

        this.xmlhttp.onreadystatechange = function() {
          switch (self.xmlhttp.readyState) {
            case 1:
              self.onLoading();
              break;
            case 2:
              self.onLoaded();
              break;
            case 3:
              self.onInteractive();
              break;
            case 4:
              self.response = self.xmlhttp.responseText;
              self.responseXML = self.xmlhttp.responseXML;
              self.responseStatus[0] = self.xmlhttp.status;
              self.responseStatus[1] = self.xmlhttp.statusText;

              if (self.execute) {
                self.runResponse();
              }

              if (self.elementObj) {
                elemNodeName = self.elementObj.nodeName;
                elemNodeName.toLowerCase();
                if (elemNodeName == "input"
                || elemNodeName == "select"
                || elemNodeName == "option"
                || elemNodeName == "textarea") {
                  self.elementObj.value = self.response;
                } else {
                  self.elementObj.innerHTML = self.response;
                }
              }
              if (self.responseStatus[0] == "200") {
                self.onCompletion();
              } else {
                self.onError();
              }

              self.URLString = "";
              break;
          }
        };

        this.xmlhttp.send(this.URLString);
      }
    }
  };

  this.reset();
  this.createAJAX();
}

var serverSideFile = '/ajax-poll-vote.php';
var voteLeftImage = '/images/poll/graph_left_1.gif';
var voteRightImage = '/images/poll/graph_right_1.gif';
var voteCenterImage = '/images/poll/graph_middle_1.gif';

var graphMaxWidth = 280;  // It will actually be a little wider than this because of the rounded image at the left and right
var graphMinWidth = 20; // Minimum size of graph
var pollScrollSpeed = 5;  // Lower = faster
var useCookiesToRememberCastedVotes = true;  // Use cookie to remember casted votes
var txt_totalVotes = 'Total number of votes: ';

var ajaxObjects = new Array();
var pollVotes = new Array();
var pollVoteCounted = new Array();
var totalVotes = new Array();


/* Preload images */

var preloadedImages = new Array();
preloadedImages[0] = new Image();
preloadedImages[0].src = voteLeftImage;
preloadedImages[1] = new Image();
preloadedImages[1].src = voteRightImage;
preloadedImages[2] = new Image();
preloadedImages[2].src = voteCenterImage;

/*
These cookie functions are downloaded from 
http://www.mach5.com/support/analyzer/manual/html/General/CookiesJavaScript.htm
*/  
function Poller_Get_Cookie(name) { 
   var start = document.cookie.indexOf(name+"="); 
   var len = start+name.length+1; 
   if ((!start) && (name != document.cookie.substring(0,name.length))) return null; 
   if (start == -1) return null; 
   var end = document.cookie.indexOf(";",len); 
   if (end == -1) end = document.cookie.length; 
   return unescape(document.cookie.substring(len,end)); 
} 
// This function has been slightly modified
function Poller_Set_Cookie(name,value,expires,path,domain,secure) { 
  expires = expires * 60*60*24*1000;
  var today = new Date();
  var expires_date = new Date( today.getTime() + (expires) );
    var cookieString = name + "=" +escape(value) + 
       ( (expires) ? ";expires=" + expires_date.toGMTString() : "") + 
       ( (path) ? ";path=" + path : "") + 
       ( (domain) ? ";domain=" + domain : "") + 
       ( (secure) ? ";secure" : ""); 
    document.cookie = cookieString; 
}

  
function showVoteResults(pollId,ajaxIndex)
{
  
  document.getElementById('poller_waitMessage' + pollId).style.display='none';
  
  var xml = ajaxObjects[ajaxIndex].response;
  xml = xml.replace(/\n/gi,'');
  
  var reg = new RegExp("^.*?<pollerTitle>(.*?)<.*$","gi");
  var pollerTitle = xml.replace(reg,'$1');
  
  var resultDiv = document.getElementById('poller_results' + pollId);
  
  var titleP = document.createElement('P');
  titleP.className='result_pollerTitle';
  titleP.innerHTML = pollerTitle;
  resultDiv.appendChild(titleP);  
  
  var options = xml.split(/<option>/gi);
  
  pollVotes[pollId] = new Array();
  totalVotes[pollId] = 0;
  for(var no=1;no<options.length;no++){
    
    var elements = options[no].split(/</gi);
    var currentOptionId = false;
    for(var no2=0;no2<elements.length;no2++){
      if(elements[no2].substring(0,1)!='/'){
        var key = elements[no2].replace(/^(.*?)>.*$/gi,'$1');
        var value = elements[no2].replace(/^.*?>(.*)$/gi,'$1');
      
        if(key.indexOf('optionText')>=0){
          var pOption = document.createElement('P');
          pOption.className='result_pollerOption';
          pOption.innerHTML = value;
          resultDiv.appendChild(pOption);         
          
        }
        
        if(key.indexOf('optionId')>=0){
          currentOptionId = value/1;
        }
        
        if(key.indexOf('votes')>=0){
          var voteDiv = document.createElement('DIV');
          voteDiv.className='result_pollGraph';
          resultDiv.appendChild(voteDiv); 
          
          var leftImage = document.createElement('IMG');
          leftImage.src = voteLeftImage;
          voteDiv.appendChild(leftImage);
          
          
          var numberDiv = document.createElement('DIV');
          numberDiv.style.backgroundImage = 'url(\'' + voteCenterImage + '\')';
          numberDiv.innerHTML = '0%';
          numberDiv.id = 'result_voteTxt' + currentOptionId;
          voteDiv.appendChild(numberDiv); 
          
          var rightImage = document.createElement('IMG');
          rightImage.src = voteRightImage;
          voteDiv.appendChild(rightImage);            
          
          pollVotes[pollId][currentOptionId] = value;         
          totalVotes[pollId] = totalVotes[pollId]/1 + value/1;
        }
      }
    }
  }
  
  var totalVoteP = document.createElement('div');
  totalVoteP.className = 'result_totalVotes';
  totalVoteP.innerHTML = txt_totalVotes + totalVotes[pollId];
  voteDiv.appendChild(totalVoteP);  
  
  setPercentageVotes(pollId);
  slideVotes(pollId,0);
}

function setPercentageVotes(pollId)
{
  for(var prop in pollVotes[pollId]){
    pollVotes[pollId][prop] =  Math.round( (pollVotes[pollId][prop] / totalVotes[pollId]) * 100);       
  } 
  
  var currentSum = 0;
  for(var prop in pollVotes[pollId]){
    currentSum = currentSum + pollVotes[pollId][prop]/1;      
  }
  pollVotes[pollId][prop] = pollVotes[pollId][prop] + (100-currentSum);
  
  
}

function slideVotes(pollId,currentPercent)
{
  currentPercent = currentPercent/1 + 1;
  
  for(var prop in pollVotes[pollId]){
    if(pollVotes[pollId][prop]>=currentPercent){
      var obj = document.getElementById('result_voteTxt' + prop);
      obj.innerHTML = currentPercent + '%';
      obj.style.width = Math.max(graphMinWidth,Math.round(currentPercent/100*graphMaxWidth)) + 'px';
    }     
  }
  
  if(currentPercent<100)setTimeout('slideVotes("' + pollId + '","' + currentPercent + '")',pollScrollSpeed);
}


function prepareForPollResults(pollId)
{
  document.getElementById('poller_waitMessage' + pollId).style.display='block';
  document.getElementById('poller_question' + pollId).style.display='none'; 
}


function castMyVote(pollId,formObj)
{ 
  var elements = formObj.elements['vote[' + pollId + ']'];
  var optionId = false;
  for(var no=0;no<elements.length;no++){
    if(elements[no].checked)optionId = elements[no].value;
  }
  Poller_Set_Cookie('dhtmlgoodies_poller_' + pollId,'1',6000000);
  if(optionId){
  
    var ajaxIndex = ajaxObjects.length;
    ajaxObjects[ajaxIndex] = new sack();
    ajaxObjects[ajaxIndex].requestFile = serverSideFile + '?pollId=' + pollId + '&optionId=' + optionId;
    prepareForPollResults(pollId);
    ajaxObjects[ajaxIndex].onCompletion = function(){ showVoteResults(pollId,ajaxIndex); }; // Specify function that will be executed after file has been found
    ajaxObjects[ajaxIndex].runAJAX();   // Execute AJAX function  

  } 
} 

function displayResultsWithoutVoting(pollId)
{
  var ajaxIndex = ajaxObjects.length;
  ajaxObjects[ajaxIndex] = new sack();
  ajaxObjects[ajaxIndex].requestFile = serverSideFile + '?pollId=' + pollId;
  prepareForPollResults(pollId);
  ajaxObjects[ajaxIndex].onCompletion = function(){ showVoteResults(pollId,ajaxIndex); }; // Specify function that will be executed after file has been found
  ajaxObjects[ajaxIndex].runAJAX();   // Execute AJAX function    
}