/*-
 * $Id: creepy.js,v 1.22 2008/06/16 15:29:52 justme Exp $
 *
 * Copyright (c) 2007 by Aparzev GmbH (http://www.aparzev.com).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

var ENUM_TO_HTML = {"fontWeight":{"NORMAL":"normal","BOLD":"bold"},"fontStyle":{"NORMAL":"normal","ITALIC":"italic"},"textDecoration":{"OVERLINE":"overline","UNDERLINE":"underline","BLINK":"blink","NONE":"none","LINE_THROUGH":"line-through"},"fontVariant":{"NORMAL":"normal","SMALLCAPS":"small-caps"},"textTransform":{"UPPERCASE":"uppercase","CAPITALIZE":"capitalize","NONE":"none","LOWERCASE":"lowercase"},"fontFamily":{"MONO":"'Courier New', Courier, mono","SERIF":"'Times New Roman', Times, Serif","SANSSERIF":"Arial, Helvetica, Lucida, 'Sans Serif'","VERDANA":"Verdana, Lucida, Arial, Helvetica, 'Sans Serif'"}};

var CSS_UNIT_TO_HTML = {"INCH":"in","PERCENT":"%","PIXEL":"px","CENTIMETER":"cm","POINT":"pt","EM":"em","EX":"ex","MILLIMETER":"mm"}

var TRANSLATE = {

    TO_JAVASCRIPT : {
        "font-family"      : "fontFamily",
        "font-size"        : "fontSize",
        "font-weight"      : "fontWeight",
        "font-style"       : "fontStyle",
        "font-variant"     : "fontVariant",
        "text-decoration"  : "textDecoration",
        "text-transform"   : "textTransform",
        "letter-spacing"   : "letterSpacing",
        "color"            : "color",
        "background-color" : "backgroundColor",
        "background-image" : "backgroundImage",
        "margin-top"       : "marginTop",
        "margin-bottom"    : "marginBottom",
        "margin-left"      : "marginLeft",
        "margin-right"     : "marginRight",
        "padding-top"      : "paddingTop",
        "padding-bottom"   : "paddingBottom",
        "padding-left"     : "paddingLeft",
        "padding-right"    : "paddingRight"
    },

    TO_HTML : {
        "fontFamily"       : "font-family",
        "fontSize"         : "font-size",
        "fontWeight"       : "font-weight",
        "fontStyle"        : "font-style",
        "fontVariant"      : "font-variant",
        "textDecoration"   : "text-decoration",
        "textTransform"    : "text-transform",
        "letterSpacing"    : "letter-spacing",
        "color"            : "color",
        "backgroundColor"  : "background-color",
        "backgroundImage"  : "background-image",
        "borderTop"        : "border-top",
        "borderBottom"     : "border-bottom",
        "borderLeft"       : "border-left",
        "borderRight"      : "border-right",
        "marginTop"        : "margin-top",
        "marginBottom"     : "margin-bottom",
        "marginLeft"       : "margin-left",
        "marginRight"      : "margin-right",
        "paddingTop"       : "padding-top",
        "paddingBottom"    : "padding-bottom",
        "paddingLeft"      : "padding-left",
        "paddingRight"     : "padding-right",
        "lineHeight"       : "line-height"
    },

    toJavascript : function(value) {
        return this.TO_JAVASCRIPT[value];
    },

    toHTML : function(value) {
        return this.TO_HTML[value];
    }
}

function Creepy(splittingStrategy, textAlign) {
    this.splittingStrategy = splittingStrategy;
    this.textAlign = textAlign || "center"; // hack for downward compatibility
    this.policies = [];
    this.errors = [];
}

Creepy.prototype.addPolicy = function(policy) {

  this.policies.push(policy);
}

Creepy.prototype.getTextAlign = function() {

  return this.textAlign;
}

Creepy.prototype.processText = function(content) {

    var items = this.splittingStrategy.split(content);
    var innerHTML = "";

    for(var i = 0; i < items.length; i++) {

        var item = items[i];

        if(item == "\n" || item == "<br />" || item == "<br/>") {
          //alert("Line break found");
          innerHTML += "<br />";
          continue;
        }

        if(item == " ") {
          //alert("Empty space found");
          item = "&#160;";
        }

        var styleChunk = "";

        for(var j = 0; j < this.policies.length; j++) {

            var policy = this.policies[j];

            if(policy.isEmpty() || policy.isHomogenous()) {
                continue;
            }

            styleChunk += this.appendStyle(policy);
        }

        if(styleChunk.length > 0) {
           innerHTML += '<span style="' + styleChunk + '">' + item + '</span>';
        } else {
           innerHTML += item;
        }
    }

    //alert(innerHTML);
    return innerHTML;
}

Creepy.prototype.appendHomogenous = function(containter) {

    var style = containter.style;

    for(var j = 0; j < this.policies.length; j++) {

        var policy = this.policies[j];

        if(policy.isEmpty() || !policy.isHomogenous()) {
            continue;
        }

        style[policy.getName()] = policy.getValue();
    }
}

Creepy.prototype.appendStyle = function(policy) {

    var styleChunk = "";

    var translated = TRANSLATE.toHTML(policy.getName());

    if(translated == null) {
        throw new Error("Property " + policy.getName() + " cannot be translated");
    }

    var value = policy.getValue();

    styleChunk +=  translated + ":" + policy.getValue() + ";";

    return styleChunk;
}

Creepy.prototype.process = function(elem) {

    if(elem == null) {
      throw new Error("Element not found!");
    }

    elem.style.cssText = "";
    elem.style.textAlign = this.textAlign;
    this.appendHomogenous(elem);

    var content = elem.innerHTML;
    elem.innerHTML = "";

    var processed = this.processText(content);
    elem.innerHTML = processed;
}

Creepy.prototype.getErrors = function() {
  return this.errors.join("\n");
}

Creepy.prototype.getErrorsCount = function() {
  return this.errors.length;
}

/**********************************************************************
 *                            Strategies                              *
 **********************************************************************/

