import { platform } from 'substance'

export default class SurfaceManager {
  constructor (editorState) {
    this.editorState = editorState
    this.surfaces = {}

    editorState.addObserver(['selection'], this._onSelectionChange, this, { stage: 'post-render' })
    editorState.addObserver(['selection', 'document'], this._recoverDOMSelection, this, { stage: 'post-render' })
    editorState.addObserver(['selection', 'document'], this._scrollSelectionIntoView, this, { stage: 'finalize' })
  }

  dispose () {
    this.editorState.off(this)
  }

  getSurface (name) {
    if (name) {
      return this.surfaces[name]
    }
  }

  getFocusedSurface () {
    console.error("DEPRECATED: use 'context.editorState.focusedSurface instead")
    return this.editorState.focusedSurface
  }

  registerSurface (surface) {
    const id = surface.getId()
    if (this.surfaces[id]) {
      console.error(`A surface with id ${id} has already been registered.`)
    }
    this.surfaces[id] = surface
  }

  unregisterSurface (surface) {
    let surfaceId = surface.getId()
    let registeredSurface = this.surfaces[surfaceId]
    if (registeredSurface === surface) {
      delete this.surfaces[surfaceId]
    }
  }

  _onSelectionChange () {
    // console.log('SurfaceManager._onSelectionChange()')
    const selection = this.editorState.selection
    // update state.focusedSurface
    this._reduceFocusedSurface(selection)
    // HACK: removing DOM selection *and* blurring when having a CustomSelection
    // otherwise we will receive events on the wrong surface
    // instead of bubbling up to GlobalEventManager
    if (selection && selection.isCustomSelection() && platform.inBrowser) {
      window.getSelection().removeAllRanges()
      window.document.activeElement.blur()
    }
  }

  _reduceFocusedSurface (sel) {
    const editorState = this.editorState
    let surface = null
    if (sel && sel.surfaceId) {
      surface = this.surfaces[sel.surfaceId]
    }
    editorState.focusedSurface = surface
  }

  /*
    At the end of the update flow, make sure the surface is focused
    and displays the right DOM selection
  */
  _recoverDOMSelection () {
    // console.log('SurfaceManager._recoverDOMSelection()')
    const editorState = this.editorState
    // do not rerender the selection if the editorSession has
    // been blurred, e.g., while some component, such as Find-And-Replace
    // dialog has the focus
    if (editorState.isBlurred) return
    let focusedSurface = editorState.focusedSurface
    // console.log('focusedSurface', focusedSurface)
    if (focusedSurface && !focusedSurface.isDisabled()) {
      // console.log('Rendering selection on surface', focusedSurface.getId(), this.editorSession.getSelection().toString());
      focusedSurface._focus()
      focusedSurface.rerenderDOMSelection()
    } else {
      // NOTE: Tried to add an integrity check here
      // for valid sel.surfaceId
      // However this is problematic, when an editor
      // is run headless, i.e. when there are no surfaces rendered
      // On the long run we should separate these to modes
      // more explicitly. For now, any code using surfaces need
      // to be aware of the fact, that this might be not availabls
      // while in the model it is referenced.
    }
  }

  _scrollSelectionIntoView () {
    const editorState = this.editorState
    let focusedSurface = editorState.focusedSurface
    if (focusedSurface && !focusedSurface.isDisabled()) {
      focusedSurface.send('scrollSelectionIntoView')
    }
  }
}

@@ -202,148 +202,56 @@
 ion'
-%5D, this._onSelectionChange, this, %7B stage: 'post-render' %7D)%0A    editorState.addObserver(%5B'selection', 'document'%5D, this._recoverDOMSelection
+, 'document'%5D, this._onSelectionOrDocumentChange
 , th
@@ -1117,24 +1117,34 @@
 _onSelection
+OrDocument
 Change () %7B%0A
@@ -1197,24 +1197,145 @@
 nChange()')%0A
+%0A    // Reducing state.focusedSurface (only if selection has changed)%0A    if (this.editorState.isDirty('selection')) %7B%0A  
     const se
@@ -1375,16 +1375,18 @@
 ion%0A    
+ 
+ 
 // updat
@@ -1404,24 +1404,26 @@
 usedSurface%0A
+  
     this._re
@@ -1452,16 +1452,18 @@
 ection)%0A
+  
     // H
@@ -1539,16 +1539,18 @@
 ion%0A    
+  
 // other
@@ -1594,24 +1594,26 @@
 ong surface%0A
+  
     // inste
@@ -1652,24 +1652,26 @@
 Manager%0A    
+  
 if (selectio
@@ -1732,24 +1732,26 @@
 er) %7B%0A      
+  
 window.getSe
@@ -1780,24 +1780,26 @@
 ges()%0A      
+ 
+ 
 window.docum
@@ -1823,25 +1823,185 @@
 .blur()%0A    
-%7D
+  %7D%0A    %7D%0A%0A    // TODO: this still needs to be improved. The DOM selection can be affected by other updates than document changes%0A    this._recoverDOMSelection()
 %0A  %7D%0A%0A  _red

Fix regression in SurfaceManager