from uuid import uuid4
import operator
from functools import partial, wraps

from toolz import merge

from .optimize import cull
from .context import _globals
from . import threaded


def get_uuid_dasks(v):
    if isinstance(v, Value):
        return v._uuid, v._dasks
    else:
        return v, []


def applyfunc(func, *args, **kwargs):
    if kwargs:
        func = partial(func, **kwargs)
    uuids, dsks = zip(*map(get_uuid_dasks, args))
    uuid = uuid4().hex
    dsks = sum(dsks, [{uuid: (func,) + uuids}])
    return Value(uuid, dsks)


def daskify(func):
    """Wraps func so that it outputs a ``Value``"""
    @wraps(func)
    def _dfunc(*args, **kwargs):
        return applyfunc(func, *args, **kwargs)
    return _dfunc


def get(dsk, keys, get=None, **kwargs):
    """Specialized get function"""
    get = get or _globals['get'] or threaded.get
    dsk2 = cull(dsk, keys)
    return get(dsk2, keys, **kwargs)


class Value(object):
    """Represents a value to be computed by dask.

    Equivalent to the output from a single key in a dask graph.
    """
    def __init__(self, uuid, dasks):
        self._uuid = uuid
        self._dasks = dasks

    __add__ = daskify(operator.add)
    __sub__ = daskify(operator.sub)
    __mul__ = daskify(operator.mul)
    __div__ = daskify(operator.div)
    __getitem__ = daskify(operator.getitem)

    def compute(self, **kwargs):
        dask1 = merge(*self._dasks)
        dask2 = cull(dask1, self._uuid)
        return get(dask2, self._uuid, **kwargs)

    @property
    def dask(self):
        return merge(*self._dasks)

    def visualize(self):
        from dask.dot import dot_graph
        dot_graph(self.dask)


def value(val, name=None):
    """Create a value from a python object"""
    name = name or uuid4().hex
    return Value(name, [{name: val}])

@@ -181,28 +181,28 @@
 d%0A%0A%0Adef get_
-uuid
+name
 _dasks(v):%0A 
@@ -247,20 +247,20 @@
 turn v._
-uuid
+name
 , v._das
@@ -391,20 +391,20 @@
 gs)%0A    
-uuid
+name
 s, dsks 
@@ -418,20 +418,20 @@
 map(get_
-uuid
+name
 _dasks, 
@@ -441,20 +441,20 @@
 s))%0A    
-uuid
+name
  = uuid4
@@ -483,20 +483,20 @@
 dsks, %5B%7B
-uuid
+name
 : (func,
@@ -499,20 +499,20 @@
 unc,) + 
-uuid
+name
 s%7D%5D)%0A   
@@ -525,20 +525,20 @@
 n Value(
-uuid
+name
 , dsks)%0A
@@ -1085,20 +1085,20 @@
 _(self, 
-uuid
+name
 , dasks)
@@ -1117,19 +1117,19 @@
 lf._
-uuid = uuid
+name = name
 %0A   
@@ -1446,20 +1446,20 @@
 , self._
-uuid
+name
 )%0A      
@@ -1484,20 +1484,20 @@
 , self._
-uuid
+name
 , **kwar

replace uuid with name