       bubble.appendChild Message.fromMessage(trace, addPath: true)
     bubble
 
-  _renderPanel: ->
-    @_panel.innerHTML = ''
-    @_removeMarkers()
-    @_removeBubble()
-    if not @_messages.size
+  renderPanel: ->
+    @panel.innerHTML = ''
+    @removeMarkers()
+    @removeBubble()
+    if not @messages.size
       return @setPanelVisibility(false)
     @setPanelVisibility(true)
     activeEditor = atom.workspace.getActiveTextEditor()
-    @_messages.forEach (message) =>
-      if @_scope is 'file' then return unless message.currentFile
-      if @_underlineIssues and message.currentFile and message.range #Add the decorations to the current TextEditor
-        @_markers.push marker = activeEditor.markBufferRange message.range, {invalidate: 'never'}
+    @messages.forEach (message) =>
+      if @scope is 'file' then return unless message.currentFile
+      if @underlineIssues and message.currentFile and message.range #Add the decorations to the current TextEditor
+        @markers.push marker = activeEditor.markBufferRange message.range, {invalidate: 'never'}
         activeEditor.decorateMarker(
           marker, type: 'line-number', class: "linter-highlight #{message.class}"
         )

          marker, type: 'highlight', class: "linter-highlight #{message.class}"
        )

      if @_scope is 'line'
        return if @_lineMessages.indexOf(message) is -1

      Element = Message.fromMessage(message, addPath: @_scope is 'project', cloneNode: true)

      @_panel.appendChild Element
    @updateBubble()


  _removeMarkers: ->
    return unless @_markers.length
    for marker in @_markers
      try marker.destroy()
    @_markers = []

  # This method is called in render, and classifies the messages according to scope
  _extractMessages: (Gen, counts) ->
    isProject = @_scope is 'project'
    activeEditor = atom.workspace.getActiveTextEditor()
    activeFile = activeEditor?.getPath()
    Gen.forEach (Entry) =>


class LinterViews
  constructor: (@linter) ->
    @showPanel = true # Altered by config observer in linter-plus
    @showBubble = true # Altered by the config observer in linter-plus
    @underlineIssues = true # Altered by config observer in linter-plus

    @messages = new Set
    @markers = []
    @statusTiles = []

    @tabs = new Map
    @tabs.set 'line', new BottomTab()
    @tabs.set 'file', new BottomTab()
    @tabs.set 'project', new BottomTab()

    @panel = document.createElement 'div'
    @bubble = null
    @bottomStatus = new BottomStatus()

    @tabs.get('line').initialize 'Line', => @changeTab('line')
    @tabs.get('file').initialize 'File', => @changeTab('file')
    @tabs.get('project').initialize 'Project', => @changeTab('project')

    @bottomStatus.initialize()
    @bottomStatus.addEventListener 'click', ->
      atom.commands.dispatch atom.views.getView(atom.workspace), 'linter:next-error'
    @panelWorkspace = atom.workspace.addBottomPanel item: @panel, visible: false

    # Set default tab
    visibleTabs = @getVisibleTabKeys()

    @scope = atom.config.get('linter.defaultErrorTab', 'file')
    if visibleTabs.indexOf(@scope) is -1
      @scope = visibleTabs[0]

    @tabs.forEach (tab, key) =>
      tab.visible = false
      tab.active = @scope is key

    @panel.id = 'linter-panel'

  getMessages: ->
    @messages

# consumed in views/panel
  setPanelVisibility: (Status) ->
    if Status
      @panelWorkspace.show() unless @panelWorkspace.isVisible()
    else
      @panelWorkspace.hide() if @panelWorkspace.isVisible()

  # Called in config observer of linter-plus.coffee
  setShowPanel: (showPanel) ->
    atom.config.set('linter.showErrorPanel', showPanel)
    @showPanel = showPanel
    if showPanel
      @panel.removeAttribute('hidden')
    else
      @panel.setAttribute('hidden', true)

  # Called in config observer of linter-plus.coffee
  setShowBubble: (@showBubble) ->

  setUnderlineIssues: (@underlineIssues) ->

  setBubbleOpaque: ->
    bubble = document.getElementById('linter-inline')
