const subordinate = require('subordinate')
function sortof (value) {
    if (value == null) {
        return null
    }
    return Object.prototype.toString.call(value).slice(8, -1).toLowerCase()
}
function condition (test) {
    const conditions = []
    switch (test.type) {
    case 'root': {
            return conditions
        }
    case 'error': {
            conditions.push(e => e instanceof test.error)
            for (const pattern of test.patterns) {
                conditions.push(value => subordinate(value, pattern))
            }
            return conditions
        }
    case 'boolean':
    case 'number':
    case 'string': {
            conditions.push(value => typeof value == test.type)
            for (const pattern of test.patterns) {
                conditions.push(value => subordinate(value, pattern))
            }
            return conditions
        }
    case 'symbol': {
            conditions.push(value => sortof(value) == test.type)
            for (const pattern of test.patterns) {
                conditions.push(value => subordinate(value, pattern))
            }
            return conditions
        }
    }
}
function compile ({ test, next }) {
    const conditions = condition(test)
    const descend = next == null
        ? { dive: [] }
        : Array.isArray(next)
            ? next.map(next => {
                return { match: next.match, dive: next.dive, test: compile(next) }
            })
            : { dive: next.dive, test: compile(next) }
    return function (object) {
        if (conditions.every(condition => condition(object))) {
            return descend
        }
        return null
    }
}
module.exports = function (ast) {
    return { match: ast.match, dive: ast.dive, test: compile(ast) }
}