<!DOCTYPE html>
<html ng-app="rainbowRoboApp">

  <head>
    <script data-require="angular.js@*" data-semver="1.3.5" src="https://code.angularjs.org/1.3.5/angular.js"></script>
    <script data-require="underscore.js@*" data-semver="1.6.0" src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min.js"></script>
    <script data-require="jquery@*" data-semver="2.1.1" src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body ng-controller="basicController">
    <label>input: (<span>{{ basicModels.mainInput.length }}</span>)</label>
    <input type="text" ng-model="basicModels.mainInput" />
    <label>output: (ingame chat)</label>
    <input type="text" class="rainbow-output selectable" ng-model="basicModels.mainOutput" value="{{ basicModels.mainInput | rainbowify }}" />
    <label>output: (bbcode)</label>
    <input type="text" class="rainbow-output selectable" ng-model="basicModels.bbcodeOutput"/>
    
    <p>Total Characters: {{ basicModels.maxChars }}</p>
    <p>Characters left: {{ 80 - basicModels.maxChars }}</p>
    
    <p>preview: <span class="lame-preview-attempt" ng-repeat="color in basicModels.previewTextArray"><b style="color: {{color.hash}}">{{color.char}}</b></span></p>
    <div class="idnolol">
          <div ng-repeat="color in basicModels.previewTextArray"><div class="block" style="width:{{100 / basicModels.previewTextArray.length}}%; background-color:{{color.hash}}"></div></div>

    </div>
    
  </body>

</html>
// Code goes here

var LL = LL || {};

function formatDigit(d) {
  return (String(d).length == 1) ? "0" + d : "" + d;
}

LL.Rainbow = {
  RGBToHash: function(r, g, b) {
    var cA = [];
    _.each(arguments, function(c) {
      cA.push(formatDigit(this.bToHex(Math.abs(Number(c)))));
    }, this);
    return "#" + cA.join('');
  },
  objToRGBToHash: function(c) {
    return this.RGBToHash(c.red, c.green, c.blue);
  },
  RGBToBrackets: function(r, g, b) {
    var cA = [];
    _.each(arguments, function(c) {
      cA.push(formatDigit(this.bToHex(Math.abs(Number(c)))));
    }, this);
    return "[" + cA.join('') + "]";
  },
  objToRGBToBrackets: function(c) {
    return this.RGBToBrackets(c.red, c.green, c.blue);
  },
  bToHex: _.memoize(function(b) {
    return Number(b).toString(16);
  }),
  getPI120: _.memoize(function(m) {
    var mu = typeof m === 'undefined' ? 1 : m;
    return mu * Math.PI / 3;
  }),
  getSteppedFrequency: _.memoize(function(s) {
    var step = typeof s === 'undefined' ? 0.21 : s;
    return Math.PI * 2 / step;
  }),
  getFixedRainbow: function(cObj) {
    if (typeof cObj === 'undefined' || typeof cObj !== 'object') throw "No Object passed.";
    return function(i) {
      if (typeof i === 'undefined') throw "No iterator passed.";
      return {
        red: Math.round(Math.sin(cObj.freq[0] * i + cObj.phase[0]) * cObj.width + cObj.center),
        green: Math.round(Math.sin(cObj.freq[1] * i + cObj.phase[1]) * cObj.width + cObj.center),
        blue: Math.round(Math.sin(cObj.freq[2] * i + cObj.phase[2]) * cObj.width + cObj.center)
      };
    };
  },
  createComponents: function(len, freq, phase, width, center) {
    var cObj = {};
    cObj.len = typeof len === 'undefined' ? 64 : len;
    cObj.freq = typeof freq === 'undefined' ? this.getSteppedFrequency(cObj.len) : freq,
    cObj.phase = typeof phase === 'undefined' ? [0, this.getPI120(2), this.getPI120(4)] : phase,
    cObj.width = typeof width === 'undefined' ? 127 : width,
    cObj.center = typeof center === 'undefined' ? 128 : center;
    if (!(cObj.freq instanceof Array)) cObj.freq = new Array(cObj.freq, cObj.freq, cObj.freq);
    if (!(cObj.phase instanceof Array)) cObj.phase = new Array(cObj.phase, cObj.phase, cObj.phase);
    return cObj;
  },
  createRainbowArray: function(cObj) {
    var rA = [],
      fR = this.getFixedRainbow(cObj);
    for (var i = 0; i < cObj.len; i++) {
      rA.push(this.objToRGBToHash(fR(i)));
    }
    return rA;
  },
  createRainbowArrayForRobocraft: function(cObj) {
    var rA = [],
      fR = this.getFixedRainbow(cObj);
    for (var i = 0; i < cObj.len; i++) {
      rA.push(this.objToRGBToBrackets(fR(i)));
    }
    return rA;
  },
  createRainbowArrayForBBCode: function(cObj) {
    var rA = [],
      fR = this.getFixedRainbow(cObj);
    for (var i = 0; i < cObj.len; i++) {
      rA.push("[color="+this.objToRGBToHash(fR(i))+"]");
    }
    return rA;
  }
};

