import makeEventsSelector from './events'
import {isolateSink, isolateSource} from './isolate'

import {filter, concat} from 'fast.js/array'

function makeIsStrictlyInRootScope(namespace) {
  const classIsForeign = c => {
    const matched = c.match(/cycle-scope-(\S+)/)
    return matched && namespace.indexOf(`.${c}`) === -1
  }
  const classIsDomestic = c => {
    const matched = c.match(/cycle-scope-(\S+)/)
    return matched && namespace.indexOf(`.${c}`) !== -1
  }
  return function isStrictlyInRootScope(leaf) {
    for (let el = leaf; el !== null; el = el.parentElement) {
      const split = String.prototype.split
      const classList = el.classList || split.call(el.className, ` `)
      if (Array.prototype.some.call(classList, classIsDomestic)) {
        return true
      }
      if (Array.prototype.some.call(classList, classIsForeign)) {
        return false
      }
    }
    return true
  }
}

function makeElementSelector(rootElem$) {
  return function DOMSelect(selector) {
    if (typeof selector !== `string`) {
      throw new Error(`DOM drivers select() expects first argument to be a ` +
        `string as a CSS selector`)
    }
    const namespace = this.namespace
    const scopedSelector = concat(
      namespace,
      selector.trim() === `:root` ? `` : selector.trim()
    )
    return {
      observable: rootElem$.map(rootEl => {
        if (scopedSelector.join(``) === ``) {
          return rootEl
        }
        let nodeList = rootEl.querySelectorAll(scopedSelector.join(` `).trim())
        if (nodeList.length === 0) {
          nodeList = rootEl.querySelectorAll(scopedSelector.join(``))
        }
        const array = Array.prototype.slice.call(nodeList)
        return filter(array, makeIsStrictlyInRootScope(scopedSelector))
      }),
      namespace: namespace.concat(selector),
      select: makeElementSelector(rootElem$),
      events: makeEventsSelector(rootElem$, scopedSelector),
      isolateSource,
      isolateSink,
    }
  }
}

export default makeElementSelector
export {makeIsStrictlyInRootScope}

@@ -908,16 +908,471 @@
 %0A  %7D%0A%7D%0A%0A
+function makeElementGetter(selector) %7B%0A  return function elemenGetter(rootElement) %7B%0A    if (selector.join(%60%60) === %60%60) %7B%0A      return rootElement%0A    %7D%0A    let nodeList = rootElement.querySelectorAll(selector.join(%60 %60).trim())%0A    if (nodeList.length === 0) %7B%0A      nodeList = rootElement.querySelectorAll(selector.join(%60%60))%0A    %7D%0A    const array = Array.prototype.slice.call(nodeList)%0A    return filter(array, makeIsStrictlyInRootScope(selector))%0A  %7D%0A%7D%0A%0A
 function
@@ -1400,16 +1400,19 @@
 rootElem
+ent
 $) %7B%0A  r
@@ -1601,32 +1601,33 @@
 elector%60)%0A    %7D%0A
+%0A
     const namesp
@@ -1647,16 +1647,17 @@
 mespace%0A
+%0A
     cons
@@ -1763,16 +1763,17 @@
 )%0A    )%0A
+%0A
     retu
@@ -1807,441 +1807,50 @@
 Elem
+ent
 $.map(
-rootEl =%3E %7B%0A        if (scopedSelector.join(%60%60) === %60%60) %7B%0A          return rootEl%0A        %7D%0A        let nodeList = rootEl.querySelectorAll(scopedSelector.join(%60 %60).trim())%0A        if (nodeList.length === 0) %7B%0A          nodeList = rootEl.querySelectorAll(scopedSelector.join(%60%60))%0A        %7D%0A        const array = Array.prototype.slice.call(nodeList)%0A        return filter(array, makeIsStrictlyInRootScope(scopedSelector))%0A      %7D
+makeElementGetter(scopedSelector)
 ),%0A 
@@ -1869,34 +1869,22 @@
 ce: 
-namespace.concat(s
+scopedS
 elector
-)
 ,%0A  
@@ -1923,16 +1923,19 @@
 rootElem
+ent
 $),%0A    
@@ -1971,16 +1971,19 @@
 rootElem
+ent
 $, scope

clean up code