1/*
2 * Copyright (c) 2022 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 */
15declare function requireNapi(s: string): any;
16interface ArkPrivate {
17  TreeMap: number;
18  Load(key: number): Object;
19}
20let flag: boolean = false;
21let fastTreeMap: Object = undefined;
22let arkPritvate: ArkPrivate = globalThis.ArkPrivate || undefined;
23if (arkPritvate !== undefined) {
24  fastTreeMap = arkPritvate.Load(arkPritvate.TreeMap);
25} else {
26  flag = true;
27}
28if (flag || fastTreeMap === undefined) {
29  let treeAbility = requireNapi('util.struct');
30  const errorUtil = treeAbility.errorUtil;
31  interface IterableIterator<T> {
32    next: () => {
33      value: T | undefined;
34      done: boolean;
35    };
36  }
37  class HandlerTreeMap<K, V> {
38    set(target: TreeMap<K, V>, p: string, value: string): boolean {
39      if (p in target) {
40        target[p] = value;
41        return true;
42      }
43      return false;
44    }
45    defineProperty(): boolean {
46      throw new Error(`Can't define Property on TreeMap Object`);
47    }
48    deleteProperty(): boolean {
49      throw new Error(`Can't delete Property on TreeMap Object`);
50    }
51    setPrototypeOf(): boolean {
52      throw new Error(`Can't set Prototype on TreeMap Object`);
53    }
54  }
55  class TreeMap<K, V> {
56    private constitute: any;
57    constructor(comparator?: (firstValue: K, secondValue: K) => boolean) {
58      errorUtil.checkNewTargetIsNullError('TreeMap', !new.target);
59      if (comparator) {
60        errorUtil.checkTypeError('comparator', 'callable', comparator);
61      }
62      this.constitute = new treeAbility.TreeClass(comparator);
63      return new Proxy(this, new HandlerTreeMap());
64    }
65    get length(): number {
66      return this.constitute.memberNumber;
67    }
68    isEmpty(): boolean {
69      errorUtil.checkBindError('isEmpty', TreeMap, this);
70      return this.constitute.memberNumber === 0;
71    }
72    hasKey(key: K): boolean {
73      errorUtil.checkBindError('hasKey', TreeMap, this);
74      return this.constitute.getNode(key) !== undefined;
75    }
76    hasValue(value: V): boolean {
77      errorUtil.checkBindError('hasValue', TreeMap, this);
78      return this.constitute.findNode(value) !== undefined;
79    }
80    get(key: K): V {
81      errorUtil.checkBindError('get', TreeMap, this);
82      if (this.constitute.getNode(key) === undefined) {
83        return undefined;
84      }
85      return this.constitute.getNode(key).value;
86    }
87    getFirstKey(): K {
88      errorUtil.checkBindError('getFirstKey', TreeMap, this);
89      if (this.constitute.firstNode() === undefined) {
90        return undefined;
91      }
92      return this.constitute.firstNode().key;
93    }
94    getLastKey(): K {
95      errorUtil.checkBindError('getLastKey', TreeMap, this);
96      if (this.constitute.lastNode() === undefined) {
97        return undefined;
98      }
99      return this.constitute.lastNode().key;
100    }
101    setAll(map: TreeMap<K, V>): void {
102      errorUtil.checkBindError('setAll', TreeMap, this);
103      errorUtil.checkTypeError('map', 'TreeMap', map);
104      this.constitute.setAll(map.constitute);
105    }
106    set(key: K, value: V): Object {
107      errorUtil.checkBindError('set', TreeMap, this);
108      return this.constitute.addNode(key, value);
109    }
110    remove(key: K): V {
111      errorUtil.checkBindError('remove', TreeMap, this);
112      return this.constitute.removeNode(key);
113    }
114    clear(): void {
115      errorUtil.checkBindError('clear', TreeMap, this);
116      this.constitute.clearTree();
117    }
118    getLowerKey(key: K): K {
119      errorUtil.checkBindError('getLowerKey', TreeMap, this);
120      let result: K | undefined = undefined;
121      if (this.constitute.getNode(key) === undefined) {
122        return undefined;
123      }
124      if (this.constitute.getNode(key).left !== undefined) {
125        return  this.constitute.getNode(key).left.key;
126      }
127      let node =  this.constitute.getNode(key);
128      while (node.parent !== undefined) {
129        if (node.parent.right === node) {
130          return node.parent.key;
131        }
132        node = node.parent;
133      }
134      return result;
135    }
136    getHigherKey(key: K): K {
137      errorUtil.checkBindError('getHigherKey', TreeMap, this);
138      let result: K | undefined = undefined;
139      if (this.constitute.getNode(key) === undefined) {
140        return undefined;
141      }
142      if (this.constitute.getNode(key).right !== undefined) {
143        return this.constitute.getNode(key).right.key;
144      }
145      let node = this.constitute.getNode(key);
146      while (node.parent !== undefined) {
147        if (node.parent.left === node) {
148          return node.parent.key;
149        }
150        node = node.parent;
151      }
152      return result;
153    }
154    keys(): IterableIterator<K> {
155      errorUtil.checkBindError('keys', TreeMap, this);
156      let count: number = 0;
157      return {
158        next: function (): { done: boolean, value: K } {
159          let done: boolean = false;
160          let value: K = undefined;
161          done = count >= this.constitute.memberNumber;
162          value = done ? undefined : this.constitute.keyValueArray[count].key;
163          count++;
164          return {
165            done: done,
166            value: value,
167          };
168        },
169      };
170    }
171    values(): IterableIterator<V> {
172      errorUtil.checkBindError('values', TreeMap, this);
173      let count: number = 0;
174      return {
175        next: function (): { done: boolean, value: V } {
176          let done: boolean = false;
177          let value: V = undefined;
178          done = count >= this.constitute.memberNumber;
179          value = done ? undefined : this.constitute.keyValueArray[count].value;
180          count++;
181          return {
182            done: done,
183            value: value,
184          };
185        },
186      };
187    }
188    replace(key: K, newValue: V): boolean {
189      errorUtil.checkBindError('replace', TreeMap, this);
190      if (this.constitute.getNode(key) === undefined) {
191        return false;
192      }
193      this.constitute.getNode(key).value = newValue;
194      return true;
195    }
196    forEach(callbackfn: (value?: V, key?: K, map?: TreeMap<K, V>) => void,
197      thisArg?: Object): void {
198      errorUtil.checkBindError('forEach', TreeMap, this);
199      errorUtil.checkTypeError('callbackfn', 'callable', callbackfn);
200      for (let i: number = 0; i < this.constitute.memberNumber; i++) {
201        callbackfn.call(thisArg, this.constitute.keyValueArray[i].value as V, this.constitute.keyValueArray[i].key);
202      }
203    }
204    entries(): IterableIterator<[K, V]> {
205      errorUtil.checkBindError('entries', TreeMap, this);
206      let count: number = 0;
207      return {
208        next: function (): { done: boolean, value: [K, V] } {
209          let done: boolean = false;
210          let value: [K, V] = undefined;
211          done = count >= this.constitute.memberNumber;
212          value = done ? undefined : this.constitute.keyValueArray[count].entry();
213          count++;
214          return {
215            done: done,
216            value: value,
217          };
218        },
219      };
220    }
221    [Symbol.iterator](): IterableIterator<[K, V]> {
222      errorUtil.checkBindError('Symbol.iterator', TreeMap, this);
223      return this.entries();
224    }
225  }
226  Object.freeze(TreeMap);
227  fastTreeMap = TreeMap;
228}
229export default fastTreeMap;
230