  void UpdateNetworkManagerStatus() {
    if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
      BrowserThread::PostTask(
          BrowserThread::UI, FROM_HERE,
          NewRunnableMethod(this,
                            &NetworkLibraryImpl::UpdateNetworkManagerStatus));
      return;
    }

    SystemInfo* system = GetSystemInfo();
    if (!system)
      return;

    std::string prev_cellular_service_path = cellular_ ?
        cellular_->service_path() : std::string();

    ClearNetworks();

    ParseSystem(system, &ethernet_, &wifi_networks_, &cellular_networks_,
                &remembered_wifi_networks_);

    wifi_ = NULL;
    for (size_t i = 0; i < wifi_networks_.size(); i++) {
      if (wifi_networks_[i]->connecting_or_connected()) {
        wifi_ = wifi_networks_[i];
        break;  // There is only one connected or connecting wifi network.
      }
    }
    cellular_ = NULL;
     for (size_t i = 0; i < cellular_networks_.size(); i++) {
       if (cellular_networks_[i]->connecting_or_connected()) {
         cellular_ = cellular_networks_[i];
         if (cellular_networks_[i]->service_path() !=
                 prev_cellular_service_path) {
          CellularDataPlanList* list = RetrieveCellularDataPlans(
              cellular_->service_path().c_str());
          UpdateCellularDataPlan(list);
          FreeCellularDataPlanList(list);
         }
         break;  // There is only one connected or connecting cellular network.
       }
    }

    available_devices_ = system->available_technologies;
    enabled_devices_ = system->enabled_technologies;
    connected_devices_ = system->connected_technologies;
    offline_mode_ = system->offline_mode;

    NotifyNetworkManagerChanged();
    FreeSystemInfo(system);
  }


int64 ClientUsageTracker::GetCachedHostUsage(const std::string& host) {
   HostUsageMap::const_iterator found = cached_usage_.find(host);
   if (found == cached_usage_.end())
     return 0;

  int64 usage = 0;
  const UsageMap& map = found->second;
  for (UsageMap::const_iterator iter = map.begin();
       iter != map.end(); ++iter) {
    usage += iter->second;
  }
  return usage;
}


void AddInstallerCopyTasks(const InstallerState& installer_state,
                           const FilePath& setup_path,
                           const FilePath& archive_path,
                           const FilePath& temp_path,
                           const Version& new_version,
                           WorkItemList* install_list) {
  DCHECK(install_list);
  FilePath installer_dir(installer_state.GetInstallerDirectory(new_version));
  install_list->AddCreateDirWorkItem(installer_dir);

   FilePath exe_dst(installer_dir.Append(setup_path.BaseName()));
   FilePath archive_dst(installer_dir.Append(archive_path.BaseName()));

  install_list->AddMoveTreeWorkItem(setup_path.value(), exe_dst.value(),
                                    temp_path.value(), WorkItem::ALWAYS_MOVE);
   install_list->AddMoveTreeWorkItem(archive_path.value(), archive_dst.value(),
                                     temp_path.value(), WorkItem::ALWAYS_MOVE);
 }


bool decode(ArgumentDecoder* decoder, RetainPtr<CFURLRef>& result)
{
    RetainPtr<CFURLRef> baseURL;
    bool hasBaseURL;
    if (!decoder->decodeBool(hasBaseURL))
        return false;
    if (hasBaseURL) {
        if (!decode(decoder, baseURL))
            return false;
    }

    RetainPtr<CFStringRef> string;
     if (!decode(decoder, string))
         return false;

     CFURLRef url = CFURLCreateWithString(0, string.get(), baseURL.get());
     if (!url)
         return false;

    result.adoptCF(url);
    return true;
}


void WebProcessProxy::addExistingWebPage(WebPageProxy* webPage, uint64_t pageID)
{
     m_pageMap.set(pageID, webPage);
     globalPageMap().set(pageID, webPage);
 #if PLATFORM(MAC)
    if (pageIsProcessSuppressible(webPage));
         m_processSuppressiblePages.add(pageID);
     updateProcessSuppressionState();
 #endif
}


v8::Handle<v8::Value> V8ThrowException::createDOMException(v8::Isolate* isolate, int ec, const String& sanitizedMessage, const String& unsanitizedMessage, const v8::Handle<v8::Object>& creationContext)
{
    if (ec <= 0 || v8::V8::IsExecutionTerminating())
        return v8Undefined();

    ASSERT(ec == SecurityError || unsanitizedMessage.isEmpty());

    if (ec == V8GeneralError)
        return V8ThrowException::createGeneralError(isolate, sanitizedMessage);
    if (ec == V8TypeError)
        return V8ThrowException::createTypeError(isolate, sanitizedMessage);
    if (ec == V8RangeError)
        return V8ThrowException::createRangeError(isolate, sanitizedMessage);
    if (ec == V8SyntaxError)
        return V8ThrowException::createSyntaxError(isolate, sanitizedMessage);
     if (ec == V8ReferenceError)
         return V8ThrowException::createReferenceError(isolate, sanitizedMessage);

     RefPtrWillBeRawPtr<DOMException> domException = DOMException::create(ec, sanitizedMessage, unsanitizedMessage);
    v8::Handle<v8::Value> exception = toV8(domException.get(), creationContext, isolate);

     if (exception.IsEmpty())
         return v8Undefined();

    v8::Handle<v8::Value> error = v8::Exception::Error(v8String(isolate, domException->message()));
    ASSERT(!error.IsEmpty());
    ASSERT(exception->IsObject());
    exception->ToObject(isolate)->SetAccessor(v8AtomicString(isolate, "stack"), domExceptionStackGetter, domExceptionStackSetter, error);
    V8HiddenValue::setHiddenValue(isolate, exception->ToObject(isolate), V8HiddenValue::error(isolate), error);

    return exception;
}


void OverlayWindowViews::OnGestureEvent(ui::GestureEvent* event) {
  if (event->type() != ui::ET_GESTURE_TAP)
    return;

  hide_controls_timer_.Reset();

  if (!GetControlsScrimLayer()->visible()) {
    UpdateControlsVisibility(true);
    return;
  }

  if (GetCloseControlsBounds().Contains(event->location())) {
    controller_->Close(true /* should_pause_video */,
                       true /* should_reset_pip_player */);
    event->SetHandled();
  } else if (GetPlayPauseControlsBounds().Contains(event->location())) {
     TogglePlayPause();
     event->SetHandled();
   }
  views::Widget::OnGestureEvent(event);
 }


std::string CellularNetwork::ActivationStateToString(
    ActivationState activation_state) {
  switch (activation_state) {
    case ACTIVATION_STATE_ACTIVATED:
      return l10n_util::GetStringUTF8(
          IDS_CHROMEOS_NETWORK_ACTIVATION_STATE_ACTIVATED);
      break;
    case ACTIVATION_STATE_ACTIVATING:
      return l10n_util::GetStringUTF8(
          IDS_CHROMEOS_NETWORK_ACTIVATION_STATE_ACTIVATING);
      break;
    case ACTIVATION_STATE_NOT_ACTIVATED:
      return l10n_util::GetStringUTF8(
          IDS_CHROMEOS_NETWORK_ACTIVATION_STATE_NOT_ACTIVATED);
      break;
    case ACTIVATION_STATE_PARTIALLY_ACTIVATED:
      return l10n_util::GetStringUTF8(
          IDS_CHROMEOS_NETWORK_ACTIVATION_STATE_PARTIALLY_ACTIVATED);
      break;
    default:
      return l10n_util::GetStringUTF8(
          IDS_CHROMEOS_NETWORK_ACTIVATION_STATE_UNKNOWN);
      break;
  }
}


  virtual void AddCellularDataPlanObserver(CellularDataPlanObserver* observer) {
    if (!data_plan_observers_.HasObserver(observer))
      data_plan_observers_.AddObserver(observer);
  }


  virtual void AddNetworkManagerObserver(NetworkManagerObserver* observer) {
    if (!network_manager_observers_.HasObserver(observer))
      network_manager_observers_.AddObserver(observer);
  }


virtual void AddNetworkManagerObserver(NetworkManagerObserver* observer) {}


  virtual void AddNetworkObserver(const std::string& service_path,
                                  NetworkObserver* observer) {
    DCHECK(observer);
    if (!EnsureCrosLoaded())
      return;
    NetworkObserverMap::iterator iter = network_observers_.find(service_path);
    NetworkObserverList* oblist;
    if (iter != network_observers_.end()) {
      oblist = iter->second;
    } else {
      std::pair<NetworkObserverMap::iterator, bool> inserted =
        network_observers_.insert(
            std::make_pair<std::string, NetworkObserverList*>(
                service_path,
                new NetworkObserverList(this, service_path)));
      oblist = inserted.first->second;
    }
    if (!oblist->HasObserver(observer))
      oblist->AddObserver(observer);
  }


  virtual void AddNetworkObserver(const std::string& service_path,
                                  NetworkObserver* observer) {}


CellularNetwork::CellularNetwork()
    : WirelessNetwork(),
      activation_state_(ACTIVATION_STATE_UNKNOWN),
      network_technology_(NETWORK_TECHNOLOGY_UNKNOWN),
      roaming_state_(ROAMING_STATE_UNKNOWN),
      restricted_pool_(false),
      prl_version_(0) {
  type_ = TYPE_CELLULAR;
}


CellularNetwork::CellularNetwork(const CellularNetwork& network)
    : WirelessNetwork(network) {
  activation_state_ = network.activation_state();
  network_technology_ = network.network_technology();
  roaming_state_ = network.roaming_state();
  restricted_pool_ = network.restricted_pool();
  service_name_ = network.service_name();
  operator_name_ = network.operator_name();
  operator_code_ = network.operator_code();
  payment_url_ = network.payment_url();
  meid_ = network.meid();
  imei_ = network.imei();
  imsi_ = network.imsi();
  esn_ = network.esn();
  mdn_ = network.mdn();
  min_ = network.min();
  model_id_ = network.model_id();
  manufacturer_ = network.manufacturer();
  firmware_revision_ = network.firmware_revision();
  hardware_revision_ = network.hardware_revision();
  last_update_ = network.last_update();
  prl_version_ = network.prl_version();
  type_ = TYPE_CELLULAR;
}


CellularNetwork::CellularNetwork(const ServiceInfo* service)
    : WirelessNetwork(service) {
  service_name_ = SafeString(service->name);
  activation_state_ = service->activation_state;
  network_technology_ = service->network_technology;
  roaming_state_ = service->roaming_state;
  restricted_pool_ = service->restricted_pool;
  if (service->carrier_info) {
    operator_name_ = SafeString(service->carrier_info->operator_name);
    operator_code_ = SafeString(service->carrier_info->operator_code);
    payment_url_ = SafeString(service->carrier_info->payment_url);
  }
  if (service->device_info) {
    meid_ = SafeString(service->device_info->MEID);
    imei_ = SafeString(service->device_info->IMEI);
    imsi_ = SafeString(service->device_info->IMSI);
    esn_ = SafeString(service->device_info->ESN);
    mdn_ = SafeString(service->device_info->MDN);
    min_ = SafeString(service->device_info->MIN);
    model_id_ = SafeString(service->device_info->model_id);
    manufacturer_ = SafeString(service->device_info->manufacturer);
    firmware_revision_ = SafeString(service->device_info->firmware_revision);
    hardware_revision_ = SafeString(service->device_info->hardware_revision);
    last_update_ = SafeString(service->device_info->last_update);
    prl_version_ = service->device_info->PRL_version;
  }
  type_ = TYPE_CELLULAR;
}


void Network::Clear() {
  state_ = STATE_UNKNOWN;
  error_ = ERROR_UNKNOWN;
  service_path_.clear();
  device_path_.clear();
  ip_address_.clear();
  is_active_ = false;
}


void WirelessNetwork::Clear() {
  Network::Clear();
  name_.clear();
  strength_ = 0;
  auto_connect_ = false;
  favorite_ = false;
}


void CellularNetwork::Clear() {
  WirelessNetwork::Clear();
  activation_state_ = ACTIVATION_STATE_UNKNOWN;
  roaming_state_ = ROAMING_STATE_UNKNOWN;
  network_technology_ = NETWORK_TECHNOLOGY_UNKNOWN;
  restricted_pool_ = false;
  service_name_.clear();
  operator_name_.clear();
  operator_code_.clear();
  payment_url_.clear();
  meid_.clear();
  imei_.clear();
  imsi_.clear();
  esn_.clear();
  mdn_.clear();
  min_.clear();
  model_id_.clear();
  manufacturer_.clear();
  firmware_revision_.clear();
  hardware_revision_.clear();
  last_update_.clear();
  prl_version_ = 0;
}


