/** @babel */

import {Emitter, CompositeDisposable} from 'event-kit'

// Extended: History manager for remembering which projects have been opened.
//
// An instance of this class is always available as the `atom.history` global.
//
// The project history is used to enable the 'Reopen Project' menu.
export class HistoryManager {
  constructor ({project, commands, stateStore}) {
    this.stateStore = stateStore
    this.emitter = new Emitter()
    this.projects = []
    this.disposables = new CompositeDisposable()
    this.disposables.add(commands.add('atom-workspace', {'application:clear-project-history': this.clearProjects.bind(this)}, false))
    this.disposables.add(project.onDidChangePaths((projectPaths) => this.addProject(projectPaths)))
  }

  destroy () {
    this.disposables.dispose()
  }

  // Public: Obtain a list of previously opened projects.
  //
  // Returns an {Array} of {HistoryProject} objects, most recent first.
  getProjects () {
    return this.projects.map(p => new HistoryProject(p.paths, p.lastOpened))
  }

  // Public: Clear all projects from the history.
  //
  // Note: This is not a privacy function - other traces will still exist,
  // e.g. window state.
  //
  // Return a {Promise} that resolves when the history has been successfully
  // cleared.
  async clearProjects () {
    this.projects = []
    await this.saveState()
    this.didChangeProjects()
  }

  // Public: Invoke the given callback when the list of projects changes.
  //
  // * `callback` {Function}
  //
  // Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.
  onDidChangeProjects (callback) {
    return this.emitter.on('did-change-projects', callback)
  }

  didChangeProjects (args = {reloaded: false}) {
    this.emitter.emit('did-change-projects', args)
  }

  async addProject (paths, lastOpened) {
    if (paths.length === 0) return

    let project = this.getProject(paths)
    if (!project) {
      project = new HistoryProject(paths)
      this.projects.push(project)
    }
    project.lastOpened = lastOpened || new Date()
    this.projects.sort((a, b) => b.lastOpened - a.lastOpened)

    await this.saveState()
    this.didChangeProjects()
  }

  async removeProject (paths) {
    if (paths.length === 0) return

    let project = this.getProject(paths)
    if (!project) return

    let index = this.projects.indexOf(project)
    this.projects.splice(index, 1)

    await this.saveState()
    this.didChangeProjects()
  }

  getProject (paths) {
    for (var i = 0; i < this.projects.length; i++) {
      if (arrayEquivalent(paths, this.projects[i].paths)) {
        return this.projects[i]
      }
    }

    return null
  }

  async loadState () {
    const history = await this.stateStore.load('history-manager')
    if (history && history.projects) {
      this.projects = history.projects.filter(p => Array.isArray(p.paths) && p.paths.length > 0).map(p => new HistoryProject(p.paths, new Date(p.lastOpened)))
      this.didChangeProjects({reloaded: true})
    } else {
      this.projects = []
    }
  }

  async saveState () {
    const projects = this.projects.map(p => ({paths: p.paths, lastOpened: p.lastOpened}))
    await this.stateStore.save('history-manager', {projects})
  }
}

function arrayEquivalent (a, b) {
  if (a.length !== b.length) return false
  for (var i = 0; i < a.length; i++) {
    if (a[i] !== b[i]) return false
  }
  return true
}

export class HistoryProject {
  constructor (paths, lastOpened) {
    this.paths = paths
    this.lastOpened = lastOpened || new Date()
  }

  set paths (paths) { this._paths = paths }
  get paths () { return this._paths }

  set lastOpened (lastOpened) { this._lastOpened = lastOpened }
  get lastOpened () { return this._lastOpened }
}
