var startRainbow;

(function(){
  function getCssRule(sheet, selector) {
    if (document.styleSheets) {
      var sheets = document.styleSheets;
      
      //Find the style sheet which we need to modify for the waves
      for (var i = 0; i != sheets.length; i++) {
        var sheetName = sheets[i].href.substring(sheets[i].href.lastIndexOf('/')+1);
        if (sheetName.indexOf(sheet) == 0) {
          var currentSheet = sheets[i];
        }
      }
    } else {
      return false;
    }

    //Get a list of rules in the stylesheet (IE needs to be different, yet again)
    if (currentSheet.cssRules) {
      var sheetRules = currentSheet.cssRules; 
    } else if (currentSheet.rules) {
      var sheetRules = currentSheet.rules;
    } else {
      return false;
    }

    //Get the rules that are used to define where the wave appears on the buttons
    if (sheetRules) {
      for (var i = 0; i != sheetRules.length; i++) {
        if (sheetRules[i].selectorText.toLowerCase() == selector) {
          return sheetRules[i];
        }
      }
    }
  }

  var timeout = 50;
  var stepSize = 0.007;
  var cycle = 0;
  
  var cssToRgb = /\d{1,3}/g;
  
  var rules;
  var currentColors; 
  var nextColors;
  
  var hexCharacters = "0123456789ABCDEF";
  function toCss(color) {
    var out = '#';
    for (i in color) {
      var dec = color[i];
      if (dec < 0) dec = 0;
      if (dec > 255) dec = 255;
      out += hexCharacters.charAt(Math.floor(dec / 16)) + hexCharacters.charAt(dec % 16);
    }
    return out;
  }
  function fromCss(str) {
    if (str.substring(0, 3) == "rgb") {
      color = str.match(cssToRgb);
      for (i in color) {
        color[i] = parseInt(color[i]);
      }
      return color;
    } else {
      var color = [str.substring(1, 3).toUpperCase(), str.substring(3, 5).toUpperCase(), str.substring(5, 7).toUpperCase()];
      for (i in color) {
        var hex = color[i];
        color[i] = (16*hexCharacters.indexOf(hex.charAt(0)))+hexCharacters.indexOf(hex.charAt(1));
      }
      return color;
    }
  }

  function makeStep() {
    if (cycle >= 1) {
      nextColor();
    }
    
    for (var i = 0; i != rules.length; i++) {
      var transition = Array(3);
      for (var j = 0; j != 3; j++) {
        transition[j] = currentColors[i][j] + parseInt((Math.cos((1 + cycle) * Math.PI) + 1)/2*(nextColors[i][j] - currentColors[i][j]));
        
        if (transition[j] > 255) {
          transition[j] -= 255;
        } else if (transition[j] < 0) {
          transition[j] += 255;
        }
      }
      rules[i].style.backgroundColor = toCss(transition);
    }
    
    cycle += stepSize;
    
    setTimeout(makeStep, timeout);
  }
  
  function nextColor() {
    for (var i = 0; i != rules.length; i++) {
      currentColors[i] = nextColors[i];
    }
    nextColors.push(nextColors.shift());
    cycle = 0;
  }
  
  startRainbow = function(numberOfColors, stylesheetName, ruleBase) {
    rules = new Array(numberOfColors);
    currentColors = new Array(numberOfColors);
    nextColors = new Array(numberOfColors);
    
    for (var i = 0; i != numberOfColors; i++) {
      rules[i] = getCssRule(stylesheetName, ruleBase + ' .rainbow-' + (i+1));
      currentColors[i] = fromCss(rules[i].style.backgroundColor);
      nextColors[i] = currentColors[i];
    }
    nextColors.push(nextColors.shift());
    
    makeStep();
  };
})();