import { observable, action, asReference, when } from 'mobx'
import { app } from '@mindhive/di'


class NavigationDomain {

  @observable location = {
    pathname: null,
    state: asReference({}),  // asReference as state is not altered internally
  }
  @observable atHistoryBeginning = true

  constructor() {
    const { browserHistory } = app()
    this._locationChanged(browserHistory.getCurrentLocation())  // TODO: browserHistory.location in reactRouter v4
    browserHistory.listen((location) => {
      this._locationChanged(location)
    })
  }

  @action _locationChanged(browserLocation) {
    this.location.pathname = browserLocation.pathname
    this.location.state = browserLocation.state == null ? {} : browserLocation.state
    this.atHistoryBeginning = browserLocation.state == null
  }

  _pathnameOrLocationToBrowserLocation(pathnameOrLocation) {
    const location = typeof pathnameOrLocation === 'string' || typeof pathnameOrLocation === 'number' ?
      { pathname: String(pathnameOrLocation) }
      : pathnameOrLocation
    if (location.state == null) {
      // ensure there is always state so we know when we are at the first page in this history
      location.state = {}
    }
    return location
  }

  push(pathnameOrLocation) {
    app().browserHistory.push(this._pathnameOrLocationToBrowserLocation(pathnameOrLocation))
  }

  replace(pathnameOrLocation) {
    app().browserHistory.replace(this._pathnameOrLocationToBrowserLocation(pathnameOrLocation))
  }

  _relativeToAbsolutePathname(relativePathname) {
    let pathnameAddition = relativePathname
    if (this.location.pathname.endsWith('/')) {
      if (relativePathname.startsWith('/')) {
        pathnameAddition = relativePathname.substring(1)
      }
    } else {
      if (! relativePathname.startsWith('/')) {
        pathnameAddition = `/${relativePathname}`
      }
    }
    return this.location.pathname + pathnameAddition
  }

  pushDown(relativePathnameOrLocation) {
    const { pathname: relativePathname, ...locationRest } =
      this._pathnameOrLocationToBrowserLocation(relativePathnameOrLocation)
    this.push({ pathname: this._relativeToAbsolutePathname(relativePathname), ...locationRest })
  }

  popUp(dirCount = 1) {
    const { browserHistory } = app()
    if (this.atHistoryBeginning) {
      let popCount = dirCount
      let resultPathname = this.location.pathname
      while (popCount > 0) {
        const breakIndex = resultPathname.lastIndexOf('/')
        if (resultPathname === '/' || breakIndex === -1) {
          console.warn('pop dirCount too large, assuming root pathname')  // eslint-disable-line no-console
          resultPathname = '/'
          break
        }
        resultPathname = breakIndex === 0 ? '/' : resultPathname.substring(0, breakIndex)
        popCount -= 1
      }
      browserHistory.replace(resultPathname)  // Don't use our replace as we don't want to set our state marker so we will know we're still at the beginning
    } else {
      browserHistory.goBack()
    }
  }

  whenNavigateAway(callback) {
    const originalPathname = this.location.pathname
    when(
      () => this.location.pathname !== originalPathname,
      callback,
    )
  }
}

export default () => ({
  navigationDomain: new NavigationDomain(),
})

@@ -1492,51 +1492,30 @@
 %0A  _
-relativeToAbsolutePathname(relativePathname
+joinPaths(path1, path2
 ) %7B%0A
@@ -1522,28 +1522,25 @@
     let path
-name
+2
 Addition = r
@@ -1542,55 +1542,27 @@
 n = 
-relativePathname%0A    if (this.location.pathname
+path2%0A    if (path1
 .end
@@ -1585,32 +1585,21 @@
     if (
-relativePathname
+path2
 .startsW
@@ -1614,36 +1614,33 @@
 ) %7B%0A        path
-name
+2
 Addition = relat
@@ -1634,32 +1634,21 @@
 ition = 
-relativePathname
+path2
 .substri
@@ -1686,32 +1686,21 @@
   if (! 
-relativePathname
+path2
 .startsW
@@ -1719,28 +1719,25 @@
         path
-name
+2
 Addition = %60
@@ -1743,93 +1743,497 @@
 %60/$%7B
-relativePathname%7D%60%0A      %7D%0A    %7D%0A    return this.location.pathname + pathnameAddition
+path2%7D%60%0A      %7D%0A    %7D%0A    return path1 + path2Addition%0A  %7D%0A%0A  // If dirCount is %3E= 0 then the number of directories in the URL to keep%0A  // If dirCount is %3C 0 then the number of directories to remove%0A  // Prefer specific positive numbers to avoid issues with quick double actions performing using the wrong state%0A  _keepDirs(dirCount) %7B%0A    if (dirCount === 0) %7B%0A      return '/'%0A    %7D%0A    return this.location.pathname.split('/').slice(0, dirCount %3E 0 ? dirCount + 1 : dirCount).join('/')
 %0A  %7D
@@ -2245,16 +2245,28 @@
 ushDown(
+dirsToKeep, 
 relative
@@ -2438,16 +2438,22 @@
 s.push(%7B
+%0A     
  pathnam
@@ -2465,35 +2465,46 @@
 is._
-relativeToAbsolutePathname(
+joinPaths(this._keepDirs(dirsToKeep), 
 rela
@@ -2517,16 +2517,22 @@
 thname),
+%0A     
  ...loca
@@ -2539,16 +2539,21 @@
 tionRest
+,%0A   
  %7D)%0A  %7D%0A
@@ -2564,24 +2564,21 @@
 opUp(dir
-Count
+s
  = 
+-
 1) %7B%0A   
@@ -2656,560 +2656,8 @@
     
-let popCount = dirCount%0A      let resultPathname = this.location.pathname%0A      while (popCount %3E 0) %7B%0A        const breakIndex = resultPathname.lastIndexOf('/')%0A        if (resultPathname === '/' %7C%7C breakIndex === -1) %7B%0A          console.warn('pop dirCount too large, assuming root pathname')  // eslint-disable-line no-console%0A          resultPathname = '/'%0A          break%0A        %7D%0A        resultPathname = breakIndex === 0 ? '/' : resultPathname.substring(0, breakIndex)%0A        popCount -= 1%0A      %7D%0A      browserHistory.replace(resultPathname)  
 // D
@@ -2762,16 +2762,67 @@
 eginning
+%0A      browserHistory.replace(this._keepDirs(dirs))
 %0A    %7D e

Change pushDown / popUp to be more explicit to avoid race conditions