void WifiNetwork::Clear() {
  WirelessNetwork::Clear();
  encryption_ = SECURITY_NONE;
  passphrase_.clear();
  identity_.clear();
  cert_path_.clear();
}


  void ClearNetworks() {
    if (ethernet_)
      delete ethernet_;
    ethernet_ = NULL;
    wifi_ = NULL;
    cellular_ = NULL;
    STLDeleteElements(&wifi_networks_);
    wifi_networks_.clear();
    STLDeleteElements(&cellular_networks_);
    cellular_networks_.clear();
    STLDeleteElements(&remembered_wifi_networks_);
    remembered_wifi_networks_.clear();
  }


  virtual void ConnectToWifiNetwork(const WifiNetwork* network,
                                    const std::string& password,
                                    const std::string& identity,
                                    const std::string& certpath) {
    DCHECK(network);
    if (!EnsureCrosLoaded())
      return;
    if (ConnectToNetworkWithCertInfo(network->service_path().c_str(),
        password.empty() ? NULL : password.c_str(),
        identity.empty() ? NULL : identity.c_str(),
        certpath.empty() ? NULL : certpath.c_str())) {
      WifiNetwork* wifi = GetWirelessNetworkByPath(
          wifi_networks_, network->service_path());
      if (wifi) {
        wifi->set_passphrase(password);
        wifi->set_identity(identity);
        wifi->set_cert_path(certpath);
        wifi->set_connecting(true);
        wifi_ = wifi;
      }
      NotifyNetworkManagerChanged();
    }
  }


  virtual void ConnectToWifiNetwork(ConnectionSecurity security,
                                    const std::string& ssid,
                                    const std::string& password,
                                    const std::string& identity,
                                    const std::string& certpath,
                                    bool auto_connect) {
    if (!EnsureCrosLoaded())
      return;

    ServiceInfo* service = GetWifiService(ssid.c_str(), security);
    if (service) {
      SetAutoConnect(service->service_path, auto_connect);
      ConnectToNetworkWithCertInfo(service->service_path,
          password.empty() ? NULL : password.c_str(),
          identity.empty() ? NULL : identity.c_str(),
          certpath.empty() ? NULL : certpath.c_str());

      FreeServiceInfo(service);
    } else {
      LOG(WARNING) << "Cannot find hidden network: " << ssid;
    }
  }


  virtual void ConnectToWifiNetwork(const WifiNetwork* network,
                                    const std::string& password,
                                    const std::string& identity,
                                    const std::string& certpath) {}


  virtual void ConnectToWifiNetwork(ConnectionSecurity security,
                                    const std::string& ssid,
                                    const std::string& password,
                                    const std::string& identity,
                                    const std::string& certpath,
                                    bool auto_connect) {}


  bool Connected() const {
    return ethernet_connected() || wifi_connected() || cellular_connected();
  }


  bool Connecting() const {
    return ethernet_connecting() || wifi_connecting() || cellular_connecting();
  }


bool Connecting() const { return false; }


  virtual void DisconnectFromWirelessNetwork(const WirelessNetwork* network) {
    DCHECK(network);
    if (!EnsureCrosLoaded() || !network)
      return;
    if (DisconnectFromNetwork(network->service_path().c_str())) {
      if (network->type() == TYPE_WIFI) {
        WifiNetwork* wifi = GetWirelessNetworkByPath(
            wifi_networks_, network->service_path());
        if (wifi) {
          wifi->set_connected(false);
          wifi_ = NULL;
        }
      } else if (network->type() == TYPE_CELLULAR) {
        CellularNetwork* cellular = GetWirelessNetworkByPath(
            cellular_networks_, network->service_path());
        if (cellular) {
          cellular->set_connected(false);
          cellular_ = NULL;
        }
      }
      NotifyNetworkManagerChanged();
    }
  }


virtual void DisconnectFromWirelessNetwork(const WirelessNetwork* network) {}


  virtual void EnableCellularNetworkDevice(bool enable) {
    EnableNetworkDeviceType(TYPE_CELLULAR, enable);
  }


  virtual void EnableEthernetNetworkDevice(bool enable) {
    EnableNetworkDeviceType(TYPE_ETHERNET, enable);
  }


virtual void EnableEthernetNetworkDevice(bool enable) {}


  void EnableNetworkDeviceType(ConnectionType device, bool enable) {
    if (!EnsureCrosLoaded())
      return;

    if (enable && (enabled_devices_ & (1 << device))) {
      LOG(WARNING) << "Trying to enable a device that's already enabled: "
                   << device;
      return;
    }
    if (!enable && !(enabled_devices_ & (1 << device))) {
      LOG(WARNING) << "Trying to disable a device that's already disabled: "
                   << device;
      return;
    }

    EnableNetworkDevice(device, enable);
  }


  virtual void EnableOfflineMode(bool enable) {
    if (!EnsureCrosLoaded())
      return;

    if (enable && offline_mode_) {
      VLOG(1) << "Trying to enable offline mode when it's already enabled.";
      return;
    }
    if (!enable && !offline_mode_) {
      VLOG(1) << "Trying to disable offline mode when it's already disabled.";
      return;
    }

    if (SetOfflineMode(enable)) {
      offline_mode_ = enable;
    }
  }


virtual void EnableOfflineMode(bool enable) {}


  virtual void EnableWifiNetworkDevice(bool enable) {
    EnableNetworkDeviceType(TYPE_WIFI, enable);
  }


  virtual CellularNetwork* FindCellularNetworkByPath(
      const std::string& path) { return NULL; }


  virtual WifiNetwork* FindWifiNetworkByPath(
      const std::string& path) {
    return GetWirelessNetworkByPath(wifi_networks_, path);
  }


  virtual WifiNetwork* FindWifiNetworkByPath(
      const std::string& path) { return NULL; }


  virtual void ForgetWifiNetwork(const std::string& service_path) {
    if (!EnsureCrosLoaded())
      return;
    if (DeleteRememberedService(service_path.c_str())) {
      for (WifiNetworkVector::iterator iter =
               remembered_wifi_networks_.begin();
          iter != remembered_wifi_networks_.end();
          ++iter) {
        if ((*iter)->service_path() == service_path) {
          delete (*iter);
          remembered_wifi_networks_.erase(iter);
          break;
        }
      }
      NotifyNetworkManagerChanged();
    }
  }


std::string CellularNetwork::GetActivationStateString() const {
  return ActivationStateToString(this->activation_state_);
}


std::string WifiNetwork::GetEncryptionString() {
  switch (encryption_) {
    case SECURITY_UNKNOWN:
      break;
    case SECURITY_NONE:
      return "";
    case SECURITY_WEP:
      return "WEP";
    case SECURITY_WPA:
      return "WPA";
    case SECURITY_RSN:
      return "RSN";
    case SECURITY_8021X:
      return "8021X";
  }
  return "Unknown";
}


std::string Network::GetErrorString() const {
  switch (error_) {
    case ERROR_UNKNOWN:
      return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_ERROR_UNKNOWN);
    case ERROR_OUT_OF_RANGE:
      return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_ERROR_OUT_OF_RANGE);
    case ERROR_PIN_MISSING:
      return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_ERROR_PIN_MISSING);
    case ERROR_DHCP_FAILED:
      return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_ERROR_DHCP_FAILED);
    case ERROR_CONNECT_FAILED:
      return l10n_util::GetStringUTF8(
          IDS_CHROMEOS_NETWORK_ERROR_CONNECT_FAILED);
    case ERROR_BAD_PASSPHRASE:
      return l10n_util::GetStringUTF8(
          IDS_CHROMEOS_NETWORK_ERROR_BAD_PASSPHRASE);
    case ERROR_BAD_WEPKEY:
      return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_ERROR_BAD_WEPKEY);
    case ERROR_ACTIVATION_FAILED:
      return l10n_util::GetStringUTF8(
          IDS_CHROMEOS_NETWORK_ERROR_ACTIVATION_FAILED);
    case ERROR_NEED_EVDO:
      return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_ERROR_NEED_EVDO);
    case ERROR_NEED_HOME_NETWORK:
      return l10n_util::GetStringUTF8(
          IDS_CHROMEOS_NETWORK_ERROR_NEED_HOME_NETWORK);
    case ERROR_OTASP_FAILED:
      return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_ERROR_OTASP_FAILED);
    case ERROR_AAA_FAILED:
      return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_ERROR_AAA_FAILED);
    default:
      break;
  }
  return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_STATE_UNRECOGNIZED);
}