var rainbowFy = function(str, phase, isBbcode) {
  var newStr = "",
    str = str,
    phase = phase || [4, 0, 2],
    rainbowArray;
    
    if (!isBbcode){
      rainbowArray = LL.Rainbow.createRainbowArrayForRobocraft(LL.Rainbow.createComponents(str.length, undefined, phase));
    }
    else {
      rainbowArray = LL.Rainbow.createRainbowArrayForBBCode(LL.Rainbow.createComponents(str.length, undefined, phase));
    }
    

  for (var i = 0, max = str.length; i < max; i++) {
    if (str.substr(i, 1) === " ") {
      newStr += " ";
    } else {
      newStr += "" + rainbowArray[i] + str.substr(i, 1);
      if(isBbcode) newStr += "[/color]"
    }

  }

  return newStr;
};

var previewText = function(str) {

  var len = str.length,
    imlazyLeaveMeAlone = LL.Rainbow.createRainbowArray(LL.Rainbow.createComponents(len, undefined, [4, 0, 2]));
    lamePreviewArray = [];

  for (var i = 0; i < len; i++) {
    lamePreviewArray.push({
      char: str[i],
      hash: imlazyLeaveMeAlone[i]
    })
  }

  return lamePreviewArray;
}



LL.app = angular.module('rainbowRoboApp', [])
  .controller('basicController', ['$scope',
    function($scope) {

      $scope.basicModels = {};
      $scope.basicModels.mainInput = 'R A I N B O W S';
      $scope.basicModels.maxChars = 0;
      $scope.basicModels.previewTextArray = previewText('R A I N B O W S');

      $scope.$watch('basicModels.mainInput', function() {
        $scope.basicModels.mainOutput = rainbowFy($scope.basicModels.mainInput);
        $scope.basicModels.bbcodeOutput = rainbowFy($scope.basicModels.mainInput, undefined, true);
        $scope.basicModels.maxChars = rainbowFy($scope.basicModels.mainInput).length;
        $scope.basicModels.previewTextArray = previewText($scope.basicModels.mainInput);
      });


    }
  ])
  .filter('rainbowify', [
    function() {
      return function(input, $scope) {
        return rainbowFy(input);
      }
    }
  ]);

$(document).on('click', '.selectable', function() {
  this.setSelectionRange(0, this.value.length);
});
/* Styles go here */

input{ width: 100%; height:30px; }
.rainbow-output { width:100%; border: 1px solid #ccc;}
.lame-preview-attempt b{ font-size:24px; text-shadow: 0 0 2px rgba(0,0,0,0.3); }

.idnolol {display:block; width:100%; height:30px;}
.idnolol .block{display:inline; float: left; height: 30px;}