#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import six
from fetchman.downloader.http.spider_request import Request
from fetchman.utils.python import to_unicode, to_native_str

if sys.version_info < (3, 0):
    reload(sys)
    sys.setdefaultencoding('utf-8')


def request_to_dict(request, processor=None):
    """Convert Request object to a dict.

    If a spider is given, it will try to find out the name of the spider method
    used in the callback and store that as the callback.
    """
    cb = request.callback
    if callable(cb):
        cb = _find_method(processor, cb)
    eb = request.errback
    if callable(eb):
        eb = _find_method(processor, eb)
    d = {
        'url': to_unicode(request.url),  # urls should be safe (safe_string_url)
        'callback': cb,
        'errback': eb,
        'data': request.data,
        'json': request.json,
        'allow_redirects': request.allow_redirects,
        'duplicate_remove': request.duplicate_remove,
        'timeout': request.timeout,
        'method': request.method,
        'headers': request.headers,
        'cookies': request.cookies,
        'meta': request.meta,
        'priority': request.priority,
    }
    return d


def request_from_dict(d, processor=None):
    """Create Request object from a dict.

    If a spider is given, it will try to resolve the callbacks looking at the
    spider for methods with the same name.
    """
    cb = d['callback']
    if cb and processor:
        cb = _get_method(processor, cb)
    eb = d['errback']
    if eb and processor:
        eb = _get_method(processor, eb)
    return Request(
            url=to_native_str(d['url']),
            data=d['data'],
            json=d['json'],
            allow_redirects=d['allow_redirects'],
            duplicate_remove=d['duplicate_remove'],
            timeout=d['timeout'],
            callback=cb,
            errback=eb,
            method=d['method'],
            headers=d['headers'],
            cookies=d['cookies'],
            meta=d['meta'],
            priority=d['priority'], )


def _find_method(obj, func):
    if obj:
        try:
            func_self = six.get_method_self(func)
        except AttributeError:  # func has no __self__
            pass
        else:
            if func_self is obj:
                return six.get_method_function(func).__name__
    raise ValueError("Function %s is not a method of: %s" % (func, obj))


def _get_method(obj, name):
    name = str(name)
    try:
        return getattr(obj, name)
    except AttributeError:
        raise ValueError("Method %r not found in: %s" % (name, obj))