       ns.join ','
     ls.join '\n'
 
-  # only for text nodes and BR (BR only comes from Chrome)
-  getNodePos: (nodeLines, selNode, offset) ->
-    # console.log selNode, offset
-    # offset is either position in text, or nr of BR child in parent node (which gets offset 0)
+  ###*
+   * Convert node-based position to row/column-based position. End of line can be represented
+   * by a right-most offset on the last text node on the line, or the index of the <BR> node on
+   * the line (Chrome)
+   *
+   * @param  {Node[][]} nodeLines  Node lines for the content-editable tree
+   * @param  {Number}   baseNode   Base node for the selection
+   * @param  {Number}   offset     Offset in node
+   * @return {Point}    The row and column for the selected node in content-editable text
+  ###
+  getNodePos: (nodeLines, baseNode, offset) ->
+    console.log 'NODELINES\n' + @showNodeLines nodeLines
     [baseNode, nodeOffset] =
-      switch selNode.nodeType
-        when Node.TEXT_NODE
-          [selNode, offset]
-        when Node.ELEMENT_NODE
-          # console.log 'Element node, offset: '+offset
-          # console.log node
-          # console.log node.childNodes[offset]
-          [selNode.childNodes[offset], 0]
+      switch
+        when baseNode.nodeType == Node.TEXT_NODE
+          # offset is position in text node
+          [baseNode, offset]
+        when baseNode.nodeType == Node.ELEMENT_NODE
+          # offset is index of <BR> child in parent node (which gets offset 0)
+          [baseNode.childNodes[offset], 0]
         else
-          console.error 'getNodePos: unhandled node type or tagName: ' + selNode.nodeType + ' & ' + selNode.tagName
+          console.error 'getNodePos: unhandled baseNode nodeType: ' + baseNode.nodeType
+          null
+
     for line, lineNr in nodeLines
       ix = line.indexOf baseNode
       if ix >= 0
         precedingNodes = line.slice 0, ix
         precedingLength = 0
         for n in precedingNodes
-          # TODO: check node type?
-          precedingLength += n.textContent.length
-        return [lineNr, precedingLength + nodeOffset]
+          if n.nodeType == Node.TEXT_NODE
+            precedingLength += n.textContent.length
+          else
+            console.error 'getNodePos: unhandled node type ' + node.nodeType
+        return new Point(lineNr, precedingLength + nodeOffset)
     return null
 
-  getSelectionPoss: ->
+  ###*
+   * Convert row/column-based position to node based-position
+   *
+   * @param  {Node[][]} nodeLines Node lines for the content-editable tree
+   * @param {Point}     pos       Position in the content-editable text
+   * @return {{node: Node, offset: number}}  Node and offset corresponding to pos
+  ###
+  getNodeAndOffsetForPos: (nodeLines, pos) ->
+    {row: rowNr, column: colNr} = Point.fromObj pos
+    nodeLine = nodeLines[rowNr]
+    textNodes = _.where nodeLine, {nodeType: Node.TEXT_NODE}
+    if textNodes.length > 0
+      relativeCol = colNr
+      for node in nodeLine
+        textLen = node.textContent.length
+        if relativeCol <= textLen
+          return {node: node, offset: relativeCol} # somewhere in a text node
+        else
+          relativeCol -= textLen
+      lastTextNode = _.last textNodes
+      return {node: lastTextNode, offset: lastTextNode.length} # beyond the last text node
+
+    else
+      brNode = nodeLine?[0]
+      if brNode?
+        return {node: brNode, offset: 0} # no text nodes, so return <BR> node with offset 0
+      else
+        console.error 'getNodeAndOffsetForPos: line not terminated by <BR>'
+        return null
+
+  getSelectionRange: ->
     sel = window.getSelection()
     nodeLines = @getNodeLines()
     # console.dir nodeLines
     anchorPos = @getNodePos nodeLines, sel.anchorNode, sel.anchorOffset
     focusPos  = @getNodePos nodeLines, sel.focusNode,  sel.focusOffset
     if anchorPos? and focusPos?
-      # Return ordered selection
-      if anchorPos[0] < focusPos[0] || anchorPos[0] == focusPos[0] && anchorPos[1] <= focusPos[1]
-        [anchorPos, focusPos]
+      # Always return lexicographicaly ordered selection (ie. start is before end)
+      if anchorPos.row < focusPos.row ||
+         anchorPos.row == focusPos.row && anchorPos.column <= focusPos.column
+        new Range(anchorPos, focusPos)
       else
-        [focusPos, anchorPos]
+        new Range(focusPos, anchorPos)
     else
       # if any of the selection points is not in the editable div, return empty selection at [0,0]
-      [[0,0], [0,0]]
-
-  setDocSelection: (startNode, startOffset, endNode, endOffset) ->
+      new Range([0,0], [0,0])
+
+
+  getText: ->
+    textLines =
+      for nodeLine in @getNodeLines()
+        _.map nodeLine, (n) -> if n.nodeType == Node.TEXT_NODE then n.textContent else ''
+          .join('')
+    textLines.join('\n')
+
+  setText: (txt) ->
+    @$editableDiv.empty()
+    for line in txt.split '\n'
+      lineDiv = $('<div>').text line
+      @$editableDiv.append lineDiv
+
+class Buffer
+  textManager: null
+
+  constructor: ($editableDiv) ->
+    @textManager = new TextManager($editableDiv)
+
+  getText: ->
+    @textManager.getText()
+
+  setText: (txt) ->
+    @textManager.setText txt
+
+  getSelectionRange: ->
+    @textManager.getSelectionRange()
+
+  setSelectionRange: (range) ->
+    range = Range.fromObj(range)
+    nodeLines = @textManager.getNodeLines()
+
+    {node: startNode, offset: startOffset} = @textManager.getNodeAndOffsetForPos nodeLines, range.start
+    {node: endNode,   offset: endOffset}   = @textManager.getNodeAndOffsetForPos nodeLines, range.end
+
     docRange = document.createRange()
     winSelection = window.getSelection()
     docRange.setStart startNode, startOffset

    @setSelectionRange(range)
    # TODO: move to TextManager
    if text != ''
      try # Firefox sometime throws exceptions on inserting '\n', even if we fist call delete, so we need to ignore this :-(
        document.execCommand 'insertText', false, text
      catch
    else

    if currentLine.length > 0
      nodeLines.push currentLine
      currentLine = []
    nodeLines

  showNodeLines: (nodeLines) ->
