1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/local_discovery/privet_local_printer_lister.h"
6
7#include <string>
8
9#include "chrome/browser/local_discovery/privet_constants.h"
10#include "chrome/browser/local_discovery/privet_device_lister_impl.h"
11#include "chrome/browser/local_discovery/privet_http_asynchronous_factory.h"
12
13namespace local_discovery {
14
15struct PrivetLocalPrinterLister::DeviceContext {
16  DeviceContext() : has_local_printing(false) {
17  }
18
19  scoped_ptr<PrivetHTTPResolution> privet_resolution;
20  scoped_ptr<PrivetHTTPClient> privet_client;
21  scoped_ptr<PrivetJSONOperation> info_operation;
22  DeviceDescription description;
23
24  bool has_local_printing;
25};
26
27PrivetLocalPrinterLister::PrivetLocalPrinterLister(
28    ServiceDiscoveryClient* service_discovery_client,
29    net::URLRequestContextGetter* request_context,
30    Delegate* delegate) : delegate_(delegate) {
31  privet_lister_.reset(
32      new PrivetDeviceListerImpl(service_discovery_client, this));
33  privet_http_factory_ = PrivetHTTPAsynchronousFactory::CreateInstance(
34      service_discovery_client, request_context);
35}
36
37PrivetLocalPrinterLister::~PrivetLocalPrinterLister() {
38}
39
40void PrivetLocalPrinterLister::Start() {
41  privet_lister_->Start();
42  privet_lister_->DiscoverNewDevices(false);
43}
44
45void PrivetLocalPrinterLister::Stop() {
46  privet_lister_.reset();
47}
48
49void PrivetLocalPrinterLister::DeviceChanged(
50    bool added,
51    const std::string& name,
52    const DeviceDescription& description) {
53  if (description.type != kPrivetTypePrinter)
54    return;
55
56  DeviceContextMap::iterator i = device_contexts_.find(name);
57
58  if (i != device_contexts_.end()) {
59    i->second->description = description;
60    delegate_->LocalPrinterChanged(added, name, i->second->has_local_printing,
61                                   description);
62  } else {
63    linked_ptr<DeviceContext> context(new DeviceContext);
64    context->has_local_printing = false;
65    context->description = description;
66    context->privet_resolution = privet_http_factory_->CreatePrivetHTTP(
67        name,
68        description.address,
69        base::Bind(&PrivetLocalPrinterLister::OnPrivetResolved,
70                   base::Unretained(this), name));
71
72    device_contexts_[name] = context;
73    context->privet_resolution->Start();
74  }
75}
76
77void PrivetLocalPrinterLister::DeviceCacheFlushed() {
78  device_contexts_.clear();
79  delegate_->LocalPrinterCacheFlushed();
80}
81
82void PrivetLocalPrinterLister::OnPrivetResolved(
83    const std::string& name,
84    scoped_ptr<PrivetHTTPClient> http_client) {
85  if (!http_client) {
86    // Remove device if we can't resolve it.
87    device_contexts_.erase(name);
88    return;
89  }
90  DeviceContextMap::iterator i = device_contexts_.find(http_client->GetName());
91  DCHECK(i != device_contexts_.end());
92
93  i->second->info_operation = http_client->CreateInfoOperation(
94      base::Bind(&PrivetLocalPrinterLister::OnPrivetInfoDone,
95                 base::Unretained(this),
96                 i->second.get(),
97                 http_client->GetName()));
98  i->second->privet_client = http_client.Pass();
99  i->second->info_operation->Start();
100}
101
102void PrivetLocalPrinterLister::OnPrivetInfoDone(
103    DeviceContext* context,
104    const std::string& name,
105    const base::DictionaryValue* json_value) {
106  bool has_local_printing = false;
107  const base::ListValue* api_list = NULL;
108  if (json_value && json_value->GetList(kPrivetInfoKeyAPIList, &api_list)) {
109    for (size_t i = 0; i < api_list->GetSize(); i++) {
110      std::string api;
111      api_list->GetString(i, &api);
112      if (api == kPrivetSubmitdocPath) {
113        has_local_printing = true;
114      }
115    }
116  }
117
118  context->has_local_printing = has_local_printing;
119  delegate_->LocalPrinterChanged(true, name, has_local_printing,
120                                 context->description);
121}
122
123void PrivetLocalPrinterLister::DeviceRemoved(const std::string& device_name) {
124  DeviceContextMap::iterator i = device_contexts_.find(device_name);
125  if (i != device_contexts_.end()) {
126    device_contexts_.erase(i);
127    delegate_->LocalPrinterRemoved(device_name);
128  }
129}
130
131const DeviceDescription* PrivetLocalPrinterLister::GetDeviceDescription(
132    const std::string& name) {
133  DeviceContextMap::iterator i = device_contexts_.find(name);
134  if (i == device_contexts_.end()) return NULL;
135  return &i->second->description;
136}
137
138}  // namespace local_discovery
139