-historyCache = []
-lastState = null
-initialized = false
+
+pageCache    = []
+currentState = null
+initialized  = false
+
 visit = (url) ->
-
-  if browserSupportsPushState? and document.location.href isnt url
-    rememberInitialPage()
-    rememberPage()
+  if browserSupportsPushState
+    cacheCurrentPage()
     reflectNewUrl url
     fetchReplacement url
   else
     document.location.href = url
 
-rememberPage = ->
-  historyCache[lastState.position] = url: document.location.href, body: document.body, title: document.title, pageYOffset: window.pageYOffset, pageXOffset: window.pageXOffset
-
-rememberInitialPage = ->
-  unless initialized
-    window.history.replaceState { turbolinks: true, position: window.history.length - 1}, "", document.location.href
-    lastState = window.history.state
-    initialized = true
 
 fetchReplacement = (url) ->
   xhr = new XMLHttpRequest
   xhr.open 'GET', url, true
   xhr.setRequestHeader 'Accept', 'text/html, application/xhtml+xml, application/xml'
-  xhr.onload  = -> fullReplacement xhr.responseText, url
-  xhr.onabort = -> console.log "Aborted turbolink fetch!"
+  xhr.onload  = -> changePage extractTitleAndBody(xhr.responseText)...
+  xhr.onabort = -> console.log 'Aborted turbolink fetch!'
   xhr.send()
 
 fetchHistory = (state) ->
-  rememberPage()
-  if cache = historyCache[state.position]
-    replaceBody cache.body, cache.title
-    triggerPageChange()
-    window.scrollTo(cache.pageXOffset,cache.pageYOffset)
+  cacheCurrentPage()
+  if page = pageCache[state.position]
+    changePage page.title, page.body.cloneNode(true)
+    recallScrollPosition page
+
   else
     fetchReplacement document.location.href
 
-fullReplacement = (html, url) ->
-  replaceHTML html
-  triggerPageChange()
+
+cacheCurrentPage = ->
+  rememberInitialPage()
+  pageCache[currentState.position] =
+    url:       document.location.href,
+    body:      document.body,
+    title:     document.title,
+    positionY: window.pageYOffset,
+    positionX: window.pageXOffset
+  garbageCollectCache()
+
+garbageCollectCache = ->
+  if currentState.position == window.history.length - 1 and pageCache[currentState.position - 10] != undefined
+    delete pageCache[currentState.position - 10]
+
+
+changePage = (title, body) ->
+  document.title = title
+  document.documentElement.replaceChild body, document.body
+
+  currentState = window.history.state
+  triggerEvent 'page:change'
+
 
 reflectNewUrl = (url) ->
-  window.history.pushState { turbolinks: true, position: window.history.length }, "", url
+  window.history.pushState { turbolinks: true, position: window.history.length }, '', url
+
+rememberCurrentUrl = ->
+  window.history.replaceState { turbolinks: true, position: window.history.length - 1 }, '', document.location.href
+
+rememberCurrentState = ->
+  currentState = window.history.state
+
+rememberInitialPage = ->
+  unless initialized
+    rememberCurrentUrl()
+    rememberCurrentState()
+    initialized = true
+
+recallScrollPosition = (page) ->
+  window.scrollTo page.positionX, page.positionX
 
 
+triggerEvent = (name) ->
+  event = document.createEvent 'Events'
+  event.initEvent name, true, true
+  document.dispatchEvent event
 
-triggerPageChange = ->
-  event = document.createEvent 'Events'
-  event.initEvent 'page:change', true, true
-  document.dispatchEvent event
+
+extractTitleAndBody = (html) ->
+  doc   = createDocument html
+  title = doc.querySelector 'title'
+  [ title?.textContent, doc.body ]
 
 createDocument = do ->
   createDocumentUsingParser = (html) ->
-    (new DOMParser).parseFromString html, "text/html"
+    (new DOMParser).parseFromString html, 'text/html'
 
   createDocumentUsingWrite = (html) ->
-    doc = document.implementation.createHTMLDocument ""
-    doc.open "replace"
+    doc = document.implementation.createHTMLDocument ''
+    doc.open 'replace'
     doc.write html
     doc.close
     doc
 
   if window.DOMParser
-    testDoc = createDocumentUsingParser "<html><body><p>test"
+    testDoc = createDocumentUsingParser '<html><body><p>test'
 
   if testDoc?.body?.childNodes.length is 1
     createDocumentUsingParser
   else
     createDocumentUsingWrite
 
-replaceHTML = (html) ->
-  doc = createDocument html
-  title = doc.querySelector "title"
-  replaceBody doc.body,title?.textContent, 'cache'
-
-replaceBody = (body, title, cache) ->
-  document.documentElement.replaceChild body, document.body
-  document.title = title
-  lastState = window.history.state
-
-
 extractLink = (event) ->
   link = event.target
   link = link.parentNode until link is document or link.nodeName is 'A'
   link
+
+samePageLink = (link) ->
+  link.href is document.location.href
 
 crossOriginLink = (link) ->
   location.protocol isnt link.protocol or location.host isnt link.host

  event.which > 1 or event.metaKey or event.ctrlKey

ignoreClick = (event, link) ->
  crossOriginLink(link) or anchoredLink(link) or nonHtmlLink(link) or noTurbolink(link) or newTabClick(event)

handleClick = (event) ->
  link = extractLink event

    visit link.href
    event.preventDefault()

browserSupportsPushState =
  window.history and window.history.pushState and window.history.replaceState


if browserSupportsPushState

  window.addEventListener 'popstate', (event) ->
    fetchHistory event.state if event.state?.turbolinks

  document.addEventListener 'click', (event) ->
    handleClick event

