1/*
2 * Copyright (c) 2023-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import type DiscoveredPrinter from './DiscoveredPrinter';
17import ArrayList from '@ohos.util.ArrayList';
18import { Log } from '@ohos/common';
19import CommonUtils from '../utils/CommonUtils';
20import CheckEmptyUtils from '@ohos/common';
21
22const TAG = 'Discovery';
23
24export default abstract class Discovery {
25  mCachePrinters: Map<string, DiscoveredPrinter> = new Map<string, DiscoveredPrinter>();
26  private mListeners: ArrayList<Listener> = new ArrayList<Listener>();
27  private mStarted: boolean = false;
28
29  constructor() {
30
31  }
32
33  /**
34  * 开始查找打印机
35  */
36  abstract onStartDiscovery(): void;
37
38  /**
39   * 停止搜索打印机,释放所有与搜索相关的资源
40   */
41  abstract onStopDiscovery(): void;
42
43  /**
44   * 任何Discovery对象找到打印机, 就添加监听器
45   * @param listener 监听器
46   */
47  public addListener(listener: Listener): void {
48    if (!this.mListeners.has(listener)) {
49      Log.info(TAG, 'addListener ' + typeof listener);
50      this.mListeners.add(listener);
51    }
52    this.start();
53  }
54
55  /**
56   * Remove a listener so that it no longer receives notifications of found printers.
57   * Discovery will continue for other listeners until the last one is removed.
58   *
59   * @param listener listener
60   */
61  public removeListener(listener: Listener): void {
62    if (!this.mListeners.has(listener)) {
63      Log.error(TAG, 'listener is not exist');
64    } else {
65      this.mListeners.remove(listener);
66    }
67    if (this.mListeners.isEmpty()) {
68      this.stop();
69    }
70  }
71
72  /**
73   * Start if not already started
74   */
75  private start(): void {
76    if (!this.mStarted) {
77      Log.info(TAG, 'discovery is not started, now start');
78      this.mStarted = true;
79      this.onStartDiscovery();
80    } else {
81      this.reportCachePrinters();
82    }
83  }
84
85  private async reportCachePrinters(): Promise<void> {
86    Log.debug(TAG, 'discovery is started, no need start');
87    if (this.mCachePrinters.size > 0) {
88      let printers: DiscoveredPrinter[] = Array.from(this.mCachePrinters.values());
89      this.mListeners.forEach((listener: Listener) => {
90        for (let printer of printers) {
91          listener.onPrinterFound(printer);
92        }
93      });
94    }
95  }
96
97  public stop(): void {
98    if (this.mStarted) {
99      Log.info(TAG, 'discovery is started, now stop');
100      this.mStarted = false;
101      this.onStopDiscovery();
102      this.mCachePrinters.clear();
103    } else {
104      Log.debug(TAG, 'discovery is not started, no need stop');
105    }
106  }
107
108  /**
109   * 发现了打印机列表
110   *
111   * @param printerArray
112   */
113  public printerFound(printer: DiscoveredPrinter): void {
114    if (CheckEmptyUtils.isEmpty<DiscoveredPrinter>(printer)) {
115      Log.error(TAG, 'printer is empty');
116      return;
117    }
118    if (this.mCachePrinters.has(<string>printer.getPath()) ) {
119      Log.info(TAG, 'Already reported the printer, ignoring');
120      return;
121    }
122    Log.info(TAG, `found printer: ${CommonUtils.getSecurityPrinterName(printer.getDeviceName())}`);
123    this.mCachePrinters.set(<string>printer.getPath(), printer);
124    for (let listener of this.mListeners) {
125      listener.onPrinterFound(printer);
126    }
127  }
128
129  /**
130   * 打印丢失, 上报并删除缓存的打印机
131   *
132   * @param uri
133   */
134  public printerLost(path: string): void {
135    if (!this.mCachePrinters.has(path)) {
136      Log.error(TAG, `${path} is not exist`);
137      return;
138    }
139    let printer = this.mCachePrinters.get(path);
140
141    let result = this.mCachePrinters.delete(path);
142    if (!result) {
143      Log.error(TAG, 'remove result is false');
144      return;
145    }
146    Log.info(TAG, `${CommonUtils.getSecurityPrinterName(printer.getDeviceName())} lost`);
147    for (let listener of this.mListeners) {
148      listener.onPrinterLost(printer);
149    }
150  }
151
152  /**
153   * 删除map中的所有打印机信息
154   */
155  clearPrinterMap(isReported: boolean): void {
156    Log.info(TAG, 'clear printer map');
157    if (this.mCachePrinters.size === 0) {
158      return;
159    }
160    if (isReported) {
161      for (let key of this.mCachePrinters.keys()) {
162        this.printerLost(<string>key);
163      }
164    } else {
165      this.mCachePrinters.clear();
166    }
167  }
168
169  /**
170   * this object is in a started state
171   *
172   * @return Return true if this object is in a started state
173   */
174  isStarted(): boolean {
175    return this.mStarted;
176  }
177}
178
179
180export interface Listener {
181
182  /**
183  * A new printer has been discovered, or an existing printer has been updated
184  *
185  * @param printer DiscoveredPrinter
186  */
187  onPrinterFound(printer: DiscoveredPrinter): void;
188
189  /**
190   * A previously-found printer is no longer discovered.
191   *
192   * @param printer DiscoveredPrinter
193   */
194  onPrinterLost(printer: DiscoveredPrinter): void;
195}
196
197export interface P2PDiscoveryListener {
198  onPeerFound(p2pDevice): void;
199  onPeerLost(p2pDevice): void;
200}