from __future__ import absolute_import, division, print_function

import os
import datetime
import glob

try:
    from cytoolz import nth
except ImportError:
    from toolz import nth

from itertools import islice
from collections import Iterator
from multiprocessing.pool import ThreadPool

# these are used throughout blaze, don't remove them
from odo.utils import tmpfile, filetext, filetexts, raises, keywords, ignoring
from odo import resource

import psutil
import numpy as np

# Imports that replace older utils.
from .compatibility import map, zip

from .dispatch import dispatch

thread_pool = ThreadPool(psutil.cpu_count())


def nth_list(n, seq):
    """

    >>> tuple(nth_list([0, 1, 4], 'Hello'))
    ('H', 'e', 'o')
    >>> tuple(nth_list([4, 1, 0], 'Hello'))
    ('o', 'e', 'H')
    >>> tuple(nth_list([0, 0, 0], 'Hello'))
    ('H', 'H', 'H')
    """
    seq = iter(seq)

    result = []
    old = 0
    item = next(seq)
    for index in sorted(n):
        for i in range(index - old):
            item = next(seq)
        result.append(item)
        old = index

    order = [x[1] for x in sorted(zip(n, range(len(n))))]
    return (result[i] for i in order)


def get(ind, coll, lazy=False):
    """

    >>> get(0, 'Hello')
    'H'

    >>> get([1, 0], 'Hello')
    ('e', 'H')

    >>> get(slice(1, 4), 'Hello')
    ('e', 'l', 'l')

    >>> get(slice(1, 4), 'Hello', lazy=True)
    <itertools.islice object at ...>
    """
    if isinstance(ind, list):
        result = nth_list(ind, coll)
    elif isinstance(ind, slice):
        result = islice(coll, ind.start, ind.stop, ind.step)
    else:
        if isinstance(coll, Iterator):
            result = nth(ind, coll)
        else:
            result = coll[ind]
    if not lazy and isinstance(result, Iterator):
        result = tuple(result)
    return result


def ndget(ind, data):
    """
    Get from N-Dimensional getable

    Can index with elements, lists, or slices.  Mimic's numpy fancy indexing on
    generic indexibles.

    >>> data = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
    >>> ndget(0, data)
    [[1, 2], [3, 4]]
    >>> ndget((0, 1), data)
    [3, 4]
    >>> ndget((0, 0, 0), data)
    1
    >>> ndget((slice(0, 2), [0, 1], 0), data)
    ((1, 3), (5, 7))
    """
    if isinstance(ind, tuple) and len(ind) == 1:
        ind = ind[0]
    if not isinstance(ind, tuple):
        return get(ind, data)
    result = get(ind[0], data)
    if isinstance(ind[0], (list, slice)):
        return type(result)(ndget(ind[1:], row) for row in result)
    else:
        return ndget(ind[1:], result)


def normalize_to_date(dt):
    if isinstance(dt, datetime.datetime) and not dt.time():
        return dt.date()
    else:
        return dt


def assert_allclose(lhs, rhs):
    for tb in map(zip, lhs, rhs):
        for left, right in tb:
            if isinstance(left, (np.floating, float)):
                # account for nans
                assert np.all(np.isclose(left, right, equal_nan=True))
                continue
            if isinstance(left, datetime.datetime):
                left = normalize_to_date(left)
            if isinstance(right, datetime.datetime):
                right = normalize_to_date(right)
            assert left == right


def example(filename, datapath=os.path.join('examples', 'data')):
    import blaze
    return os.path.join(os.path.dirname(blaze.__file__), datapath, filename)


def available_memory():
    return psutil.virtual_memory().available


def listpack(x):
    """
    >>> listpack(1)
    [1]
    >>> listpack((1, 2))
    [1, 2]
    >>> listpack([1, 2])
    [1, 2]
    """
    if isinstance(x, tuple):
        return list(x)
    elif isinstance(x, list):
        return x
    else:
        return [x]


@dispatch(datetime.datetime)
def json_dumps(dt):
    s = dt.isoformat()
    if not dt.tzname():
        s += 'Z'
    return s


def _spider(resource_path, ignore, followlinks, hidden):
    resources = {}
    for filename in (os.path.join(resource_path, x)
                     for x in os.listdir(resource_path)):
        basename = os.path.basename(filename)
        if (basename.startswith(os.curdir) and not hidden or
                os.path.islink(filename) and not followlinks):
            continue
        if os.path.isdir(filename):
            new_resources = _spider(filename, ignore=ignore,
                                    followlinks=followlinks, hidden=hidden)
            if new_resources:
                resources[basename] = new_resources
        else:
            with ignoring(*ignore):
                resources[basename] = resource(filename)
    return resources


def spider(resource_path, ignore=(ValueError, NotImplementedError),
           followlinks=True, hidden=False, globs=()):
    return {
        os.path.basename(resource_path): _spider(resource_path, ignore=ignore,
                                                 followlinks=followlinks,
                                                 hidden=hidden)
    }

@@ -88,20 +88,8 @@
 time
-%0Aimport glob
 %0A%0Atr
@@ -408,33 +408,8 @@
 ring
-%0Afrom odo import resource
 %0A%0Aim
@@ -3819,1126 +3819,4 @@
 n s%0A
-%0A%0Adef _spider(resource_path, ignore, followlinks, hidden):%0A    resources = %7B%7D%0A    for filename in (os.path.join(resource_path, x)%0A                     for x in os.listdir(resource_path)):%0A        basename = os.path.basename(filename)%0A        if (basename.startswith(os.curdir) and not hidden or%0A                os.path.islink(filename) and not followlinks):%0A            continue%0A        if os.path.isdir(filename):%0A            new_resources = _spider(filename, ignore=ignore,%0A                                    followlinks=followlinks, hidden=hidden)%0A            if new_resources:%0A                resources%5Bbasename%5D = new_resources%0A        else:%0A            with ignoring(*ignore):%0A                resources%5Bbasename%5D = resource(filename)%0A    return resources%0A%0A%0Adef spider(resource_path, ignore=(ValueError, NotImplementedError),%0A           followlinks=True, hidden=False, globs=()):%0A    return %7B%0A        os.path.basename(resource_path): _spider(resource_path, ignore=ignore,%0A                                                 followlinks=followlinks,%0A                                                 hidden=hidden)%0A    %7D%0A

Move spider to its own file