var CreepyStrategy = Class.create();

CreepyStrategy.prototype = {

  initialize: function(property, value) {

    if(property == null) {
        throw new Error("Property name must not be undefined");
    }

    this.property = property;
    this.value = value;
    this.empty = false;
    this.checkValue();
  },

  getName : function() {
    return this.property;
  },

  toString : function () {
    return this.property + " -> " + this.value;
  },

  isEmpty : function () {
    return this.empty;
  }
}

var CreepyValues = Class.create();

CreepyValues.prototype = {

  checkValue : function() {
    if(this.value.length == 0) {
      this.empty = true;
    }
  },

  isHomogenous : function() {
    return this.value.length == 1 && this.property != "backgroundColor";
  },

  getValue : function() {

    var random = new RandomRange(0, this.value.length - 1);
    var rand = random.next();
    if(rand >= this.value.length) {
        throw new Error(rand + " >= " + this.value.length);
    }
    return this.value[rand];
  }
}

Object.extend(CreepyValues.prototype, CreepyStrategy.prototype);

// Creepy policy

var CreepyValuesRef = Class.create();

CreepyValuesRef.prototype = {

  checkValue : function() {
    if(this.value.length == 0) {
      this.empty = true;
    }
  },

  isHomogenous : function() {

    return this.value.length == 1 && this.property != "backgroundColor";
  },

  getValue : function() {

    if(this.empty) {
      return null;
    }

    var length = this.value.length;
    var random = new RandomRange(0, length - 1);
    var rand = random.next();

    if(rand >= length) {
        throw new Error(rand + " >= " + length);
    }

    var index = this.value[rand];
    var ref = creepyReference[this.property].value;

    if(ref == null) {
        throw new Error("Property " + this.property + " not found in the styles catalogue");
    }

    if(index >= ref.length) {
        throw new Error("Array index out of bounds for property " + property + ": index: " + index + ", size: " + ref.length);
    }

    var ret = ref[index]

    if(ret == null) {
        throw new Error("No value of " + this.property + " found at index " + index + ", avaliable: " + ref.join(","));
    }

    return ret;
  }
}

Object.extend(CreepyValuesRef.prototype, CreepyStrategy.prototype);

var CreepyRange = Class.create();

CreepyRange.prototype = {

  checkValue : function() {
    return;
  },

  isHomogenous : function() {
    var range = this.value;
    return range.min == range.max && this.property != "backgroundColor";
  },

  getValue : function() {
    var range = this.value;
    var random = new RandomRange(range.min, range.max);
    var next = random.next();
    return random.next() + range.unit;
  }
}

