// Copyright (c) 2011 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 "chrome/browser/ui/webui/favicon_source.h"

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "chrome/browser/history/top_sites.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/url_constants.h"
#include "grit/locale_settings.h"
#include "grit/ui_resources.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"

FaviconSource::FaviconSource(Profile* profile, IconType type)
    : DataSource(type == FAVICON ? chrome::kChromeUIFaviconHost :
                     chrome::kChromeUITouchIconHost,
                 MessageLoop::current()),
      profile_(profile->GetOriginalProfile()),
      icon_types_(type == FAVICON ? history::FAVICON :
          history::TOUCH_PRECOMPOSED_ICON | history::TOUCH_ICON |
          history::FAVICON) {
}

FaviconSource::~FaviconSource() {
}

void FaviconSource::StartDataRequest(const std::string& path,
                                     bool is_incognito,
                                     int request_id) {
  FaviconService* favicon_service =
      profile_->GetFaviconService(Profile::EXPLICIT_ACCESS);
  if (!favicon_service || path.empty()) {
    SendDefaultResponse(request_id);
    return;
  }

  FaviconService::Handle handle;
  if (path.size() > 8 && path.substr(0, 8) == "iconurl/") {
    // TODO : Change GetFavicon to support combination of IconType.
    handle = favicon_service->GetFavicon(
        GURL(path.substr(8)),
        history::FAVICON,
        &cancelable_consumer_,
        base::Bind(&FaviconSource::OnFaviconDataAvailable,
                   base::Unretained(this)));
  } else {
    GURL url;

    if (path.size() > 5 && path.substr(0, 5) == "size/") {
      size_t slash = path.find("/", 5);
      std::string size = path.substr(5, slash - 5);
      int pixel_size = atoi(size.c_str());
      CHECK(pixel_size == 32 || pixel_size == 16) <<
          "only 32x32 and 16x16 icons are supported";
      request_size_map_[request_id] = pixel_size;
      url = GURL(path.substr(slash + 1));
    } else {
      request_size_map_[request_id] = 16;
      url = GURL(path);
    }

    // Intercept requests for prepopulated pages.
    for (size_t i = 0; i < arraysize(history::kPrepopulatedPages); i++) {
      if (url.spec() ==
          l10n_util::GetStringUTF8(history::kPrepopulatedPages[i].url_id)) {
        request_size_map_.erase(request_id);
        SendResponse(request_id,
            ResourceBundle::GetSharedInstance().LoadDataResourceBytes(
                history::kPrepopulatedPages[i].favicon_id));
        return;
      }
    }

    // TODO(estade): fetch the requested size.
    handle = favicon_service->GetFaviconForURL(
        url,
        icon_types_,
        &cancelable_consumer_,
        base::Bind(&FaviconSource::OnFaviconDataAvailable,
                   base::Unretained(this)));
  }

  // Attach the ChromeURLDataManager request ID to the history request.
  cancelable_consumer_.SetClientData(favicon_service, handle, request_id);
}

std::string FaviconSource::GetMimeType(const std::string&) const {
  // We need to explicitly return a mime type, otherwise if the user tries to
  // drag the image they get no extension.
  return "image/png";
}

bool FaviconSource::ShouldReplaceExistingSource() const {
  // Leave the existing DataSource in place, otherwise we'll drop any pending
  // requests on the floor.
  return false;
}

void FaviconSource::OnFaviconDataAvailable(
    FaviconService::Handle request_handle,
    history::FaviconData favicon) {
  FaviconService* favicon_service =
      profile_->GetFaviconService(Profile::EXPLICIT_ACCESS);
  int request_id = cancelable_consumer_.GetClientData(favicon_service,
                                                      request_handle);

  if (favicon.is_valid()) {
    // Forward the data along to the networking system.
    SendResponse(request_id, favicon.image_data);
  } else {
    SendDefaultResponse(request_id);
  }
}

void FaviconSource::SendDefaultResponse(int request_id) {
  RefCountedMemory* bytes = NULL;
  if (request_size_map_[request_id] == 32) {
    if (!default_favicon_large_.get()) {
      default_favicon_large_ =
          ResourceBundle::GetSharedInstance().LoadDataResourceBytes(
              IDR_DEFAULT_LARGE_FAVICON);
    }
    bytes = default_favicon_large_;
  } else {
    if (!default_favicon_.get()) {
      default_favicon_ =
          ResourceBundle::GetSharedInstance().LoadDataResourceBytes(
              IDR_DEFAULT_FAVICON);
    }
    bytes = default_favicon_;
  }
  request_size_map_.erase(request_id);

  SendResponse(request_id, bytes);
}