133eb0b6dSopenharmony_ci/*
233eb0b6dSopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
333eb0b6dSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
433eb0b6dSopenharmony_ci * you may not use this file except in compliance with the License.
533eb0b6dSopenharmony_ci * You may obtain a copy of the License at
633eb0b6dSopenharmony_ci *
733eb0b6dSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
833eb0b6dSopenharmony_ci *
933eb0b6dSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1033eb0b6dSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1133eb0b6dSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1233eb0b6dSopenharmony_ci * See the License for the specific language governing permissions and
1333eb0b6dSopenharmony_ci * limitations under the License.
1433eb0b6dSopenharmony_ci */
1533eb0b6dSopenharmony_ci#include "event_target.h"
1633eb0b6dSopenharmony_ci
1733eb0b6dSopenharmony_ci#include <cstring>
1833eb0b6dSopenharmony_ci
1933eb0b6dSopenharmony_ci#include "securec.h"
2033eb0b6dSopenharmony_ci#include "utils/log.h"
2133eb0b6dSopenharmony_ci
2233eb0b6dSopenharmony_ci#define LISTENER_TYPTE_MAX_LENGTH 64
2333eb0b6dSopenharmony_ci
2433eb0b6dSopenharmony_cistruct EventListener {
2533eb0b6dSopenharmony_ci    char type[LISTENER_TYPTE_MAX_LENGTH] = { 0 };
2633eb0b6dSopenharmony_ci    bool isOnce = false;
2733eb0b6dSopenharmony_ci    napi_ref handlerRef = nullptr;
2833eb0b6dSopenharmony_ci    EventListener* back = nullptr;
2933eb0b6dSopenharmony_ci    EventListener* next = nullptr;
3033eb0b6dSopenharmony_ci};
3133eb0b6dSopenharmony_ci
3233eb0b6dSopenharmony_ciEventTarget::EventTarget(napi_env env, napi_value thisVar)
3333eb0b6dSopenharmony_ci    : env_(env), thisVarRef_(nullptr), first_(nullptr), last_(nullptr)
3433eb0b6dSopenharmony_ci{
3533eb0b6dSopenharmony_ci    napi_create_reference(env, thisVar, 1, &thisVarRef_);
3633eb0b6dSopenharmony_ci}
3733eb0b6dSopenharmony_ci
3833eb0b6dSopenharmony_ciEventTarget::~EventTarget()
3933eb0b6dSopenharmony_ci{
4033eb0b6dSopenharmony_ci    EventListener* temp = nullptr;
4133eb0b6dSopenharmony_ci    for (EventListener* i = first_; i != nullptr; i = temp) {
4233eb0b6dSopenharmony_ci        temp = i->next;
4333eb0b6dSopenharmony_ci        if (i == first_) {
4433eb0b6dSopenharmony_ci            first_ = first_->next;
4533eb0b6dSopenharmony_ci        } else if (i == last_) {
4633eb0b6dSopenharmony_ci            last_ = last_->back;
4733eb0b6dSopenharmony_ci        } else {
4833eb0b6dSopenharmony_ci            i->next->back = i->back;
4933eb0b6dSopenharmony_ci            i->back->next = i->next;
5033eb0b6dSopenharmony_ci        }
5133eb0b6dSopenharmony_ci        napi_delete_reference(env_, i->handlerRef);
5233eb0b6dSopenharmony_ci        delete i;
5333eb0b6dSopenharmony_ci    }
5433eb0b6dSopenharmony_ci    napi_delete_reference(env_, thisVarRef_);
5533eb0b6dSopenharmony_ci}
5633eb0b6dSopenharmony_ci
5733eb0b6dSopenharmony_civoid EventTarget::On(const char* type, napi_value handler)
5833eb0b6dSopenharmony_ci{
5933eb0b6dSopenharmony_ci    auto tmp = new EventListener();
6033eb0b6dSopenharmony_ci
6133eb0b6dSopenharmony_ci    if (strncpy_s(tmp->type, LISTENER_TYPTE_MAX_LENGTH, type, strlen(type)) != EOK) {
6233eb0b6dSopenharmony_ci        delete tmp;
6333eb0b6dSopenharmony_ci        tmp = nullptr;
6433eb0b6dSopenharmony_ci        return;
6533eb0b6dSopenharmony_ci    }
6633eb0b6dSopenharmony_ci
6733eb0b6dSopenharmony_ci    if (first_ == nullptr) {
6833eb0b6dSopenharmony_ci        first_ = last_ = tmp;
6933eb0b6dSopenharmony_ci    } else {
7033eb0b6dSopenharmony_ci        last_->next = tmp;
7133eb0b6dSopenharmony_ci        last_->next->back = last_;
7233eb0b6dSopenharmony_ci        last_ = last_->next;
7333eb0b6dSopenharmony_ci    }
7433eb0b6dSopenharmony_ci    last_->isOnce = false;
7533eb0b6dSopenharmony_ci    napi_create_reference(env_, handler, 1, &last_->handlerRef);
7633eb0b6dSopenharmony_ci}
7733eb0b6dSopenharmony_ci
7833eb0b6dSopenharmony_civoid EventTarget::Once(const char* type, napi_value handler)
7933eb0b6dSopenharmony_ci{
8033eb0b6dSopenharmony_ci    auto tmp = new EventListener();
8133eb0b6dSopenharmony_ci
8233eb0b6dSopenharmony_ci    if (strncpy_s(tmp->type, LISTENER_TYPTE_MAX_LENGTH, type, strlen(type)) != EOK) {
8333eb0b6dSopenharmony_ci        delete tmp;
8433eb0b6dSopenharmony_ci        tmp = nullptr;
8533eb0b6dSopenharmony_ci        return;
8633eb0b6dSopenharmony_ci    }
8733eb0b6dSopenharmony_ci
8833eb0b6dSopenharmony_ci    if (first_ == nullptr) {
8933eb0b6dSopenharmony_ci        first_ = last_ = tmp;
9033eb0b6dSopenharmony_ci    } else {
9133eb0b6dSopenharmony_ci        last_->next = tmp;
9233eb0b6dSopenharmony_ci        last_->next->back = last_;
9333eb0b6dSopenharmony_ci        last_ = last_->next;
9433eb0b6dSopenharmony_ci    }
9533eb0b6dSopenharmony_ci    last_->isOnce = true;
9633eb0b6dSopenharmony_ci    napi_create_reference(env_, handler, 1, &last_->handlerRef);
9733eb0b6dSopenharmony_ci}
9833eb0b6dSopenharmony_ci
9933eb0b6dSopenharmony_civoid EventTarget::Off(const char* type, napi_value handler)
10033eb0b6dSopenharmony_ci{
10133eb0b6dSopenharmony_ci    napi_handle_scope scope = nullptr;
10233eb0b6dSopenharmony_ci    napi_open_handle_scope(env_, &scope);
10333eb0b6dSopenharmony_ci    if (scope == nullptr) {
10433eb0b6dSopenharmony_ci        HILOG_ERROR("scope is nullptr");
10533eb0b6dSopenharmony_ci        return;
10633eb0b6dSopenharmony_ci    }
10733eb0b6dSopenharmony_ci
10833eb0b6dSopenharmony_ci    EventListener* temp = nullptr;
10933eb0b6dSopenharmony_ci    for (EventListener* eventListener = first_; eventListener != nullptr; eventListener = temp) {
11033eb0b6dSopenharmony_ci        temp = eventListener->next;
11133eb0b6dSopenharmony_ci        bool isEquals = false;
11233eb0b6dSopenharmony_ci        napi_value handlerTemp = nullptr;
11333eb0b6dSopenharmony_ci        napi_get_reference_value(env_, eventListener->handlerRef, &handlerTemp);
11433eb0b6dSopenharmony_ci        napi_strict_equals(env_, handlerTemp, handler, &isEquals);
11533eb0b6dSopenharmony_ci        if (strcmp(eventListener->type, type) == 0 && isEquals) {
11633eb0b6dSopenharmony_ci            if (eventListener == first_) {
11733eb0b6dSopenharmony_ci                first_ = first_->next;
11833eb0b6dSopenharmony_ci            } else if (eventListener == last_) {
11933eb0b6dSopenharmony_ci                last_ = last_->back;
12033eb0b6dSopenharmony_ci            } else {
12133eb0b6dSopenharmony_ci                eventListener->next->back = eventListener->back;
12233eb0b6dSopenharmony_ci                eventListener->back->next = eventListener->next;
12333eb0b6dSopenharmony_ci            }
12433eb0b6dSopenharmony_ci            napi_delete_reference(env_, eventListener->handlerRef);
12533eb0b6dSopenharmony_ci            delete eventListener;
12633eb0b6dSopenharmony_ci            eventListener = nullptr;
12733eb0b6dSopenharmony_ci            break;
12833eb0b6dSopenharmony_ci        }
12933eb0b6dSopenharmony_ci    }
13033eb0b6dSopenharmony_ci    napi_close_handle_scope(env_, scope);
13133eb0b6dSopenharmony_ci}
13233eb0b6dSopenharmony_ci
13333eb0b6dSopenharmony_civoid EventTarget::Off(const char* type)
13433eb0b6dSopenharmony_ci{
13533eb0b6dSopenharmony_ci    EventListener* temp = nullptr;
13633eb0b6dSopenharmony_ci    for (EventListener* eventListener = first_; eventListener != nullptr; eventListener = temp) {
13733eb0b6dSopenharmony_ci        temp = eventListener->next;
13833eb0b6dSopenharmony_ci        if (strcmp(eventListener->type, type) == 0) {
13933eb0b6dSopenharmony_ci            if (eventListener == first_) {
14033eb0b6dSopenharmony_ci                first_ = first_->next;
14133eb0b6dSopenharmony_ci            } else if (eventListener == last_) {
14233eb0b6dSopenharmony_ci                last_ = last_->back;
14333eb0b6dSopenharmony_ci            } else {
14433eb0b6dSopenharmony_ci                eventListener->next->back = eventListener->back;
14533eb0b6dSopenharmony_ci                eventListener->back->next = eventListener->next;
14633eb0b6dSopenharmony_ci            }
14733eb0b6dSopenharmony_ci            napi_delete_reference(env_, eventListener->handlerRef);
14833eb0b6dSopenharmony_ci            delete eventListener;
14933eb0b6dSopenharmony_ci            eventListener = nullptr;
15033eb0b6dSopenharmony_ci        }
15133eb0b6dSopenharmony_ci    }
15233eb0b6dSopenharmony_ci}
15333eb0b6dSopenharmony_ci
15433eb0b6dSopenharmony_civoid EventTarget::Emit(const char* type, Event* event)
15533eb0b6dSopenharmony_ci{
15633eb0b6dSopenharmony_ci    napi_handle_scope scope = nullptr;
15733eb0b6dSopenharmony_ci    napi_open_handle_scope(env_, &scope);
15833eb0b6dSopenharmony_ci
15933eb0b6dSopenharmony_ci    napi_value thisVar = nullptr;
16033eb0b6dSopenharmony_ci    napi_get_reference_value(env_, thisVarRef_, &thisVar);
16133eb0b6dSopenharmony_ci    for (EventListener* eventListener = first_; eventListener != nullptr; eventListener = eventListener->next) {
16233eb0b6dSopenharmony_ci        if (strcmp(eventListener->type, type) == 0) {
16333eb0b6dSopenharmony_ci            napi_value jsEvent = event ? event->ToJsObject() : nullptr;
16433eb0b6dSopenharmony_ci            napi_value handler = nullptr;
16533eb0b6dSopenharmony_ci            napi_get_reference_value(env_, eventListener->handlerRef, &handler);
16633eb0b6dSopenharmony_ci            napi_call_function(env_, thisVar, handler, jsEvent ? 1 : 0, jsEvent ? &jsEvent : nullptr, nullptr);
16733eb0b6dSopenharmony_ci            if (eventListener->isOnce) {
16833eb0b6dSopenharmony_ci                Off(type, handler);
16933eb0b6dSopenharmony_ci            }
17033eb0b6dSopenharmony_ci        }
17133eb0b6dSopenharmony_ci    }
17233eb0b6dSopenharmony_ci
17333eb0b6dSopenharmony_ci    napi_close_handle_scope(env_, scope);
17433eb0b6dSopenharmony_ci}
175