Object.extend(CreepyRange.prototype, CreepyStrategy.prototype);

/**********************************************************************
 *                          Style Appenders                           *
 **********************************************************************/

var StyleAppender = Class.create();

StyleAppender.prototype = {

  initialize : function(container) {
    this.container = container;
  }
}

var HtmlStyleAppender = Class.create();

HtmlStyleAppender.prototype = {

  processText : function(items, policies) {

    var innerHTML = "";

    for(var i = 0; i < items.length; i++) {

        var item = items[i];

        if(item == "\n" || item == "<br />" || item == "<br/>") {
          //alert("Line break found");
          innerHTML += "<br />";
          continue;
        }

        var styleChunk = "";

        for(var j = 0; j < this.policies.length; j++) {

            var policy = this.policies[j];

            if(policy.isEmpty() || policy.isHomogenous()) {
                continue;
            }

            styleChunk += this.appendStyle(policy);
        }

        if(styleChunk.length > 0) {
           innerHTML += '<span style="' + styleChunk + '">' + item + '</span>';
        } else {
           innerHTML += item;
        }
    }

    this.container.innerHTML = innerHTML;
  }
}

Object.extend(HtmlStyleAppender.prototype, StyleAppender.prototype);

var JsStyleAppender = Class.create();

JsStyleAppender.prototype = {

  processText : function(items, policies) {

    var style = this.containter.style;

    for(var i = 0; i < items.length; i++) {

        var item = items[i];

        if(item == "\n" || item == "<br />" || item == "<br/>") {
          //alert("Line break found");
          innerHTML += "<br />";
          continue;
        }

        var styleChunk = "";

        for(var j = 0; j < this.policies.length; j++) {

            var policy = this.policies[j];

            if(policy.isEmpty() || policy.isHomogenous()) {
                continue;
            }

            styleChunk += this.appendStyle(policy);
        }

        if(styleChunk.length > 0) {
           innerHTML += '<span style="' + styleChunk + '">' + item + '</span>';
        } else {
           innerHTML += item;
        }
    }

    container.innerHTML = innerHTML;
  }
}

Object.extend(JsStyleAppender.prototype, StyleAppender.prototype);

/**********************************************************************
 *                            Splitter                                *
 **********************************************************************/

function TextSplitterByWord() {

}

TextSplitterByWord.prototype.split = function(text) {

  var result = [];
  var lines = text.split(/\n|<br *\/*>/i); /**/

  for(var i = 0; i < lines.length; i++) {

    var line = lines[i];
    var words = line.split(" ");

    for(var j = 0; j < words.length; j++) {

      result.push(words[j]);
      result.push(" ");
    }
    result.pop();
    result.push("<br />");
  }

  return result;
}

function TextSplitterByLetter() {

}

TextSplitterByLetter.prototype.split = function(text) {

  var result = [];
  var lines = text.split(/\n|<br *\/*>/i); /**/
  //alert(lines.length);

  for(var i = 0; i < lines.length; i++) {

    var line = lines[i];

      var letters = line.split('');

      for(var k = 0; k < letters.length; k++) {

        result.push(letters[k]);
        //if(letters[k] == "<") {
        //  alert("Found unescaped tag - check your code:\n" + line);
        //}

    }

    result.push("<br />");
  }

  return result;

}

function TextSplitterByEveryNLetter(every) {
  this.every = every;
}

TextSplitterByEveryNLetter.prototype.split = function(text) {

  var ret = [];

  var count = text.length / this.every;

  for(var i = 0; i < count; i++) {
    var fromText = i * this.every;
    var fromLetter = fromText + this.every;
    var untilText = fromLetter - 1;
    var untilLetter = fromLetter;
    ret.push(text.substring(fromText, untilText));
    ret.push(text.substring(fromLetter, untilLetter));
  }
}

var SplittingStrategy = {

  newStrategy : function(type) {

      if(type == "LETTER") {
        return new TextSplitterByLetter();
      }

      if(type == "WORD") {
        return new TextSplitterByWord();
      }

      if(type == "LETTERS") {
        return new TextSplitterByEveryNLetter();
      }

      throw new Error("No such strategy: " + type);
  }
};
