ace.define("ace/ext/rtl", ["require", "exports", "module", "ace/editor", "ace/config"], function (require, exports, module) {
  "use strict";

  var commands = [{
    name: "leftToRight",
    bindKey: {
      win: "Ctrl-Alt-Shift-L",
      mac: "Command-Alt-Shift-L"
    },
    exec: function exec(editor) {
      editor.session.$bidiHandler.setRtlDirection(editor, false);
    },
    readOnly: true
  }, {
    name: "rightToLeft",
    bindKey: {
      win: "Ctrl-Alt-Shift-R",
      mac: "Command-Alt-Shift-R"
    },
    exec: function exec(editor) {
      editor.session.$bidiHandler.setRtlDirection(editor, true);
    },
    readOnly: true
  }];

  var Editor = require("../editor").Editor;

  require("../config").defineOptions(Editor.prototype, "editor", {
    rtlText: {
      set: function set(val) {
        if (val) {
          this.on("change", onChange);
          this.on("changeSelection", onChangeSelection);
          this.renderer.on("afterRender", updateLineDirection);
          this.commands.on("exec", onCommandEmitted);
          this.commands.addCommands(commands);
        } else {
          this.off("change", onChange);
          this.off("changeSelection", onChangeSelection);
          this.renderer.off("afterRender", updateLineDirection);
          this.commands.off("exec", onCommandEmitted);
          this.commands.removeCommands(commands);
          clearTextLayer(this.renderer);
        }

        this.renderer.updateFull();
      }
    },
    rtl: {
      set: function set(val) {
        this.session.$bidiHandler.$isRtl = val;

        if (val) {
          this.setOption("rtlText", false);
          this.renderer.on("afterRender", updateLineDirection);
          this.session.$bidiHandler.seenBidi = true;
        } else {
          this.renderer.off("afterRender", updateLineDirection);
          clearTextLayer(this.renderer);
        }

        this.renderer.updateFull();
      }
    }
  });

  function onChangeSelection(e, editor) {
    var lead = editor.getSelection().lead;

    if (editor.session.$bidiHandler.isRtlLine(lead.row)) {
      if (lead.column === 0) {
        if (editor.session.$bidiHandler.isMoveLeftOperation && lead.row > 0) {
          editor.getSelection().moveCursorTo(lead.row - 1, editor.session.getLine(lead.row - 1).length);
        } else {
          if (editor.getSelection().isEmpty()) lead.column += 1;else lead.setPosition(lead.row, lead.column + 1);
        }
      }
    }
  }

  function onCommandEmitted(commadEvent) {
    commadEvent.editor.session.$bidiHandler.isMoveLeftOperation = /gotoleft|selectleft|backspace|removewordleft/.test(commadEvent.command.name);
  }

  function onChange(delta, editor) {
    var session = editor.session;
    session.$bidiHandler.currentRow = null;

    if (session.$bidiHandler.isRtlLine(delta.start.row) && delta.action === 'insert' && delta.lines.length > 1) {
      for (var row = delta.start.row; row < delta.end.row; row++) {
        if (session.getLine(row + 1).charAt(0) !== session.$bidiHandler.RLE) session.doc.$lines[row + 1] = session.$bidiHandler.RLE + session.getLine(row + 1);
      }
    }
  }

  function updateLineDirection(e, renderer) {
    var session = renderer.session;
    var $bidiHandler = session.$bidiHandler;
    var cells = renderer.$textLayer.$lines.cells;
    var width = renderer.layerConfig.width - renderer.layerConfig.padding + "px";
    cells.forEach(function (cell) {
      var style = cell.element.style;

      if ($bidiHandler && $bidiHandler.isRtlLine(cell.row)) {
        style.direction = "rtl";
        style.textAlign = "right";
        style.width = width;
      } else {
        style.direction = "";
        style.textAlign = "";
        style.width = "";
      }
    });
  }

  function clearTextLayer(renderer) {
    var lines = renderer.$textLayer.$lines;
    lines.cells.forEach(clear);
    lines.cellCache.forEach(clear);

    function clear(cell) {
      var style = cell.element.style;
      style.direction = style.textAlign = style.width = "";
    }
  }
});

(function () {
  ace.require(["ace/ext/rtl"], function (m) {
    if (typeof module == "object" && typeof exports == "object" && module) {
      module.exports = m;
    }
  });
})();