virtual std::string GetHtmlInfo(int refresh) {
    std::string output;
    output.append("<title>About Network</title>");
    if (refresh > 0)
      output.append("<meta http-equiv=\"refresh\" content=\"" +
          base::IntToString(refresh) + "\"/>");
    output.append("");
    if (refresh > 0) {
      output.append("(Auto-refreshing page every " +
                    base::IntToString(refresh) + "s)");
    } else {
      output.append("(To auto-refresh this page: about:network/<secs>)");
    }

    output.append("
Ethernet:

");
    if (ethernet_ && ethernet_enabled()) {
      output.append("
" + ToHtmlTableHeader(ethernet_) + "
");
      output.append("
" + ToHtmlTableRow(ethernet_) + "
");
    }

    output.append("

Wifi:

");
    for (size_t i = 0; i < wifi_networks_.size(); ++i) {
      if (i == 0)
        output.append("
" + ToHtmlTableHeader(wifi_networks_[i]) + "
");
      output.append("
" + ToHtmlTableRow(wifi_networks_[i]) + "
");
    }

    output.append("

Cellular:

");
    for (size_t i = 0; i < cellular_networks_.size(); ++i) {
      if (i == 0)
        output.append("
" + ToHtmlTableHeader(cellular_networks_[i]) +
            "
");
      output.append("
" + ToHtmlTableRow(cellular_networks_[i]) + "
");
    }

    output.append("

Remembered Wifi:

");
    for (size_t i = 0; i < remembered_wifi_networks_.size(); ++i) {
      if (i == 0)
        output.append(
            "
" + ToHtmlTableHeader(remembered_wifi_networks_[i]) +
            "
");
      output.append("
" + ToHtmlTableRow(remembered_wifi_networks_[i]) +
          "
");
    }

    output.append("
");
    return output;
  }


virtual std::string GetHtmlInfo(int refresh) { return std::string(); }


  virtual NetworkIPConfigVector GetIPConfigs(const std::string& device_path,
                                             std::string* hardware_address) {
    hardware_address->clear();
    NetworkIPConfigVector ipconfig_vector;
    if (EnsureCrosLoaded() && !device_path.empty()) {
      IPConfigStatus* ipconfig_status = ListIPConfigs(device_path.c_str());
      if (ipconfig_status) {
        for (int i = 0; i < ipconfig_status->size; i++) {
          IPConfig ipconfig = ipconfig_status->ips[i];
          ipconfig_vector.push_back(
              NetworkIPConfig(device_path, ipconfig.type, ipconfig.address,
                              ipconfig.netmask, ipconfig.gateway,
                              ipconfig.name_servers));
        }
        *hardware_address = ipconfig_status->hardware_address;
        FreeIPConfigStatus(ipconfig_status);
        std::sort(ipconfig_vector.begin(), ipconfig_vector.end());
      }
    }
    return ipconfig_vector;
  }


  virtual NetworkIPConfigVector GetIPConfigs(const std::string& device_path,
                                             std::string* hardware_address) {
    hardware_address->clear();
    return NetworkIPConfigVector();
  }


NetworkLibrary* NetworkLibrary::GetImpl(bool stub) {
  if (stub)
    return new NetworkLibraryStubImpl();
  else
    return new NetworkLibraryImpl();
}


std::string CellularNetwork::GetRoamingStateString() const {
  switch (this->roaming_state_) {
    case ROAMING_STATE_HOME:
      return l10n_util::GetStringUTF8(
          IDS_CHROMEOS_NETWORK_ROAMING_STATE_HOME);
      break;
    case ROAMING_STATE_ROAMING:
      return l10n_util::GetStringUTF8(
          IDS_CHROMEOS_NETWORK_ROAMING_STATE_ROAMING);
      break;
    default:
      return l10n_util::GetStringUTF8(
          IDS_CHROMEOS_NETWORK_ROAMING_STATE_UNKNOWN);
      break;
  };
}


std::string Network::GetStateString() const {
  switch (state_) {
    case STATE_UNKNOWN:
      return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_STATE_UNKNOWN);
    case STATE_IDLE:
      return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_STATE_IDLE);
    case STATE_CARRIER:
      return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_STATE_CARRIER);
    case STATE_ASSOCIATION:
      return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_STATE_ASSOCIATION);
    case STATE_CONFIGURATION:
      return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_STATE_CONFIGURATION);
    case STATE_READY:
      return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_STATE_READY);
    case STATE_DISCONNECT:
      return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_STATE_DISCONNECT);
    case STATE_FAILURE:
      return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_STATE_FAILURE);
    case STATE_ACTIVATION_FAILURE:
      return l10n_util::GetStringUTF8(
          IDS_CHROMEOS_NETWORK_STATE_ACTIVATION_FAILURE);
    default:
      break;
  }
  return l10n_util::GetStringUTF8(IDS_CHROMEOS_NETWORK_STATE_UNRECOGNIZED);
}


  virtual bool GetWifiAccessPoints(WifiAccessPointVector* result) {
    if (!EnsureCrosLoaded())
      return false;
    DeviceNetworkList* network_list = GetDeviceNetworkList();
    if (network_list == NULL)
      return false;
    result->clear();
    result->reserve(network_list->network_size);
    const base::Time now = base::Time::Now();
    for (size_t i = 0; i < network_list->network_size; ++i) {
      DCHECK(network_list->networks[i].address);
      DCHECK(network_list->networks[i].name);
      WifiAccessPoint ap;
      ap.mac_address = SafeString(network_list->networks[i].address);
      ap.name = SafeString(network_list->networks[i].name);
      ap.timestamp = now -
          base::TimeDelta::FromSeconds(network_list->networks[i].age_seconds);
      ap.signal_strength = network_list->networks[i].strength;
      ap.channel = network_list->networks[i].channel;
      result->push_back(ap);
    }
    FreeDeviceNetworkList(network_list);
    return true;
  }


  virtual bool GetWifiAccessPoints(WifiAccessPointVector* result) {
    return false;
  }


  WifiNetwork* GetWifiNetworkByName(const std::string& name) {
    for (size_t i = 0; i < wifi_networks_.size(); ++i) {
      if (wifi_networks_[i]->name().compare(name) == 0) {
        return wifi_networks_[i];
      }
    }
    return NULL;
  }


  template<typename T> T GetWirelessNetworkByPath(
      std::vector<T>& networks, const std::string& path) {
    typedef typename std::vector<T>::iterator iter_t;
    iter_t iter = std::find_if(networks.begin(), networks.end(),
                               WirelessNetwork::ServicePathEq(path));
    return (iter != networks.end()) ? *iter : NULL;
  }


  template<typename T> const T GetWirelessNetworkByPath(
      const std::vector<T>& networks, const std::string& path) const {
    typedef typename std::vector<T>::const_iterator iter_t;
    iter_t iter = std::find_if(networks.begin(), networks.end(),
                               WirelessNetwork::ServicePathEq(path));
    return (iter != networks.end()) ? *iter : NULL;
  }


  const std::string& IPAddress() const {
    const Network* active = active_network();
    if (active != NULL)
      return active->ip_address();
    if (ethernet_)
      return ethernet_->ip_address();
    static std::string null_address("0.0.0.0");
    return null_address;
  }


const std::string& IPAddress() const { return ip_address_; }


  void Init() {
    VLOG(1) << "Getting initial CrOS network info.";
    UpdateSystemInfo();
  }


  void InitTestData() {
    ethernet_ = new EthernetNetwork();
    ethernet_->set_connected(true);
    ethernet_->set_service_path("eth1");

    STLDeleteElements(&wifi_networks_);
    wifi_networks_.clear();
    WifiNetwork* wifi1 = new WifiNetwork();
    wifi1->set_service_path("fw1");
    wifi1->set_name("Fake Wifi 1");
    wifi1->set_strength(90);
    wifi1->set_connected(false);
    wifi1->set_encryption(SECURITY_NONE);
    wifi_networks_.push_back(wifi1);

    WifiNetwork* wifi2 = new WifiNetwork();
    wifi2->set_service_path("fw2");
    wifi2->set_name("Fake Wifi 2");
    wifi2->set_strength(70);
    wifi2->set_connected(true);
    wifi2->set_encryption(SECURITY_WEP);
    wifi_networks_.push_back(wifi2);

    WifiNetwork* wifi3 = new WifiNetwork();
    wifi3->set_service_path("fw3");
    wifi3->set_name("Fake Wifi 3");
    wifi3->set_strength(50);
    wifi3->set_connected(false);
    wifi3->set_encryption(SECURITY_WEP);
    wifi_networks_.push_back(wifi3);

    wifi_ = wifi2;

    STLDeleteElements(&cellular_networks_);
    cellular_networks_.clear();

    CellularNetwork* cellular1 = new CellularNetwork();
    cellular1->set_service_path("fc1");
    cellular1->set_name("Fake Cellular 1");
    cellular1->set_strength(70);
    cellular1->set_connected(true);
    cellular1->set_activation_state(ACTIVATION_STATE_PARTIALLY_ACTIVATED);
    cellular1->set_payment_url(std::string("http://www.google.com"));
    cellular_networks_.push_back(cellular1);
    cellular_ = cellular1;

    remembered_wifi_networks_.clear();
    remembered_wifi_networks_.push_back(new WifiNetwork(*wifi2));

    int devices = (1 << TYPE_ETHERNET) | (1 << TYPE_WIFI) |
        (1 << TYPE_CELLULAR);
    available_devices_ = devices;
    enabled_devices_ = devices;
    connected_devices_ = devices;
    offline_mode_ = false;
  }


bool WifiNetwork::IsCertificateLoaded() const {
  static const std::string settings_string("SETTINGS:");
  static const std::string pkcs11_key("key_id");
  if (cert_path_.find(settings_string) == 0) {
    std::string::size_type idx = cert_path_.find(pkcs11_key);
    if (idx != std::string::npos)
      idx = cert_path_.find_first_not_of(kWhitespaceASCII,
                                         idx + pkcs11_key.length());
    if (idx != std::string::npos && cert_path_[idx] == '=')
      return true;
  }
  return false;
}


Network::Network(const Network& network) {
  service_path_ = network.service_path();
  device_path_ = network.device_path();
  ip_address_ = network.ip_address();
  type_ = network.type();
  state_ = network.state();
  error_ = network.error();
}


Network::Network(const ServiceInfo* service) {
  type_ = service->type;
  state_ = service->state;
  error_ = service->error;
  service_path_ = SafeString(service->service_path);
  device_path_ = SafeString(service->device_path);
  is_active_ = service->is_active;
  ip_address_.clear();
  if (EnsureCrosLoaded() && connected() && service->device_path) {
    IPConfigStatus* ipconfig_status = ListIPConfigs(service->device_path);
    if (ipconfig_status) {
      for (int i = 0; i < ipconfig_status->size; i++) {
        IPConfig ipconfig = ipconfig_status->ips[i];
        if (strlen(ipconfig.address) > 0)
          ip_address_ = ipconfig.address;
      }
      FreeIPConfigStatus(ipconfig_status);
    }
  }
}


  NetworkLibraryImpl()
      : network_manager_monitor_(NULL),
        data_plan_monitor_(NULL),
        ethernet_(NULL),
        wifi_(NULL),
        cellular_(NULL),
        available_devices_(0),
        enabled_devices_(0),
        connected_devices_(0),
        offline_mode_(false) {
    if (EnsureCrosLoaded()) {
      Init();
      network_manager_monitor_ =
          MonitorNetworkManager(&NetworkManagerStatusChangedHandler,
                                this);
      data_plan_monitor_ = MonitorCellularDataPlan(&DataPlanUpdateHandler,
                                                   this);
    } else {
      InitTestData();
    }
  }


    NetworkObserverList(NetworkLibraryImpl* library,
                        const std::string& service_path) {
      network_monitor_ = MonitorNetworkService(&NetworkStatusChangedHandler,
                                               service_path.c_str(),
                                               library);
    }


    static void NetworkStatusChangedHandler(void* object,
                                            const char* path,
                                            const char* key,
                                            const Value* value) {
      NetworkLibraryImpl* networklib = static_cast<NetworkLibraryImpl*>(object);
      DCHECK(networklib);
      networklib->UpdateNetworkStatus(path, key, value);
    }


  void NotifyNetworkChanged(Network* network) {
    DCHECK(network);
    NetworkObserverMap::const_iterator iter = network_observers_.find(
        network->service_path());
    if (iter != network_observers_.end()) {
      FOR_EACH_OBSERVER(NetworkObserver,
                        *(iter->second),
                        OnNetworkChanged(this, network));
    } else {
      NOTREACHED() <<
          "There weren't supposed to be any property change observers of " <<
           network->service_path();
    }
  }


static ActivationState ParseActivationState(
    const std::string& activation_state) {
  if (activation_state == kActivationStateActivated)
    return ACTIVATION_STATE_ACTIVATED;
  if (activation_state == kActivationStateActivating)
    return ACTIVATION_STATE_ACTIVATING;
  if (activation_state == kActivationStateNotActivated)
    return ACTIVATION_STATE_NOT_ACTIVATED;
  if (activation_state == kActivationStateUnknown)
    return ACTIVATION_STATE_UNKNOWN;
  if (activation_state == kActivationStatePartiallyActivated)
    return ACTIVATION_STATE_PARTIALLY_ACTIVATED;
  return ACTIVATION_STATE_UNKNOWN;
}


static NetworkTechnology ParseNetworkTechnology(
    const std::string& technology) {
    if (technology == kNetworkTechnology1Xrtt)
    return NETWORK_TECHNOLOGY_1XRTT;
  if (technology == kNetworkTechnologyEvdo)
    return NETWORK_TECHNOLOGY_EVDO;
  if (technology == kNetworkTechnologyGprs)
    return NETWORK_TECHNOLOGY_GPRS;
  if (technology == kNetworkTechnologyEdge)
    return NETWORK_TECHNOLOGY_EDGE;
  if (technology == kNetworkTechnologyUmts)
    return NETWORK_TECHNOLOGY_UMTS;
  if (technology == kNetworkTechnologyHspa)
    return NETWORK_TECHNOLOGY_HSPA;
  if (technology == kNetworkTechnologyHspaPlus)
    return NETWORK_TECHNOLOGY_HSPA_PLUS;
  if (technology == kNetworkTechnologyLte)
    return NETWORK_TECHNOLOGY_LTE;
  if (technology == kNetworkTechnologyLteAdvanced)
    return NETWORK_TECHNOLOGY_LTE_ADVANCED;
  return NETWORK_TECHNOLOGY_UNKNOWN;
}


static NetworkRoamingState ParseRoamingState(
    const std::string& roaming_state) {
    if (roaming_state == kRoamingStateHome)
    return ROAMING_STATE_HOME;
  if (roaming_state == kRoamingStateRoaming)
    return ROAMING_STATE_ROAMING;
  if (roaming_state == kRoamingStateUnknown)
    return ROAMING_STATE_UNKNOWN;
  return ROAMING_STATE_UNKNOWN;
}


static ConnectionState ParseState(const std::string& state) {
  if (state == kStateIdle)
    return STATE_IDLE;
  if (state == kStateCarrier)
    return STATE_CARRIER;
  if (state == kStateAssociation)
    return STATE_ASSOCIATION;
  if (state == kStateConfiguration)
    return STATE_CONFIGURATION;
  if (state == kStateReady)
    return STATE_READY;
  if (state == kStateDisconnect)
    return STATE_DISCONNECT;
  if (state == kStateFailure)
    return STATE_FAILURE;
  if (state == kStateActivationFailure)
    return STATE_ACTIVATION_FAILURE;
  return STATE_UNKNOWN;
}


  static void ParseSystem(SystemInfo* system,
      EthernetNetwork** ethernet,
      WifiNetworkVector* wifi_networks,
      CellularNetworkVector* cellular_networks,
      WifiNetworkVector* remembered_wifi_networks) {
    DVLOG(1) << "ParseSystem:";
    DCHECK(!(*ethernet));
    for (int i = 0; i < system->service_size; i++) {
      const ServiceInfo* service = system->GetServiceInfo(i);
      DVLOG(1) << "  (" << service->type << ") " << service->name
               << " mode=" << service->mode
               << " state=" << service->state
               << " sec=" << service->security
               << " req=" << service->passphrase_required
               << " pass=" << service->passphrase
               << " id=" << service->identity
               << " certpath=" << service->cert_path
               << " str=" << service->strength
               << " fav=" << service->favorite
               << " auto=" << service->auto_connect
               << " is_active=" << service->is_active
               << " error=" << service->error;
      if (service->type == TYPE_ETHERNET)
        (*ethernet) = new EthernetNetwork(service);
      else if (service->type == TYPE_WIFI) {
        wifi_networks->push_back(new WifiNetwork(service));
      } else if (service->type == TYPE_CELLULAR) {
        cellular_networks->push_back(new CellularNetwork(service));
      }
    }

    if (!(*ethernet))
      (*ethernet) = new EthernetNetwork();

    DVLOG(1) << "Remembered networks:";
    for (int i = 0; i < system->remembered_service_size; i++) {
      const ServiceInfo* service = system->GetRememberedServiceInfo(i);
      if (service->auto_connect) {
        DVLOG(1) << "  (" << service->type << ") " << service->name
                 << " mode=" << service->mode
                 << " sec=" << service->security
                 << " pass=" << service->passphrase
                 << " id=" << service->identity
                 << " certpath=" << service->cert_path
                 << " auto=" << service->auto_connect;
        if (service->type == TYPE_WIFI) {
          remembered_wifi_networks->push_back(new WifiNetwork(service));
        }
      }
    }
  }


  virtual void RefreshCellularDataPlans(const CellularNetwork* network) {
    DCHECK(network);
    if (!EnsureCrosLoaded() || !network)
      return;
    RequestCellularDataPlanUpdate(network->service_path().c_str());
  }


virtual void RefreshCellularDataPlans(const CellularNetwork* network) {}


  virtual void RemoveCellularDataPlanObserver(
      CellularDataPlanObserver* observer) {
    data_plan_observers_.RemoveObserver(observer);
  }


  virtual void RemoveCellularDataPlanObserver(
      CellularDataPlanObserver* observer) {}


  virtual void RemoveNetworkManagerObserver(NetworkManagerObserver* observer) {
    network_manager_observers_.RemoveObserver(observer);
  }


virtual void RemoveNetworkManagerObserver(NetworkManagerObserver* observer) {}


  virtual void RemoveNetworkObserver(const std::string& service_path,
                                     NetworkObserver* observer) {
    DCHECK(observer);
    DCHECK(service_path.size());
    NetworkObserverMap::iterator map_iter =
        network_observers_.find(service_path);
    if (map_iter != network_observers_.end()) {
      map_iter->second->RemoveObserver(observer);
      if (!map_iter->second->size()) {
        delete map_iter->second;
        network_observers_.erase(map_iter++);
      }
    }
  }


  virtual void RemoveNetworkObserver(const std::string& service_path,
                                     NetworkObserver* observer) {}


  virtual void RemoveObserverForAllNetworks(NetworkObserver* observer) {
    DCHECK(observer);
    NetworkObserverMap::iterator map_iter = network_observers_.begin();
    while (map_iter != network_observers_.end()) {
      map_iter->second->RemoveObserver(observer);
      if (!map_iter->second->size()) {
        delete map_iter->second;
        network_observers_.erase(map_iter++);
      } else {
        ++map_iter;
      }
    }
  }


virtual void RemoveObserverForAllNetworks(NetworkObserver* observer) {}


  virtual void RequestWifiScan() {
    if (EnsureCrosLoaded()) {
      RequestScan(TYPE_WIFI);
    }
  }


static std::string SafeString(const char* s) {
  return s ? std::string(s) : std::string();
}


  virtual void SaveCellularNetwork(const CellularNetwork* network) {
    DCHECK(network);
    if (!EnsureCrosLoaded() || !network)
      return;

    SetAutoConnect(network->service_path().c_str(), network->auto_connect());
  }


virtual void SaveCellularNetwork(const CellularNetwork* network) {}


  virtual void SaveWifiNetwork(const WifiNetwork* network) {
    DCHECK(network);
    if (!EnsureCrosLoaded() || !network)
      return;
    SetPassphrase(
        network->service_path().c_str(), network->passphrase().c_str());
    SetIdentity(network->service_path().c_str(),
        network->identity().c_str());
    SetCertPath(network->service_path().c_str(),
        network->cert_path().c_str());
    SetAutoConnect(network->service_path().c_str(), network->auto_connect());
  }


virtual void SaveWifiNetwork(const WifiNetwork* network) {}


bool CellularNetwork::StartActivation() const {
  if (!EnsureCrosLoaded())
    return false;
  return ActivateCellularModem(service_path_.c_str(), NULL);
}


static std::string ToHtmlTableHeader(Network* network) {
  std::string str;
  if (network->type() == TYPE_WIFI || network->type() == TYPE_CELLULAR) {
    str += WrapWithTH("Name") + WrapWithTH("Auto-Connect") +
        WrapWithTH("Strength");
    if (network->type() == TYPE_WIFI)
      str += WrapWithTH("Encryption") + WrapWithTH("Passphrase") +
          WrapWithTH("Identity") + WrapWithTH("Certificate");
  }
  str += WrapWithTH("State") + WrapWithTH("Error") + WrapWithTH("IP Address");
  return str;
}


static std::string ToHtmlTableRow(Network* network) {
  std::string str;
  if (network->type() == TYPE_WIFI || network->type() == TYPE_CELLULAR) {
    WirelessNetwork* wireless = static_cast<WirelessNetwork*>(network);
    str += WrapWithTD(wireless->name()) +
        WrapWithTD(base::IntToString(wireless->auto_connect())) +
        WrapWithTD(base::IntToString(wireless->strength()));
    if (network->type() == TYPE_WIFI) {
      WifiNetwork* wifi = static_cast<WifiNetwork*>(network);
      str += WrapWithTD(wifi->GetEncryptionString()) +
          WrapWithTD(std::string(wifi->passphrase().length(), '*')) +
          WrapWithTD(wifi->identity()) + WrapWithTD(wifi->cert_path());
    }
  }
  str += WrapWithTD(network->GetStateString()) +
      WrapWithTD(network->failed() ? network->GetErrorString() : "") +
      WrapWithTD(network->ip_address());
  return str;
}


  void UpdateCellularDataPlan(const CellularDataPlanList* data_plans) {
    DCHECK(cellular_);
    cellular_->SetDataPlans(data_plans);
    NotifyCellularDataPlanChanged();
  }


  void UpdateNetworkStatus(const char* path,
                           const char* key,
                           const Value* value) {
    if (key == NULL || value == NULL)
      return;
    if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
      BrowserThread::PostTask(
          BrowserThread::UI, FROM_HERE,
          NewRunnableMethod(this,
                            &NetworkLibraryImpl::UpdateNetworkStatus,
                            path, key, value));
      return;
    }

    bool boolval = false;
    int intval = 0;
    std::string stringval;
    Network* network;
    if (ethernet_->service_path() == path) {
      network = ethernet_;
    } else {
      CellularNetwork* cellular =
          GetWirelessNetworkByPath(cellular_networks_, path);
      WifiNetwork* wifi =
          GetWirelessNetworkByPath(wifi_networks_, path);
      if (cellular == NULL && wifi == NULL)
        return;

      WirelessNetwork* wireless;
      if (wifi != NULL)
        wireless = static_cast<WirelessNetwork*>(wifi);
      else
        wireless = static_cast<WirelessNetwork*>(cellular);

      if (strcmp(key, kSignalStrengthProperty) == 0) {
        if (value->GetAsInteger(&intval))
          wireless->set_strength(intval);
      } else if (cellular != NULL) {
        if (strcmp(key, kRestrictedPoolProperty) == 0) {
          if (value->GetAsBoolean(&boolval))
            cellular->set_restricted_pool(boolval);
        } else if (strcmp(key, kActivationStateProperty) == 0) {
          if (value->GetAsString(&stringval))
            cellular->set_activation_state(ParseActivationState(stringval));
        } else if (strcmp(key, kPaymentURLProperty) == 0) {
          if (value->GetAsString(&stringval))
            cellular->set_payment_url(stringval);
        } else if (strcmp(key, kNetworkTechnologyProperty) == 0) {
          if (value->GetAsString(&stringval))
            cellular->set_network_technology(
                ParseNetworkTechnology(stringval));
        } else if (strcmp(key, kRoamingStateProperty) == 0) {
          if (value->GetAsString(&stringval))
            cellular->set_roaming_state(ParseRoamingState(stringval));
        }
      }
      network = wireless;
    }
    if (strcmp(key, kIsActiveProperty) == 0) {
      if (value->GetAsBoolean(&boolval))
        network->set_active(boolval);
    } else if (strcmp(key, kStateProperty) == 0) {
      if (value->GetAsString(&stringval))
        network->set_state(ParseState(stringval));
    }
    NotifyNetworkChanged(network);
  }


  void UpdateSystemInfo() {
    if (EnsureCrosLoaded()) {
      UpdateNetworkManagerStatus();
    }
  }


WifiNetwork::WifiNetwork()
    : WirelessNetwork(),
      encryption_(SECURITY_NONE) {
  type_ = TYPE_WIFI;
}


WifiNetwork::WifiNetwork(const WifiNetwork& network)
    : WirelessNetwork(network) {
  encryption_ = network.encryption();
  passphrase_ = network.passphrase();
  identity_ = network.identity();
  cert_path_ = network.cert_path();
}


WirelessNetwork::WirelessNetwork(const WirelessNetwork& network)
    : Network(network) {
  name_ = network.name();
  strength_ = network.strength();
  auto_connect_ = network.auto_connect();
  favorite_ = network.favorite();
}


WirelessNetwork::WirelessNetwork(const ServiceInfo* service)
    : Network(service) {
  name_ = SafeString(service->name);
  strength_ = service->strength;
  auto_connect_ = service->auto_connect;
  favorite_ = service->favorite;
}


static std::string WrapWithTD(std::string text) {
  return "<td>" + text + "</td>";
}


static std::string WrapWithTH(std::string text) {
  return "<th>" + text + "</th>";
}


  virtual const Network* active_network() const {
    if (ethernet_ && ethernet_->is_active())
      return ethernet_;
    if (wifi_ && wifi_->is_active())
      return wifi_;
    if (cellular_ && cellular_->is_active())
      return cellular_;
    return NULL;
  }


virtual const Network* active_network() const { return NULL; }


  virtual bool cellular_available() const {
    return available_devices_ & (1 << TYPE_CELLULAR);
  }


virtual bool cellular_available() const { return false; }


  virtual bool cellular_connected() const {
    return cellular_ ? cellular_->connected() : false;
  }


virtual bool cellular_connected() const { return false; }


  virtual bool cellular_connecting() const {
    return cellular_ ? cellular_->connecting() : false;
  }


virtual bool cellular_connecting() const { return false; }


  virtual bool cellular_enabled() const {
    return enabled_devices_ & (1 << TYPE_CELLULAR);
  }


virtual CellularNetwork* cellular_network() { return cellular_; }


  virtual const CellularNetworkVector& cellular_networks() const {
    return cellular_networks_;
  }


CellularNetwork::DataLeft CellularNetwork::data_left() const {
  if (data_plans_.empty())
    return DATA_NORMAL;
  const CellularDataPlan& plan(data_plans_[0]);
  if (plan.plan_type == CELLULAR_DATA_PLAN_UNLIMITED) {
    base::TimeDelta remaining = plan.plan_end_time - plan.update_time;
    if (remaining <= base::TimeDelta::FromSeconds(0))
      return DATA_NONE;
    else if (remaining <=
        base::TimeDelta::FromSeconds(kCellularDataVeryLowSecs))
      return DATA_VERY_LOW;
    else if (remaining <= base::TimeDelta::FromSeconds(kCellularDataLowSecs))
      return DATA_LOW;
    else
      return DATA_NORMAL;
  } else if (plan.plan_type == CELLULAR_DATA_PLAN_METERED_PAID ||
             plan.plan_type == CELLULAR_DATA_PLAN_METERED_BASE) {
    int64 remaining = plan.plan_data_bytes - plan.data_bytes_used;
    if (remaining <= 0)
      return DATA_NONE;
    else if (remaining <= kCellularDataVeryLowBytes)
      return DATA_VERY_LOW;
    else if (remaining <= kCellularDataLowBytes)
      return DATA_LOW;
    else
      return DATA_NORMAL;
  }
  return DATA_NORMAL;
}


virtual bool ethernet_available() const { return true; }


  virtual bool ethernet_connected() const {
    return ethernet_ ? ethernet_->connected() : false;
  }


virtual bool ethernet_connected() const { return true; }


virtual bool ethernet_connecting() const { return false; }


  virtual bool ethernet_enabled() const {
    return enabled_devices_ & (1 << TYPE_ETHERNET);
  }


virtual bool ethernet_enabled() const { return true; }


virtual EthernetNetwork* ethernet_network() { return ethernet_; }


  virtual bool has_cellular_networks() const {
    return cellular_networks_.begin() != cellular_networks_.end();
  }


bool CellularNetwork::is_gsm() const {
  return network_technology_ != NETWORK_TECHNOLOGY_EVDO &&
      network_technology_ != NETWORK_TECHNOLOGY_1XRTT &&
      network_technology_ != NETWORK_TECHNOLOGY_UNKNOWN;
}


virtual bool offline_mode() const { return offline_mode_; }


virtual bool offline_mode() const { return false; }


  virtual const WifiNetworkVector& remembered_wifi_networks() const {
    return remembered_wifi_networks_;
  }


  virtual const WifiNetworkVector& remembered_wifi_networks() const {
    return wifi_networks_;
  }


  virtual bool wifi_available() const {
    return available_devices_ & (1 << TYPE_WIFI);
  }


virtual bool wifi_available() const { return false; }


virtual bool wifi_connected() const { return false; }


  virtual bool wifi_connecting() const {
    return wifi_ ? wifi_->connecting() : false;
  }


virtual bool wifi_connecting() const { return false; }


  virtual bool wifi_enabled() const {
    return enabled_devices_ & (1 << TYPE_WIFI);
  }


virtual bool wifi_enabled() const { return false; }


virtual WifiNetwork* wifi_network() { return wifi_; }


  virtual const WifiNetworkVector& wifi_networks() const {
    return wifi_networks_;
  }


  ~NetworkLibraryImpl() {
    network_manager_observers_.Clear();
    if (network_manager_monitor_)
      DisconnectPropertyChangeMonitor(network_manager_monitor_);
    data_plan_observers_.Clear();
    if (data_plan_monitor_)
      DisconnectDataPlanUpdateMonitor(data_plan_monitor_);
    STLDeleteValues(&network_observers_);
    ClearNetworks();
  }


~NetworkLibraryStubImpl() { if (ethernet_) delete ethernet_; }


    virtual ~NetworkObserverList() {
      if (network_monitor_)
        DisconnectPropertyChangeMonitor(network_monitor_);
    }


  bool AddCallback(GetUsageAndQuotaCallback* callback, bool unlimited) {
    if (unlimited)
      unlimited_callbacks_.push_back(callback);
    else
      callbacks_.push_back(callback);
    return (callbacks_.size() + unlimited_callbacks_.size() == 1);
  }


  bool AppendEntry(const TableEntry& entry) {
    entries_.push_back(entry);
    return true;
  }


  void CallCallbacksAndClear(
      CallbackList* callbacks, QuotaStatusCode status,
      int64 usage, int64 quota) {
    for (CallbackList::iterator iter = callbacks->begin();
         iter != callbacks->end(); ++iter) {
      (*iter)->Run(status, usage, quota);
      delete *iter;
    }
    callbacks->clear();
  }


  void CheckCompleted() {
    if (--waiting_callbacks_ <= 0) {
      DispatchCallbacks();
      DCHECK(callbacks_.empty());
      DCHECK(unlimited_callbacks_.empty());

      UsageAndQuotaDispatcherTaskMap& dispatcher_map =
          manager()->usage_and_quota_dispatchers_;
      DCHECK(dispatcher_map.find(std::make_pair(host_, type_)) !=
             dispatcher_map.end());
      dispatcher_map.erase(std::make_pair(host_, type_));
      CallCompleted();
    }
  }


void CountOriginType(const std::set<GURL>& origins,
                     SpecialStoragePolicy* policy,
                     size_t* protected_origins,
                     size_t* unlimited_origins) {
  DCHECK(protected_origins);
  DCHECK(unlimited_origins);
  *protected_origins = 0;
  *unlimited_origins = 0;
  if (!policy)
    return;
  for (std::set<GURL>::const_iterator itr = origins.begin();
       itr != origins.end();
       ++itr) {
    if (policy->IsStorageProtected(*itr))
      ++*protected_origins;
    if (policy->IsStorageUnlimited(*itr))
      ++*unlimited_origins;
  }
}


QuotaManager::UsageAndQuotaDispatcherTask::Create(
    QuotaManager* manager, const std::string& host, StorageType type) {
  switch (type) {
    case kStorageTypeTemporary:
      return new UsageAndQuotaDispatcherTaskForTemporary(
          manager, host);
    case kStorageTypePersistent:
      return new UsageAndQuotaDispatcherTaskForPersistent(
          manager, host);
    default:
      NOTREACHED();
  }
  return NULL;
}


void QuotaManager::DeleteOnCorrectThread() const {
  if (!io_thread_->BelongsToCurrentThread()) {
    io_thread_->DeleteSoon(FROM_HERE, this);
    return;
  }
  delete this;
}


void QuotaManager::DeleteOriginData(
    const GURL& origin, StorageType type, StatusCallback* callback) {
  LazyInitialize();

  if (origin.is_empty() || clients_.empty()) {
    callback->Run(kQuotaStatusOk);
    delete callback;
    return;
  }

  OriginDataDeleter* deleter =
      new OriginDataDeleter(this, origin, type, callback);
  deleter->Start();
}


  DeleteOriginInfo(
      QuotaManager* manager,
      const GURL& origin,
      StorageType type)
      : DatabaseTaskBase(manager),
        origin_(origin),
        type_(type) {}


  void DidDeleteOriginData(QuotaStatusCode status) {
    DCHECK_GT(remaining_clients_, 0);

    if (status != kQuotaStatusOk)
      ++error_count_;

    if (--remaining_clients_ == 0)
      CallCompleted();
  }


void QuotaManager::DidGetAvailableSpaceForEviction(
    QuotaStatusCode status,
    int64 available_space) {
  eviction_context_.get_usage_and_quota_callback->Run(status,
      eviction_context_.usage,
      eviction_context_.unlimited_usage,
      eviction_context_.quota, available_space);
  eviction_context_.get_usage_and_quota_callback.reset();
}


void QuotaManager::DidGetDatabaseLRUOrigin(const GURL& origin) {
  if (origins_in_use_.find(origin) != origins_in_use_.end() ||
      access_notified_origins_.find(origin) != access_notified_origins_.end())
    lru_origin_callback_->Run(GURL());
  else
    lru_origin_callback_->Run(origin);
  access_notified_origins_.clear();
  lru_origin_callback_.reset();
}


  void DidGetGlobalQuota(QuotaStatusCode status,
                         StorageType type,
                         int64 quota) {
    DCHECK_EQ(type_, type);
    quota_status_ = status;
    quota_ = quota;
    CheckCompleted();
  }


void QuotaManager::DidGetGlobalQuotaForEviction(
    QuotaStatusCode status,
    StorageType type,
    int64 quota) {
  DCHECK_EQ(type, kStorageTypeTemporary);
  if (status != kQuotaStatusOk) {
    eviction_context_.get_usage_and_quota_callback->Run(
        status, 0, 0, 0, 0);
    eviction_context_.get_usage_and_quota_callback.reset();
    return;
  }

  eviction_context_.quota = quota;
  GetAvailableSpace(callback_factory_.
      NewCallback(&QuotaManager::DidGetAvailableSpaceForEviction));
}


  void DidGetGlobalUsage(StorageType type, int64 usage,
                         int64 unlimited_usage) {
    DCHECK_EQ(type_, type);
    DCHECK_GE(usage, unlimited_usage);
    global_usage_ = usage;
    global_unlimited_usage_ = unlimited_usage;
    CheckCompleted();
  }


void QuotaManager::DidGetGlobalUsageForEviction(
    StorageType type, int64 usage, int64 unlimited_usage) {
  DCHECK_EQ(type, kStorageTypeTemporary);
  DCHECK_GE(usage, unlimited_usage);
  eviction_context_.usage = usage;
  eviction_context_.unlimited_usage = unlimited_usage;
  GetTemporaryGlobalQuota(callback_factory_.
      NewCallback(&QuotaManager::DidGetGlobalQuotaForEviction));
}


  void DidGetHostQuota(QuotaStatusCode status,
                       const std::string& host,
                       StorageType type,
                       int64 quota) {
    DCHECK_EQ(host_, host);
    DCHECK_EQ(type_, type);
    quota_status_ = status;
    quota_ = quota;
    CheckCompleted();
  }


  void DidGetHostUsage(const std::string& host,
                       StorageType type,
                       int64 usage) {
    DCHECK_EQ(host_, host);
    DCHECK_EQ(type_, type);
    host_usage_ = usage;
    CheckCompleted();
  }


void QuotaManager::DidGetPersistentGlobalUsageForHistogram(
    StorageType type,
    int64 usage,
    int64 unlimited_usage) {
  UMA_HISTOGRAM_MBYTES("Quota.GlobalUsageOfPersistentStorage", usage);

  std::set<GURL> origins;
  GetCachedOrigins(type, &origins);

  size_t num_origins = origins.size();
  size_t protected_origins = 0;
  size_t unlimited_origins = 0;
  CountOriginType(origins, special_storage_policy_,
                  &protected_origins, &unlimited_origins);

  UMA_HISTOGRAM_COUNTS("Quota.NumberOfPersistentStorageOrigins",
                       num_origins);
  UMA_HISTOGRAM_COUNTS("Quota.NumberOfProtectedPersistentStorageOrigins",
                       protected_origins);
  UMA_HISTOGRAM_COUNTS("Quota.NumberOfUnlimitedPersistentStorageOrigins",
                       unlimited_origins);
}


void QuotaManager::DidInitializeTemporaryGlobalQuota(int64 quota) {
  temporary_global_quota_ = quota;
  temporary_global_quota_callbacks_.Run(
      db_disabled_ ? kQuotaErrorInvalidAccess : kQuotaStatusOk,
      kStorageTypeTemporary, quota);

  if (db_disabled_ || eviction_disabled_)
    return;

  if (!need_initialize_origins_) {
    StartEviction();
    return;
  }

  temporary_usage_tracker_->GetGlobalUsage(callback_factory_.NewCallback(
      &QuotaManager::DidRunInitialGetTemporaryGlobalUsage));
}


void QuotaManager::DidRunInitialGetTemporaryGlobalUsage(
    StorageType type, int64 usage_unused, int64 unlimited_usage_unused) {
  DCHECK_EQ(type, kStorageTypeTemporary);
  scoped_refptr<InitializeTemporaryOriginsInfoTask> task(
      new InitializeTemporaryOriginsInfoTask(
          this, temporary_usage_tracker_.get()));
  task->Start();
}


void QuotaManager::DumpOriginInfoTable(
    DumpOriginInfoTableCallback* callback) {
  make_scoped_refptr(new DumpOriginInfoTableTask(this, callback))->Start();
}


  DumpOriginInfoTableTask(
      QuotaManager* manager,
      Callback* callback)
      : DatabaseTaskBase(manager),
        callback_(callback) {
  }


void QuotaManager::DumpQuotaTable(DumpQuotaTableCallback* callback) {
  make_scoped_refptr(new DumpQuotaTableTask(this, callback))->Start();
}


  DumpQuotaTableTask(
      QuotaManager* manager,
      Callback* callback)
      : DatabaseTaskBase(manager),
        callback_(callback) {
  }


void QuotaManager::EvictOriginData(
    const GURL& origin,
    StorageType type,
    EvictOriginDataCallback* callback) {
  DCHECK(io_thread_->BelongsToCurrentThread());
  DCHECK_EQ(type, kStorageTypeTemporary);

  eviction_context_.evicted_origin = origin;
  eviction_context_.evicted_type = type;
  eviction_context_.evict_origin_data_callback.reset(callback);

  DeleteOriginData(origin, type, callback_factory_.NewCallback(
      &QuotaManager::DidOriginDataEvicted));
}


void QuotaManager::GetAvailableSpace(AvailableSpaceCallback* callback) {
  scoped_refptr<AvailableSpaceQueryTask> task(
      new AvailableSpaceQueryTask(this, db_thread_, profile_path_, callback));
  task->Start();
}


void QuotaManager::GetCachedOrigins(
    StorageType type, std::set<GURL>* origins) {
  DCHECK(origins);
  LazyInitialize();
  switch (type) {
    case kStorageTypeTemporary:
      DCHECK(temporary_usage_tracker_.get());
      temporary_usage_tracker_->GetCachedOrigins(origins);
      return;
    case kStorageTypePersistent:
      DCHECK(persistent_usage_tracker_.get());
      persistent_usage_tracker_->GetCachedOrigins(origins);
      return;
    default:
      NOTREACHED();
  }
}


void QuotaManager::GetGlobalUsage(
    StorageType type,
    GlobalUsageCallback* callback) {
  LazyInitialize();
  GetUsageTracker(type)->GetGlobalUsage(callback);
}


void QuotaManager::GetHostUsage(const std::string& host, StorageType type,
                                HostUsageCallback* callback) {
  LazyInitialize();
  GetUsageTracker(type)->GetHostUsage(host, callback);
}


int64 GetInitialTemporaryStorageQuotaSize(const FilePath& path,
                                          bool is_incognito) {
  int64 free_space = base::SysInfo::AmountOfFreeDiskSpace(path);
  UMA_HISTOGRAM_MBYTES("Quota.FreeDiskSpaceForProfile", free_space);

  if (free_space < QuotaManager::kTemporaryStorageQuotaDefaultSize * 2)
    return 0;

  if (is_incognito)
    return QuotaManager::kIncognitoDefaultTemporaryQuota;

  if (free_space < QuotaManager::kTemporaryStorageQuotaDefaultSize * 20)
    return QuotaManager::kTemporaryStorageQuotaDefaultSize;

  if (free_space < QuotaManager::kTemporaryStorageQuotaMaxSize * 20)
    return free_space / 20;

  return QuotaManager::kTemporaryStorageQuotaMaxSize;
}


void QuotaManager::GetLRUOrigin(
    StorageType type,
    GetLRUOriginCallback* callback) {
  LazyInitialize();
  DCHECK(!lru_origin_callback_.get());
  lru_origin_callback_.reset(callback);
  if (db_disabled_) {
    lru_origin_callback_->Run(GURL());
    lru_origin_callback_.reset();
    return;
  }
  scoped_refptr<GetLRUOriginTask> task(new GetLRUOriginTask(
      this, type, origins_in_use_,
      origins_in_error_, callback_factory_.NewCallback(
          &QuotaManager::DidGetDatabaseLRUOrigin)));
  task->Start();
}


  GetLRUOriginTask(
      QuotaManager* manager,
      StorageType type,
      const std::map<GURL, int>& origins_in_use,
      const std::map<GURL, int>& origins_in_error,
      GetLRUOriginCallback *callback)
      : DatabaseTaskBase(manager),
        type_(type),
        callback_(callback),
        special_storage_policy_(manager->special_storage_policy_) {
    for (std::map<GURL, int>::const_iterator p = origins_in_use.begin();
         p != origins_in_use.end();
         ++p) {
      if (p->second > 0)
        exceptions_.insert(p->first);
    }
    for (std::map<GURL, int>::const_iterator p = origins_in_error.begin();
         p != origins_in_error.end();
         ++p) {
      if (p->second > QuotaManager::kThresholdOfErrorsToBeBlacklisted)
        exceptions_.insert(p->first);
    }
  }


  GetModifiedSinceTask(
      QuotaManager* manager,
      StorageType type,
      base::Time modified_since,
      GetOriginsCallback* callback)
      : DatabaseTaskBase(manager),
        type_(type),
        modified_since_(modified_since),
        callback_(callback) {}


void QuotaManager::GetOriginsModifiedSince(
    StorageType type,
    base::Time modified_since,
    GetOriginsCallback* callback) {
  LazyInitialize();
  make_scoped_refptr(new GetModifiedSinceTask(
      this, type, modified_since, callback))->Start();
}


  GetPersistentHostQuotaTask(
      QuotaManager* manager,
      const std::string& host,
      HostQuotaCallback* callback)
      : DatabaseTaskBase(manager),
        host_(host),
        quota_(-1),
        callback_(callback) {
  }


void QuotaManager::GetStatistics(
    std::map<std::string, std::string>* statistics) {
  DCHECK(statistics);
  if (temporary_storage_evictor_.get()) {
    std::map<std::string, int64> stats;
    temporary_storage_evictor_->GetStatistics(&stats);
    for (std::map<std::string, int64>::iterator p = stats.begin();
         p != stats.end();
         ++p)
      (*statistics)[p->first] = base::Int64ToString(p->second);
  }
}


void QuotaManager::GetTemporaryGlobalQuota(QuotaCallback* callback) {
  LazyInitialize();
  if (temporary_global_quota_ >= 0) {
    callback->Run(kQuotaStatusOk,
                  kStorageTypeTemporary, temporary_global_quota_);
    delete callback;
    return;
  }
  temporary_global_quota_callbacks_.Add(callback);
}


 void QuotaManager::GetUsageAndQuota(
     const GURL& origin, StorageType type,
     GetUsageAndQuotaCallback* callback_ptr) {
  scoped_ptr<GetUsageAndQuotaCallback> callback(callback_ptr);
  LazyInitialize();

  if (type == kStorageTypeUnknown) {
    callback->Run(kQuotaErrorNotSupported, 0, 0);
    return;
  }

  std::string host = net::GetHostOrSpecFromURL(origin);
  UsageAndQuotaDispatcherTaskMap::iterator found =
      usage_and_quota_dispatchers_.find(std::make_pair(host, type));
  if (found == usage_and_quota_dispatchers_.end()) {
    UsageAndQuotaDispatcherTask* dispatcher =
        UsageAndQuotaDispatcherTask::Create(this, host, type);
    found = usage_and_quota_dispatchers_.insert(
        std::make_pair(std::make_pair(host, type), dispatcher)).first;
  }
  if (found->second->AddCallback(
          callback.release(), IsStorageUnlimited(origin))) {
    found->second->Start();
  }
}


void QuotaManager::GetUsageAndQuotaForEviction(
    GetUsageAndQuotaForEvictionCallback* callback) {
  DCHECK(io_thread_->BelongsToCurrentThread());
  DCHECK(!eviction_context_.get_usage_and_quota_callback.get());

  eviction_context_.get_usage_and_quota_callback.reset(callback);
  GetGlobalUsage(kStorageTypeTemporary, callback_factory_.
      NewCallback(&QuotaManager::DidGetGlobalUsageForEviction));
}


UsageTracker* QuotaManager::GetUsageTracker(StorageType type) const {
  switch (type) {
    case kStorageTypeTemporary:
      return temporary_usage_tracker_.get();
    case kStorageTypePersistent:
      return persistent_usage_tracker_.get();
    default:
      NOTREACHED();
  }
  return NULL;
}


  InitializeTask(
      QuotaManager* manager,
      const FilePath& profile_path,
      bool is_incognito)
      : DatabaseTaskBase(manager),
        profile_path_(profile_path),
        is_incognito_(is_incognito),
        need_initialize_origins_(false),
        temporary_storage_quota_(-1) {
  }


  InitializeTemporaryOriginsInfoTask(
      QuotaManager* manager,
      UsageTracker* temporary_usage_tracker)
      : DatabaseTaskBase(manager),
        has_registered_origins_(false) {
    DCHECK(temporary_usage_tracker);
    temporary_usage_tracker->GetCachedOrigins(&origins_);
  }


void QuotaManager::LazyInitialize() {
  DCHECK(io_thread_->BelongsToCurrentThread());
  if (database_.get()) {
    return;
  }

  database_.reset(new QuotaDatabase(is_incognito_ ? FilePath() :
      profile_path_.AppendASCII(kDatabaseName)));

  temporary_usage_tracker_.reset(
      new UsageTracker(clients_, kStorageTypeTemporary,
                       special_storage_policy_));
  persistent_usage_tracker_.reset(
      new UsageTracker(clients_, kStorageTypePersistent,
                       special_storage_policy_));

  scoped_refptr<InitializeTask> task(
      new InitializeTask(this, profile_path_, is_incognito_));
  task->Start();
}


  QuotaCallback* NewWaitableGlobalQuotaCallback() {
    ++waiting_callbacks_;
    return callback_factory_.NewCallback(
            &UsageAndQuotaDispatcherTask::DidGetGlobalQuota);
  }


  GlobalUsageCallback* NewWaitableGlobalUsageCallback() {
    ++waiting_callbacks_;
    return callback_factory_.NewCallback(
            &UsageAndQuotaDispatcherTask::DidGetGlobalUsage);
  }


  HostQuotaCallback* NewWaitableHostQuotaCallback() {
    ++waiting_callbacks_;
    return callback_factory_.NewCallback(
            &UsageAndQuotaDispatcherTask::DidGetHostQuota);
  }


  HostUsageCallback* NewWaitableHostUsageCallback() {
    ++waiting_callbacks_;
    return callback_factory_.NewCallback(
            &UsageAndQuotaDispatcherTask::DidGetHostUsage);
  }


void QuotaManager::NotifyOriginInUse(const GURL& origin) {
  DCHECK(io_thread_->BelongsToCurrentThread());
  origins_in_use_[origin]++;
}


void QuotaManagerProxy::NotifyOriginInUse(
    const GURL& origin) {
  if (!io_thread_->BelongsToCurrentThread()) {
    io_thread_->PostTask(FROM_HERE, NewRunnableMethod(
        this, &QuotaManagerProxy::NotifyOriginInUse, origin));
    return;
  }
  if (manager_)
    manager_->NotifyOriginInUse(origin);
}


void QuotaManager::NotifyOriginNoLongerInUse(const GURL& origin) {
  DCHECK(io_thread_->BelongsToCurrentThread());
  DCHECK(IsOriginInUse(origin));
  int& count = origins_in_use_[origin];
  if (--count == 0)
    origins_in_use_.erase(origin);
}


void QuotaManagerProxy::NotifyOriginNoLongerInUse(
    const GURL& origin) {
  if (!io_thread_->BelongsToCurrentThread()) {
    io_thread_->PostTask(FROM_HERE, NewRunnableMethod(
        this, &QuotaManagerProxy::NotifyOriginNoLongerInUse, origin));
    return;
  }
  if (manager_)
    manager_->NotifyOriginNoLongerInUse(origin);
}


void QuotaManager::NotifyStorageAccessed(
    QuotaClient::ID client_id,
    const GURL& origin, StorageType type) {
  NotifyStorageAccessedInternal(client_id, origin, type, base::Time::Now());
}


void QuotaManagerProxy::NotifyStorageAccessed(
    QuotaClient::ID client_id,
    const GURL& origin,
    StorageType type) {
  if (!io_thread_->BelongsToCurrentThread()) {
    io_thread_->PostTask(FROM_HERE, NewRunnableMethod(
        this, &QuotaManagerProxy::NotifyStorageAccessed,
        client_id, origin, type));
    return;
  }
  if (manager_)
    manager_->NotifyStorageAccessed(client_id, origin, type);
}


void QuotaManager::NotifyStorageAccessedInternal(
    QuotaClient::ID client_id,
    const GURL& origin, StorageType type,
    base::Time accessed_time) {
  LazyInitialize();
  if (type == kStorageTypeTemporary && lru_origin_callback_.get()) {
    access_notified_origins_.insert(origin);
  }

  if (db_disabled_)
    return;
  make_scoped_refptr(new UpdateAccessTimeTask(
      this, origin, type, accessed_time))->Start();
}


void QuotaManager::NotifyStorageModified(
    QuotaClient::ID client_id,
    const GURL& origin, StorageType type, int64 delta) {
  NotifyStorageModifiedInternal(client_id, origin, type, delta,
                                base::Time::Now());
}


void QuotaManagerProxy::NotifyStorageModified(
    QuotaClient::ID client_id,
    const GURL& origin,
    StorageType type,
    int64 delta) {
  if (!io_thread_->BelongsToCurrentThread()) {
    io_thread_->PostTask(FROM_HERE, NewRunnableMethod(
        this, &QuotaManagerProxy::NotifyStorageModified,
        client_id, origin, type, delta));
    return;
  }
  if (manager_)
    manager_->NotifyStorageModified(client_id, origin, type, delta);
}


void QuotaManager::NotifyStorageModifiedInternal(
    QuotaClient::ID client_id,
    const GURL& origin,
    StorageType type,
    int64 delta,
    base::Time modified_time) {
  LazyInitialize();
  GetUsageTracker(type)->UpdateUsageCache(client_id, origin, delta);
  make_scoped_refptr(new UpdateModifiedTimeTask(
      this, origin, type, modified_time))->Start();
}


  OriginDataDeleter(QuotaManager* manager,
                    const GURL& origin,
                    StorageType type,
                    StatusCallback* callback)
      : QuotaTask(manager),
        origin_(origin),
        type_(type),
        error_count_(0),
        remaining_clients_(-1),
        callback_(callback),
        callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {}


QuotaManager::QuotaManager(bool is_incognito,
                           const FilePath& profile_path,
                           base::MessageLoopProxy* io_thread,
                           base::MessageLoopProxy* db_thread,
                           SpecialStoragePolicy* special_storage_policy)
  : is_incognito_(is_incognito),
    profile_path_(profile_path),
    proxy_(new QuotaManagerProxy(
        ALLOW_THIS_IN_INITIALIZER_LIST(this), io_thread)),
    db_disabled_(false),
    eviction_disabled_(false),
    io_thread_(io_thread),
    db_thread_(db_thread),
    need_initialize_origins_(false),
    temporary_global_quota_(-1),
    special_storage_policy_(special_storage_policy),
    callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
}


QuotaManagerProxy::QuotaManagerProxy(
    QuotaManager* manager, base::MessageLoopProxy* io_thread)
    : manager_(manager), io_thread_(io_thread) {
}


void QuotaManager::RegisterClient(QuotaClient* client) {
  DCHECK(io_thread_->BelongsToCurrentThread());
  DCHECK(!database_.get());
  clients_.push_back(client);
}


void QuotaManagerProxy::RegisterClient(QuotaClient* client) {
  if (!io_thread_->BelongsToCurrentThread()) {
    io_thread_->PostTask(FROM_HERE, NewRunnableMethod(
        this, &QuotaManagerProxy::RegisterClient, client));
    return;
  }
  if (manager_)
    manager_->RegisterClient(client);
  else
    client->OnQuotaManagerDestroyed();
}


void QuotaManager::SetPersistentHostQuota(const std::string& host,
                                          int64 new_quota,
                                          HostQuotaCallback* callback_ptr) {
  scoped_ptr<HostQuotaCallback> callback(callback_ptr);
  LazyInitialize();
  if (host.empty()) {
    callback->Run(kQuotaErrorNotSupported, host, kStorageTypePersistent, 0);
    return;
  }
  if (new_quota < 0) {
    callback->Run(kQuotaErrorInvalidModification,
                  host, kStorageTypePersistent, -1);
    return;
  }

  if (!db_disabled_) {
    scoped_refptr<UpdatePersistentHostQuotaTask> task(
        new UpdatePersistentHostQuotaTask(
            this, host, new_quota, callback.release()));
    task->Start();
  } else {
    callback->Run(kQuotaErrorInvalidAccess,
                  host, kStorageTypePersistent, -1);
  }
}


void QuotaManager::SetTemporaryGlobalQuota(int64 new_quota,
                                           QuotaCallback* callback) {
  LazyInitialize();
  if (new_quota < 0) {
    callback->Run(kQuotaErrorInvalidModification,
                  kStorageTypeTemporary, -1);
    delete callback;
    return;
  }

  if (!db_disabled_) {
    scoped_refptr<UpdateTemporaryGlobalQuotaTask> task(
        new UpdateTemporaryGlobalQuotaTask(this, new_quota, callback));
    task->Start();
  } else {
    callback->Run(kQuotaErrorInvalidAccess,
                  kStorageTypeTemporary, -1);
    delete callback;
  }
}


void QuotaManager::StartEviction() {
  DCHECK(!temporary_storage_evictor_.get());
  temporary_storage_evictor_.reset(new QuotaTemporaryStorageEvictor(this,
      kEvictionIntervalInMilliSeconds));
  temporary_storage_evictor_->Start();
}


  UpdateAccessTimeTask(
      QuotaManager* manager,
      const GURL& origin,
      StorageType type,
      base::Time accessed_time)
      : DatabaseTaskBase(manager),
        origin_(origin),
        type_(type),
        accessed_time_(accessed_time) {}


  UpdateModifiedTimeTask(
      QuotaManager* manager,
      const GURL& origin,
      StorageType type,
      base::Time modified_time)
      : DatabaseTaskBase(manager),
        origin_(origin),
        type_(type),
        modified_time_(modified_time) {}


  UpdatePersistentHostQuotaTask(
      QuotaManager* manager,
      const std::string& host,
      int new_quota,
      HostQuotaCallback* callback)
      : DatabaseTaskBase(manager),
        host_(host),
        new_quota_(new_quota),
        callback_(callback) {
    DCHECK_GE(new_quota_, 0);
  }


  UsageAndQuotaDispatcherTask(
      QuotaManager* manager,
      const std::string& host,
      StorageType type)
      : QuotaTask(manager),
        host_(host),
        type_(type),
        quota_(-1),
        global_usage_(-1),
        global_unlimited_usage_(-1),
        host_usage_(-1),
        quota_status_(kQuotaStatusUnknown),
        waiting_callbacks_(1),
        callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {}


  UsageAndQuotaDispatcherTaskForPersistent(
      QuotaManager* manager, const std::string& host)
      : UsageAndQuotaDispatcherTask(manager, host, kStorageTypePersistent) {}


  UsageAndQuotaDispatcherTaskForTemporary(
      QuotaManager* manager, const std::string& host)
      : UsageAndQuotaDispatcherTask(manager, host, kStorageTypeTemporary) {}


CallbackList& callbacks() { return callbacks_; }


QuotaDatabase* database() const { return database_; }


bool db_disabled() const { return db_disabled_; }


int64 global_unlimited_usage() const { return global_unlimited_usage_; }


int64 global_usage() const { return global_usage_; }


std::string host() const { return host_; }


int64 host_usage() const { return host_usage_; }


  QuotaManager* manager() const {
    return static_cast<QuotaManager*>(observer());
  }


QuotaManager* manager() const { return manager_; }


QuotaManager* QuotaManagerProxy::quota_manager() const {
  DCHECK(!io_thread_ || io_thread_->BelongsToCurrentThread());
  return manager_;
}


QuotaStatusCode quota_status() const { return quota_status_; }


  void set_db_disabled(bool db_disabled) {
    db_disabled_ = db_disabled;
  }


StorageType type() const { return type_; }


QuotaManager::~QuotaManager() {
  DCHECK(io_thread_->BelongsToCurrentThread());
  proxy_->manager_ = NULL;
  std::for_each(clients_.begin(), clients_.end(),
                std::mem_fun(&QuotaClient::OnQuotaManagerDestroyed));
  if (database_.get())
     db_thread_->DeleteSoon(FROM_HERE, database_.release());
 }


  virtual ~UsageAndQuotaDispatcherTask() {
    STLDeleteContainerPointers(callbacks_.begin(), callbacks_.end());
    STLDeleteContainerPointers(unlimited_callbacks_.begin(),
                               unlimited_callbacks_.end());
  }


  MockStorageClient* CreateClient(
      const MockOriginData* mock_data, size_t mock_data_size) {
    return new MockStorageClient(quota_manager_->proxy(),
                                 mock_data, mock_data_size);
  }


  void DeleteClientOriginData(QuotaClient* client,
                        const GURL& origin,
                        StorageType type) {
    DCHECK(client);
    quota_status_ = kQuotaStatusUnknown;
    client->DeleteOriginData(origin, type,
        callback_factory_.NewCallback(
            &QuotaManagerTest::StatusCallback));
  }


  void DeleteOriginData(const GURL& origin,
                        StorageType type) {
    quota_status_ = kQuotaStatusUnknown;
    quota_manager_->DeleteOriginData(origin, type,
        callback_factory_.NewCallback(
            &QuotaManagerTest::StatusCallback));
  }


  void DeleteOriginFromDatabase(const GURL& origin, StorageType type) {
    quota_manager_->DeleteOriginFromDatabase(origin, type);
  }


  void DidDumpOriginInfoTable(const OriginInfoTableEntries& entries) {
    origin_info_entries_ = entries;
  }


  void DidDumpQuotaTable(const QuotaTableEntries& entries) {
    quota_entries_ = entries;
  }


  void DidGetAvailableSpace(QuotaStatusCode status, int64 available_space) {
    quota_status_ = status;
    available_space_ = available_space;
  }


  void DidGetGlobalUsage(StorageType type, int64 usage,
                         int64 unlimited_usage) {
    type_ = type;
    usage_ = usage;
    unlimited_usage_ = unlimited_usage;
  }


  void DidGetHostQuota(QuotaStatusCode status,
                       const std::string& host,
                       StorageType type,
                       int64 quota) {
    quota_status_ = status;
    host_ = host;
    type_ = type;
    quota_ = quota;
  }


  void DidGetHostUsage(const std::string& host,
                       StorageType type,
                       int64 usage) {
    host_ = host;
    type_ = type;
    usage_ = usage;
  }


  void DidGetLRUOrigin(const GURL& origin) {
    lru_origin_ = origin;
  }


  void DidGetModifiedOrigins(const std::set<GURL>& origins, StorageType type) {
    modified_origins_ = origins;
    modified_origins_type_ = type;
  }


  void DidGetQuota(QuotaStatusCode status,
                   StorageType type,
                   int64 quota) {
    quota_status_ = status;
    type_ = type;
    quota_ = quota;
  }


   void DidGetUsageAndQuota(QuotaStatusCode status, int64 usage, int64 quota) {
     quota_status_ = status;
     usage_ = usage;
    quota_ = quota;
  }


  void DidGetUsageAndQuotaAdditional(
      QuotaStatusCode status, int64 usage, int64 quota) {
    ++additional_callback_count_;
  }


  void DidGetUsageAndQuotaForEviction(QuotaStatusCode status,
      int64 usage, int64 unlimited_usage, int64 quota, int64 available_space) {
    quota_status_ = status;
    usage_ = usage;
    unlimited_usage_ = unlimited_usage;
    quota_ = quota;
    available_space_ = available_space;
  }


  void DumpOriginInfoTable() {
    origin_info_entries_.clear();
    quota_manager_->DumpOriginInfoTable(
        callback_factory_.NewCallback(
             &QuotaManagerTest::DidDumpOriginInfoTable));
   }


  void EvictOriginData(const GURL& origin,
                       StorageType type) {
    quota_status_ = kQuotaStatusUnknown;
    quota_manager_->EvictOriginData(origin, type,
        callback_factory_.NewCallback(
            &QuotaManagerTest::StatusCallback));
  }


  void GetAvailableSpace() {
    quota_status_ = kQuotaStatusUnknown;
    available_space_ = -1;
    quota_manager_->GetAvailableSpace(
        callback_factory_.NewCallback(
            &QuotaManagerTest::DidGetAvailableSpace));
  }


  void GetCachedOrigins(StorageType type, std::set<GURL>* origins) {
    ASSERT_TRUE(origins != NULL);
    origins->clear();
    quota_manager_->GetCachedOrigins(type, origins);
  }


  void GetGlobalUsage(StorageType type) {
    type_ = kStorageTypeUnknown;
    usage_ = -1;
    unlimited_usage_ = -1;
    quota_manager_->GetGlobalUsage(type,
        callback_factory_.NewCallback(
            &QuotaManagerTest::DidGetGlobalUsage));
  }


  void GetHostUsage(const std::string& host, StorageType type) {
    host_.clear();
    type_ = kStorageTypeUnknown;
    usage_ = -1;
    quota_manager_->GetHostUsage(host, type,
        callback_factory_.NewCallback(
            &QuotaManagerTest::DidGetHostUsage));
  }


  void GetLRUOrigin(StorageType type) {
    lru_origin_ = GURL();
    quota_manager_->GetLRUOrigin(type,
        callback_factory_.NewCallback(&QuotaManagerTest::DidGetLRUOrigin));
  }


  void GetOriginsModifiedSince(StorageType type, base::Time modified_since) {
    modified_origins_.clear();
    modified_origins_type_ = kStorageTypeUnknown;
    quota_manager_->GetOriginsModifiedSince(type, modified_since,
        callback_factory_.NewCallback(
            &QuotaManagerTest::DidGetModifiedOrigins));
  }


  void GetTemporaryGlobalQuota() {
    quota_status_ = kQuotaStatusUnknown;
    quota_ = -1;
    quota_manager_->GetTemporaryGlobalQuota(
        callback_factory_.NewCallback(
            &QuotaManagerTest::DidGetQuota));
  }


   void GetUsageAndQuota(const GURL& origin, StorageType type) {
     quota_status_ = kQuotaStatusUnknown;
     usage_ = -1;
    quota_ = -1;
    quota_manager_->GetUsageAndQuota(origin, type,
        callback_factory_.NewCallback(
            &QuotaManagerTest::DidGetUsageAndQuota));
  }


  void GetUsageAndQuotaForEviction() {
    quota_status_ = kQuotaStatusUnknown;
    usage_ = -1;
    unlimited_usage_ = -1;
    quota_ = -1;
    available_space_ = -1;
    quota_manager_->GetUsageAndQuotaForEviction(
        callback_factory_.NewCallback(
            &QuotaManagerTest::DidGetUsageAndQuotaForEviction));
  }


void QuotaManagerTest::GetUsage_WithModifyTestBody(const StorageType type) {
  const MockOriginData data[] = {
    { "http://foo.com/",   type,  10 },
    { "http://foo.com:1/", type,  20 },
  };
  MockStorageClient* client = CreateClient(data, ARRAYSIZE_UNSAFE(data));
  RegisterClient(client);

  GetUsageAndQuota(GURL("http://foo.com/"), type);
  MessageLoop::current()->RunAllPending();
  EXPECT_EQ(kQuotaStatusOk, status());
  EXPECT_EQ(10 + 20, usage());

  client->ModifyOriginAndNotify(GURL("http://foo.com/"), type, 30);
  client->ModifyOriginAndNotify(GURL("http://foo.com:1/"), type, -5);
  client->AddOriginAndNotify(GURL("https://foo.com/"), type, 1);

  GetUsageAndQuota(GURL("http://foo.com/"), type);
  MessageLoop::current()->RunAllPending();
  EXPECT_EQ(kQuotaStatusOk, status());
  EXPECT_EQ(10 + 20 + 30 - 5 + 1, usage());
  int foo_usage = usage();

  client->AddOriginAndNotify(GURL("http://bar.com/"), type, 40);
  GetUsageAndQuota(GURL("http://bar.com/"), type);
  MessageLoop::current()->RunAllPending();
  EXPECT_EQ(kQuotaStatusOk, status());
  EXPECT_EQ(40, usage());

  GetGlobalUsage(type);
  MessageLoop::current()->RunAllPending();
  EXPECT_EQ(foo_usage + 40, usage());
  EXPECT_EQ(0, unlimited_usage());
}


  void NotifyOriginInUse(const GURL& origin) {
    quota_manager_->NotifyOriginInUse(origin);
  }


  void NotifyOriginNoLongerInUse(const GURL& origin) {
    quota_manager_->NotifyOriginNoLongerInUse(origin);
  }


  void NotifyStorageAccessed(QuotaClient* client,
                             const GURL& origin,
                             StorageType type) {
    DCHECK(client);
    quota_manager_->NotifyStorageAccessedInternal(
        client->id(), origin, type, IncrementMockTime());
  }


  QuotaManagerTest()
      : callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
        mock_time_counter_(0) {
  }


  void RegisterClient(MockStorageClient* client) {
     quota_manager_->proxy()->RegisterClient(client);
   }


  void RunAdditionalUsageAndQuotaTask(const GURL& origin, StorageType type) {
    quota_manager_->GetUsageAndQuota(origin, type,
        callback_factory_.NewCallback(
            &QuotaManagerTest::DidGetUsageAndQuotaAdditional));
  }


  void SetPersistentHostQuota(const std::string& host, int64 new_quota) {
    quota_status_ = kQuotaStatusUnknown;
    host_.clear();
    type_ = kStorageTypeUnknown;
    quota_ = -1;
    quota_manager_->SetPersistentHostQuota(host, new_quota,
        callback_factory_.NewCallback(
            &QuotaManagerTest::DidGetHostQuota));
  }


  void SetTemporaryGlobalQuota(int64 new_quota) {
    quota_status_ = kQuotaStatusUnknown;
    quota_ = -1;
    quota_manager_->SetTemporaryGlobalQuota(new_quota,
        callback_factory_.NewCallback(
            &QuotaManagerTest::DidGetQuota));
  }


  void SetUp() {
    ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
    mock_special_storage_policy_ = new MockSpecialStoragePolicy;
    quota_manager_ = new QuotaManager(
        false /* is_incognito */,
        data_dir_.path(),
        MessageLoopProxy::current(),
        MessageLoopProxy::current(),
        mock_special_storage_policy_);
    quota_manager_->eviction_disabled_ = true;
    additional_callback_count_ = 0;
  }


  void StatusCallback(QuotaStatusCode status) {
    ++status_callback_count_;
    quota_status_ = status;
  }


int additional_callback_count() const { return additional_callback_count_; }


int64 available_space() const { return available_space_; }


const GURL& lru_origin() const { return lru_origin_; }


  MockSpecialStoragePolicy* mock_special_storage_policy() const {
    return mock_special_storage_policy_.get();
   }


const std::set<GURL>& modified_origins() const { return modified_origins_; }


StorageType modified_origins_type() const { return modified_origins_type_; }


QuotaManager* quota_manager() const { return quota_manager_.get(); }


void reset_status_callback_count() { status_callback_count_ = 0; }


void set_additional_callback_count(int c) { additional_callback_count_ = c; }


int status_callback_count() const { return status_callback_count_; }


int64 unlimited_usage() const { return unlimited_usage_; }


void ClientUsageTracker::AddCachedHost(const std::string& host) {
  cached_hosts_.insert(host);
}


void ClientUsageTracker::AddCachedOrigin(
    const GURL& origin, int64 usage) {
  std::string host = net::GetHostOrSpecFromURL(origin);
  UsageMap::iterator iter = cached_usage_[host].
      insert(UsageMap::value_type(origin, 0)).first;
  int64 old_usage = iter->second;
  iter->second = usage;
  int64 delta = usage - old_usage;
  if (delta) {
    global_usage_ += delta;
    if (global_unlimited_usage_is_valid_ && IsStorageUnlimited(origin))
      global_unlimited_usage_ += delta;
  }
  DCHECK_GE(iter->second, 0);
  DCHECK_GE(global_usage_, 0);
}


ClientUsageTracker::ClientUsageTracker(
    UsageTracker* tracker, QuotaClient* client, StorageType type,
    SpecialStoragePolicy* special_storage_policy)
    : tracker_(tracker),
      client_(client),
      type_(type),
      global_usage_(0),
      global_unlimited_usage_(0),
      global_usage_retrieved_(false),
      global_unlimited_usage_is_valid_(true),
      global_usage_task_(NULL),
      special_storage_policy_(special_storage_policy) {
  DCHECK(tracker_);
  DCHECK(client_);
  if (special_storage_policy_)
    special_storage_policy_->AddObserver(this);
}


void UsageTracker::DidGetClientGlobalUsage(StorageType type,
                                           int64 usage,
                                           int64 unlimited_usage) {
  DCHECK_EQ(type, type_);
  global_usage_.usage += usage;
  global_usage_.unlimited_usage += unlimited_usage;
  if (--global_usage_.pending_clients == 0) {
    if (global_usage_.usage < 0)
      global_usage_.usage = 0;
    if (global_usage_.unlimited_usage > global_usage_.usage)
      global_usage_.unlimited_usage = global_usage_.usage;
    else if (global_usage_.unlimited_usage < 0)
      global_usage_.unlimited_usage = 0;

    global_usage_callbacks_.Run(type, global_usage_.usage,
                                global_usage_.unlimited_usage);
  }
}


void UsageTracker::DidGetClientHostUsage(const std::string& host,
                                         StorageType type,
                                         int64 usage) {
  DCHECK_EQ(type, type_);
  TrackingInfo& info = outstanding_host_usage_[host];
  info.usage += usage;
  if (--info.pending_clients == 0) {
    if (info.usage < 0)
      info.usage = 0;
    host_usage_callbacks_.Run(host, host, type, info.usage);
    outstanding_host_usage_.erase(host);
  }
}


  void DidGetUsage(int64 usage) {
    DCHECK(original_message_loop()->BelongsToCurrentThread());
    DCHECK(!pending_origins_.empty());
    DCHECK(client_tracker_);

    DCHECK_GE(usage, 0);
    if (usage < 0)
      usage = 0;

    const GURL& origin = pending_origins_.front();
    std::string host = net::GetHostOrSpecFromURL(origin);
    client_tracker_->AddCachedOrigin(origin, usage);

    pending_origins_.pop_front();
    if (pending_origins_.empty() ||
        host != net::GetHostOrSpecFromURL(pending_origins_.front())) {
      client_tracker_->AddCachedHost(host);
    }

    if (pending_origins_.empty()) {
      CallCompleted();
      DeleteSoon();
    }
  }


void ClientUsageTracker::GatherGlobalUsageComplete() {
  DCHECK(global_usage_task_ != NULL);
  global_usage_task_ = NULL;
  global_usage_retrieved_ = true;

  DCHECK(global_usage_callback_.HasCallbacks());
  global_usage_callback_.Run(type_, global_usage_,
                             GetCachedGlobalUnlimitedUsage());

  for (HostUsageCallbackMap::iterator iter = host_usage_callbacks_.Begin();
       iter != host_usage_callbacks_.End(); ++iter) {
    iter->second.Run(iter->first, type_, GetCachedHostUsage(iter->first));
  }
  host_usage_callbacks_.Clear();
}


void ClientUsageTracker::GatherHostUsageComplete(const std::string& host) {
  DCHECK(host_usage_tasks_.find(host) != host_usage_tasks_.end());
  host_usage_tasks_.erase(host);
   host_usage_callbacks_.Run(host, host, type_, GetCachedHostUsage(host));
 }


  GatherHostUsageTask(
      UsageTracker* tracker,
      QuotaClient* client,
      const std::string& host)
      : GatherUsageTaskBase(tracker, client),
        client_(client),
        host_(host),
        callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
    DCHECK(client_);
  }


int64 ClientUsageTracker::GetCachedGlobalUnlimitedUsage() {
  if (!global_unlimited_usage_is_valid_) {
    global_unlimited_usage_ = 0;
    for (HostUsageMap::const_iterator host_iter = cached_usage_.begin();
         host_iter != cached_usage_.end(); host_iter++) {
      const UsageMap& origin_map = host_iter->second;
      for (UsageMap::const_iterator origin_iter = origin_map.begin();
           origin_iter != origin_map.end(); origin_iter++) {
        if (IsStorageUnlimited(origin_iter->first))
          global_unlimited_usage_ += origin_iter->second;
      }
    }
    global_unlimited_usage_is_valid_ = true;
  }
  return global_unlimited_usage_;
}


 void UsageTracker::GetCachedOrigins(std::set<GURL>* origins) const {
   DCHECK(origins);
   origins->clear();
  for (ClientTrackerMap::const_iterator iter = client_tracker_map_.begin();
       iter != client_tracker_map_.end(); ++iter) {
    iter->second->GetCachedOrigins(origins);
  }
}


 void ClientUsageTracker::GetCachedOrigins(std::set<GURL>* origins) const {
   DCHECK(origins);
   for (HostUsageMap::const_iterator host_iter = cached_usage_.begin();
       host_iter != cached_usage_.end(); host_iter++) {
    const UsageMap& origin_map = host_iter->second;
    for (UsageMap::const_iterator origin_iter = origin_map.begin();
         origin_iter != origin_map.end(); origin_iter++) {
      origins->insert(origin_iter->first);
    }
  }
}


ClientUsageTracker* UsageTracker::GetClientTracker(QuotaClient::ID client_id) {
  ClientTrackerMap::iterator found = client_tracker_map_.find(client_id);
  if (found != client_tracker_map_.end())
    return found->second;
  return NULL;
}


void UsageTracker::GetGlobalUsage(GlobalUsageCallback* callback) {
  if (client_tracker_map_.size() == 0) {
    callback->Run(type_, 0, 0);
    delete callback;
    return;
  }
  if (global_usage_callbacks_.Add(callback)) {
    global_usage_.pending_clients = client_tracker_map_.size();
    global_usage_.usage = 0;
    global_usage_.unlimited_usage = 0;
    for (ClientTrackerMap::iterator iter = client_tracker_map_.begin();
         iter != client_tracker_map_.end();
         ++iter) {
      iter->second->GetGlobalUsage(callback_factory_.NewCallback(
          &UsageTracker::DidGetClientGlobalUsage));
    }
  }
}


void ClientUsageTracker::GetGlobalUsage(GlobalUsageCallback* callback) {
  if (global_usage_retrieved_) {
    callback->Run(type_, global_usage_, GetCachedGlobalUnlimitedUsage());
    delete callback;
    return;
  }
  DCHECK(!global_usage_callback_.HasCallbacks());
  global_usage_callback_.Add(callback);
  global_usage_task_ = new GatherGlobalUsageTask(tracker_, client_);
  global_usage_task_->Start();
}


void UsageTracker::GetHostUsage(
    const std::string& host, HostUsageCallback* callback) {
  if (client_tracker_map_.size() == 0) {
    callback->Run(host, type_, 0);
    delete callback;
    return;
  }
  if (host_usage_callbacks_.Add(host, callback)) {
    DCHECK(outstanding_host_usage_.find(host) == outstanding_host_usage_.end());
    outstanding_host_usage_[host].pending_clients = client_tracker_map_.size();
    for (ClientTrackerMap::iterator iter = client_tracker_map_.begin();
         iter != client_tracker_map_.end();
         ++iter) {
      iter->second->GetHostUsage(host, callback_factory_.NewCallback(
          &UsageTracker::DidGetClientHostUsage));
    }
  }
}


  void GetUsageForOrigins(const std::set<GURL>& origins, StorageType type) {
    DCHECK(original_message_loop()->BelongsToCurrentThread());
    std::vector<GURL> origins_to_gather;
    std::set<GURL> cached_origins;
    client_tracker()->GetCachedOrigins(&cached_origins);
    std::set<GURL> already_added;
    for (std::set<GURL>::const_iterator iter = origins.begin();
         iter != origins.end(); ++iter) {
      if (cached_origins.find(*iter) == cached_origins.end() &&
          already_added.insert(*iter).second) {
        origins_to_gather.push_back(*iter);
      }
    }
    if (origins_to_gather.empty()) {
      CallCompleted();
      DeleteSoon();
      return;
    }

    std::sort(origins_to_gather.begin(), origins_to_gather.end(), SortByHost);

    for (std::vector<GURL>::const_iterator iter = origins_to_gather.begin();
         iter != origins_to_gather.end(); iter++)
      pending_origins_.push_back(*iter);

    for (std::vector<GURL>::const_iterator iter = origins_to_gather.begin();
         iter != origins_to_gather.end(); iter++)
      client_->GetOriginUsage(
          *iter,
          tracker_->type(),
          callback_factory_.NewCallback(&GatherUsageTaskBase::DidGetUsage));
  }


bool ClientUsageTracker::IsStorageUnlimited(const GURL& origin) const {
  return special_storage_policy_.get() &&
         special_storage_policy_->IsStorageUnlimited(origin);
}


void ClientUsageTracker::NoopHostUsageCallback(
    const std::string& host,  StorageType type, int64 usage) {
}


void ClientUsageTracker::OnSpecialStoragePolicyChanged() {
  DCHECK(CalledOnValidThread());
  global_unlimited_usage_is_valid_ = false;
}


bool SortByHost(const GURL& lhs, const GURL& rhs) {
  return net::GetHostOrSpecFromURL(lhs) > net::GetHostOrSpecFromURL(rhs);
}


void UsageTracker::UpdateUsageCache(
    QuotaClient::ID client_id, const GURL& origin, int64 delta) {
  ClientUsageTracker* client_tracker = GetClientTracker(client_id);
  DCHECK(client_tracker);
   client_tracker->UpdateUsageCache(origin, delta);
 }


void ClientUsageTracker::UpdateUsageCache(
    const GURL& origin, int64 delta) {
  std::string host = net::GetHostOrSpecFromURL(origin);
  if (cached_hosts_.find(host) != cached_hosts_.end()) {
    cached_usage_[host][origin] += delta;
    global_usage_ += delta;
    if (global_unlimited_usage_is_valid_ && IsStorageUnlimited(origin))
      global_unlimited_usage_ += delta;
    DCHECK_GE(cached_usage_[host][origin], 0);
    DCHECK_GE(global_usage_, 0);
    return;
  }

  GetHostUsage(host,
                NewCallback(this, &ClientUsageTracker::NoopHostUsageCallback));
 }


UsageTracker::UsageTracker(const QuotaClientList& clients, StorageType type,
                           SpecialStoragePolicy* special_storage_policy)
    : type_(type),
      callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
  for (QuotaClientList::const_iterator iter = clients.begin();
      iter != clients.end();
      ++iter) {
    client_tracker_map_.insert(std::make_pair(
        (*iter)->id(),
        new ClientUsageTracker(this, *iter, type, special_storage_policy)));
  }
}


ClientUsageTracker* client_tracker() const { return client_tracker_; }


UsageTracker* tracker() const { return tracker_; }


ClientUsageTracker::~ClientUsageTracker() {
  if (special_storage_policy_)
    special_storage_policy_->RemoveObserver(this);
}


UsageTracker::~UsageTracker() {
  STLDeleteValues(&client_tracker_map_);
}