import twisted.python.failure
import twisted.web.error
import scrapy.http
import scrapy.item


class Autoresponder(object):
    # The purpose of Autoresponder is to be initialized during a run
    # of a test case and used to iterate over scrapy Request objects
    # until finally there are no more Requests to execute.
    #
    # Instead of passing the Requests to the 'net, it handles them
    # through the configuration you pass it.
    #
    # Successful (status=200) Responses can be generated by configuring
    # url2filename.
    #
    # Error responses (status usually 4xx) can be generated by configuring
    # url2errors.
    def __init__(self, url2filename, url2errors=None):
        self.url2filename = url2filename
        if url2errors is None:
           url2errors = {}
        self.url2errors = url2errors

    @staticmethod
    def manufacture_http_failure(status_code):
        error = twisted.web.error.Error(code=status_code)
        failure = twisted.python.failure.Failure(
            exc_value=error, exc_type=twisted.web.error.Error)
        return failure

    def respond_recursively(self, request_iterable):
        items = []
        work_queue = itertools.chain() # The empty chain
        print request_iterable
        work_queue.extend(request_iterable)
        while work_queue:
            thing = work_queue.pop(0)
            if isinstance(thing, scrapy.item.Item):
                items.append(thing)
                continue

            request = thing
            if request.url in self.url2filename:
                filename = self.url2filename[request.url]
                with open(filename) as f:
                    data = f.read()
                response = scrapy.http.HtmlResponse(url=request.url,
                                                    body=data)
                response.request = request
                if hasattr(request, 'callback'):
                    callback = request.callback
                else:
                    callback = request.deferred.callback
                results = callback(response)
                if results:
                    if isinstance(results, scrapy.item.Item):
                        results = [results]
                    if isinstance(results, scrapy.http.Request):
                        results = [results]
                    work_queue.extend(results)
                continue

            if request.url in self.url2errors:
                status_code = self.url2errors[request.url]
                failure = (
                    Autoresponder.manufacture_http_failure(status_code))

                # Find the errback. Note that its location varies between versions
                # of scrapy.
                if hasattr(request, 'errback'):
                    errback = request.errback
                else:
                    errback = request.deferred.errback

                results = errback(failure)
                if results:
                    if isinstance(results, scrapy.item.Item):
                        results = [results]
                    work_queue.extend(list(results))
                continue

            raise KeyError
        return items
