text: // Copyright 2014 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include "components/image_fetcher/image_fetcher_impl.h"
  
  #include <string>
  
  #include "base/bind.h"
  #include "net/base/load_flags.h"
  #include "net/url_request/url_request_context_getter.h"
  
  namespace image_fetcher {
  
  ImageFetcherImpl::ImageFetcherImpl(
      std::unique_ptr<ImageDecoder> image_decoder,
      net::URLRequestContextGetter* url_request_context)
      : delegate_(nullptr), url_request_context_(url_request_context),
        image_decoder_(std::move(image_decoder)),
        image_data_fetcher_(new ImageDataFetcher(url_request_context_.get())) {
  }
  
  ImageFetcherImpl::~ImageFetcherImpl() {}
  
  ImageFetcherImpl::ImageRequest::ImageRequest() {}
  
  ImageFetcherImpl::ImageRequest::ImageRequest(const ImageRequest& other) =
      default;
  
  ImageFetcherImpl::ImageRequest::~ImageRequest() { }
  
  void ImageFetcherImpl::SetImageFetcherDelegate(ImageFetcherDelegate* delegate) {
    DCHECK(delegate);
    delegate_ = delegate;
  }
  
  void ImageFetcherImpl::SetDataUseServiceName(
      DataUseServiceName data_use_service_name) {
    image_data_fetcher_->SetDataUseServiceName(data_use_service_name);
  }
  
  void ImageFetcherImpl::StartOrQueueNetworkRequest(
      const std::string& id,
      const GURL& image_url,
      base::Callback<void(const std::string&, const gfx::Image&)> callback) {
    // Before starting to fetch the image. Look for a request in progress for
    // |image_url|, and queue if appropriate.
    ImageRequestMap::iterator it = pending_net_requests_.find(image_url);
    if (it == pending_net_requests_.end()) {
      ImageRequest request;
      request.id = id;
      request.callbacks.push_back(callback);
      pending_net_requests_[image_url].swap(&request);
  
      image_data_fetcher_->FetchImageData(
          image_url,
          base::Bind(&ImageFetcherImpl::OnImageURLFetched,
                     base::Unretained(this), image_url));
    } else {
      // Request in progress. Register as an interested callback.
      it->second.callbacks.push_back(callback);
    }
  }
  
  void ImageFetcherImpl::OnImageURLFetched(const GURL& image_url,
                                           const std::string& image_data) {
    // Inform the ImageFetcherDelegate.
    if (delegate_) {
      auto it = pending_net_requests_.find(image_url);
      DCHECK(it != pending_net_requests_.end());
      delegate_->OnImageDataFetched(it->second.id, image_data);
    }
  
    image_decoder_->DecodeImage(
        image_data,
        base::Bind(&ImageFetcherImpl::OnImageDecoded,
                   base::Unretained(this), image_url));
  }
  
  void ImageFetcherImpl::OnImageDecoded(const GURL& image_url,
                                        const gfx::Image& image) {
    // Get request for the given image_url from the request queue.
    ImageRequestMap::iterator image_iter = pending_net_requests_.find(image_url);
    DCHECK(image_iter != pending_net_requests_.end());
    ImageRequest* request = &image_iter->second;
  
    // Run all callbacks
    for (const auto& callback : request->callbacks) {
      callback.Run(request->id, image);
    }
  
    // Inform the ImageFetcherDelegate.
    if (delegate_) {
      delegate_->OnImageFetched(request->id, image);
    }
  
    // Erase the completed ImageRequest.
    pending_net_requests_.erase(image_iter);
  }
  
  }  // namespace image_fetcher
  