text: /* ***** BEGIN LICENSE BLOCK *****
   * Distributed under the BSD license:
   *
   * Copyright (c) 2010, Ajax.org B.V.
   * All rights reserved.
   * 
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are met:
   *     * Redistributions of source code must retain the above copyright
   *       notice, this list of conditions and the following disclaimer.
   *     * Redistributions in binary form must reproduce the above copyright
   *       notice, this list of conditions and the following disclaimer in the
   *       documentation and/or other materials provided with the distribution.
   *     * Neither the name of Ajax.org B.V. nor the
   *       names of its contributors may be used to endorse or promote products
   *       derived from this software without specific prior written permission.
   * 
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
   * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   * ***** END LICENSE BLOCK ***** */
  
  define(function(require, exports, module) {
  "use strict";
  
  var dom = require("../lib/dom");
  var oop = require("../lib/oop");
  var EventEmitter = require("../lib/event_emitter").EventEmitter;
  
  var Gutter = function(parentEl) {
      this.element = dom.createElement("div");
      this.element.className = "ace_layer ace_gutter-layer";
      parentEl.appendChild(this.element);
      this.setShowFoldWidgets(this.$showFoldWidgets);
      
      this.gutterWidth = 0;
  
      this.$annotations = [];
  };
  
  (function() {
  
      oop.implement(this, EventEmitter);
      
      this.setSession = function(session) {
          this.session = session;
      };
  
      this.addGutterDecoration = function(row, className){
          if (window.console)
              console.warn && console.warn("deprecated use session.addGutterDecoration");
          this.session.addGutterDecoration(row, className);
      };
  
      this.removeGutterDecoration = function(row, className){
          if (window.console)
              console.warn && console.warn("deprecated use session.removeGutterDecoration");
          this.session.removeGutterDecoration(row, className);
      };
  
      this.setAnnotations = function(annotations) {
          // iterate over sparse array
          this.$annotations = [];
          for (var row in annotations) if (annotations.hasOwnProperty(row)) {
              var rowAnnotations = annotations[row];
              if (!rowAnnotations)
                  continue;
  
              var rowInfo = this.$annotations[row] = {
                  text: []
              };
              for (var i=0; i<rowAnnotations.length; i++) {
                  var annotation = rowAnnotations[i];
                  var annoText = annotation.text.replace(/"/g, "&quot;").replace(/'/g, "&#8217;").replace(/</, "&lt;");
                  if (rowInfo.text.indexOf(annoText) === -1)
                      rowInfo.text.push(annoText);
                  var type = annotation.type;
                  if (type == "error")
                      rowInfo.className = " ace_error";
                  else if (type == "warning" && rowInfo.className != " ace_error")
                      rowInfo.className = " ace_warning";
                  else if (type == "info" && (!rowInfo.className))
                      rowInfo.className = " ace_info";
              }
          }
      };
  
      this.update = function(config) {
          var emptyAnno = {className: ""};
          var html = [];
          var i = config.firstRow;
          var lastRow = config.lastRow;
          var fold = this.session.getNextFoldLine(i);
          var foldStart = fold ? fold.start.row : Infinity;
          var foldWidgets = this.$showFoldWidgets && this.session.foldWidgets;
          var breakpoints = this.session.$breakpoints;
          var decorations = this.session.$decorations;
          var lastLineNumber = 0;
  
          while (true) {
              if(i > foldStart) {
                  i = fold.end.row + 1;
                  fold = this.session.getNextFoldLine(i, fold);
                  foldStart = fold ?fold.start.row :Infinity;
              }
              if(i > lastRow)
                  break;
  
              var annotation = this.$annotations[i] || emptyAnno;
              html.push(
                  "<div class='ace_gutter-cell ",
                  breakpoints[i] || "", decorations[i] || "", annotation.className,
                  "' style='height:", this.session.getRowLength(i) * config.lineHeight, "px;'>", 
                  lastLineNumber = i + 1
              );
  
              if (foldWidgets) {
                  var c = foldWidgets[i];
                  // check if cached value is invalidated and we need to recompute
                  if (c == null)
                      c = foldWidgets[i] = this.session.getFoldWidget(i);
                  if (c)
                      html.push(
                          "<span class='ace_fold-widget ", c,
                          c == "start" && i == foldStart && i < fold.end.row ? " closed" : " open",
                          "' style='height:", config.lineHeight, "px",
                          "'></span>"
                      );
              }
  
              html.push("</div>");
  
              i++;
          }
  
          this.element = dom.setInnerHtml(this.element, html.join(""));
          this.element.style.height = config.minHeight + "px";
          
          if (this.session.$useWrapMode)
              lastLineNumber = this.session.getLength();
          
          var gutterWidth = ("" + lastLineNumber).length * config.characterWidth;
          var padding = this.$padding || this.$computePadding();
          gutterWidth += padding.left + padding.right;
          if (gutterWidth !== this.gutterWidth) {
              this.gutterWidth = gutterWidth;
              this.element.style.width = Math.ceil(this.gutterWidth) + "px";
              this._emit("changeGutterWidth", gutterWidth);
          }
      };
  
      this.$showFoldWidgets = true;
      this.setShowFoldWidgets = function(show) {
          if (show)
              dom.addCssClass(this.element, "ace_folding-enabled");
          else
              dom.removeCssClass(this.element, "ace_folding-enabled");
  
          this.$showFoldWidgets = show;
          this.$padding = null;
      };
      
      this.getShowFoldWidgets = function() {
          return this.$showFoldWidgets;
      };
  
      this.$computePadding = function() {
          if (!this.element.firstChild)
              return {left: 0, right: 0};
          var style = dom.computedStyle(this.element.firstChild);
          this.$padding = {}
          this.$padding.left = parseInt(style.paddingLeft) + 1;
          this.$padding.right = parseInt(style.paddingRight);  
          return this.$padding;
      };
  
      this.getRegion = function(point) {
          var padding = this.$padding || this.$computePadding();
          var rect = this.element.getBoundingClientRect();
          if (point.x < padding.left + rect.left)
              return "markers";
          if (this.$showFoldWidgets && point.x > rect.right - padding.right)
              return "foldWidgets";
      };
  
  }).call(Gutter.prototype);
  
  exports.Gutter = Gutter;
  
  });
  