/*
 * Copyright (c) 2023-2026 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "state_machine.h"

#include "application_state_observer_stub.h"
#include "iservice_registry.h"
#include "system_ability_definition.h"

#include "common_event_observer.h"
#include "cooperate_events.h"
#include "cooperate_free.h"
#include "cooperate_hisysevent.h"
#include "cooperate_in.h"
#include "cooperate_out.h"
#include "devicestatus_define.h"
#include "devicestatus_errors.h"
#include "event_manager.h"
#include "utility.h"

#undef LOG_TAG
#define LOG_TAG "StateMachine"

namespace OHOS {
namespace Msdp {
namespace DeviceStatus {

namespace {
const std::string VIRTUAL_TRACK_PAD_NAME { "VirtualTrackpad" };
}
namespace Cooperate {

StateMachine::AppStateObserver::AppStateObserver(Channel<CooperateEvent>::Sender sender, int32_t clientPid)
    : sender_(sender), clientPid_(clientPid) {}

void StateMachine::AppStateObserver::OnProcessDied(const AppExecFwk::ProcessData &processData)
{
    FI_HILOGI("\'%{public}s\' died, pid:%{public}d", processData.bundleName.c_str(), processData.pid);
    if (processData.pid == clientPid_) {
        auto ret = sender_.Send(CooperateEvent(
            CooperateEventType::APP_CLOSED,
            ClientDiedEvent {
                .pid = clientPid_,
            }));
        if (ret != Channel<CooperateEvent>::NO_ERROR) {
            FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
        }
        FI_HILOGI("\'%{public}s\' died, report to handler", processData.bundleName.c_str());
    }
}

void StateMachine::AppStateObserver::UpdateClientPid(int32_t clientPid)
{
    clientPid_ = clientPid;
}

StateMachine::StateMachine(IContext *env)
    : env_(env)
{
    states_[COOPERATE_STATE_FREE] = std::make_shared<CooperateFree>(*this, env);
    states_[COOPERATE_STATE_OUT] = std::make_shared<CooperateOut>(*this, env);
    states_[COOPERATE_STATE_IN] = std::make_shared<CooperateIn>(*this, env);

    AddHandler(CooperateEventType::ADD_OBSERVER, [this](Context &context, const CooperateEvent &event) {
        this->AddObserver(context, event);
    });
    AddHandler(CooperateEventType::REMOVE_OBSERVER, [this](Context &context, const CooperateEvent &event) {
        this->RemoveObserver(context, event);
    });
    AddHandler(CooperateEventType::REGISTER_LISTENER, [this](Context &context, const CooperateEvent &event) {
        this->RegisterListener(context, event);
    });
    AddHandler(CooperateEventType::UNREGISTER_LISTENER, [this](Context &context, const CooperateEvent &event) {
        this->UnregisterListener(context, event);
    });
    AddHandler(CooperateEventType::REGISTER_HOTAREA_LISTENER, [this](Context &context, const CooperateEvent &event) {
        this->RegisterHotAreaListener(context, event);
    });
    AddHandler(CooperateEventType::UNREGISTER_HOTAREA_LISTENER,
        [this](Context &context, const CooperateEvent &event) {
            this->UnregisterHotAreaListener(context, event);
    });
    AddHandler(CooperateEventType::ENABLE, [this](Context &context, const CooperateEvent &event) {
        this->EnableCooperate(context, event);
    });
    AddHandler(CooperateEventType::DISABLE, [this](Context &context, const CooperateEvent &event) {
        this->DisableCooperate(context, event);
    });
    AddHandler(CooperateEventType::START, [this](Context &context, const CooperateEvent &event) {
        this->StartCooperate(context, event);
    });
    AddHandler(CooperateEventType::GET_COOPERATE_STATE, [this](Context &context, const CooperateEvent &event) {
        this->GetCooperateState(context, event);
    });
    AddHandler(CooperateEventType::WITH_OPTIONS_START, [this](Context &context, const CooperateEvent &event) {
        this->StartCooperateWithOptions(context, event);
    });
    AddHandler(CooperateEventType::REGISTER_EVENT_LISTENER,
        [this](Context &context, const CooperateEvent &event) {
            this->RegisterEventListener(context, event);
    });
    AddHandler(CooperateEventType::UNREGISTER_EVENT_LISTENER,
        [this](Context &context, const CooperateEvent &event) {
            this->UnregisterEventListener(context, event);
    });
    AddHandler(CooperateEventType::DDM_BOARD_ONLINE,
        [this](Context &context, const CooperateEvent &event) {
            this->OnBoardOnline(context, event);
    });
    AddHandler(CooperateEventType::DDM_BOARD_OFFLINE,
        [this](Context &context, const CooperateEvent &event) {
            this->OnBoardOffline(context, event);
    });
    AddHandler(CooperateEventType::DDP_COOPERATE_SWITCH_CHANGED,
        [this](Context &context, const CooperateEvent &event) {
            this->OnProfileChanged(context, event);
    });
    AddHandler(CooperateEventType::INPUT_POINTER_EVENT,
        [this](Context &context, const CooperateEvent &event) {
            this->OnPointerEvent(context, event);
    });
    AddHandler(CooperateEventType::APP_CLOSED, [this](Context &context, const CooperateEvent &event) {
        this->OnProcessClientDied(context, event);
    });
    AddHandler(CooperateEventType::DSOFTBUS_SESSION_OPENED,
        [this](Context &context, const CooperateEvent &event) {
            this->OnSoftbusSessionOpened(context, event);
    });
    AddHandler(CooperateEventType::DSOFTBUS_SESSION_CLOSED,
        [this](Context &context, const CooperateEvent &event) {
            this->OnSoftbusSessionClosed(context, event);
    });
    AddHandler(CooperateEventType::DSOFTBUS_SUBSCRIBE_MOUSE_LOCATION,
        [this](Context &context, const CooperateEvent &event) {
            this->OnSoftbusSubscribeMouseLocation(context, event);
    });
    AddHandler(CooperateEventType::DSOFTBUS_UNSUBSCRIBE_MOUSE_LOCATION,
        [this](Context &context, const CooperateEvent &event) {
            this->OnSoftbusUnSubscribeMouseLocation(context, event);
    });
    AddHandler(CooperateEventType::DSOFTBUS_REPLY_SUBSCRIBE_MOUSE_LOCATION,
        [this](Context &context, const CooperateEvent &event) {
            this->OnSoftbusReplySubscribeMouseLocation(context, event);
    });
    AddHandler(CooperateEventType::DSOFTBUS_REPLY_UNSUBSCRIBE_MOUSE_LOCATION,
        [this](Context &context, const CooperateEvent &event) {
            this->OnSoftbusReplyUnSubscribeMouseLocation(context, event);
    });
    AddHandler(CooperateEventType::DSOFTBUS_MOUSE_LOCATION,
        [this](Context &context, const CooperateEvent &event) {
            this->OnSoftbusMouseLocation(context, event);
    });
    AddHandler(CooperateEventType::DSOFTBUS_START_COOPERATE,
        [this](Context &context, const CooperateEvent &event) {
            this->OnRemoteStart(context, event);
    });
    AddHandler(CooperateEventType::INPUT_HOTPLUG_EVENT,
        [this](Context &context, const CooperateEvent &event) {
            this->OnHotPlugEvent(context, event);
    });
    AddHandler(CooperateEventType::DSOFTBUS_INPUT_DEV_HOT_PLUG,
        [this](Context &context, const CooperateEvent &event) {
            this->OnRemoteHotPlug(context, event);
    });
    AddHandler(CooperateEventType::DSOFTBUS_INPUT_DEV_SYNC,
        [this](Context &context, const CooperateEvent &event) {
            this->OnRemoteInputDevice(context, event);
    });
    AddHandler(CooperateEventType::STOP, [this](Context &context, const CooperateEvent &event) {
        this->StopCooperate(context, event);
    });
    AddHandler(CooperateEventType::UPDATE_VIRTUAL_DEV_ID_MAP, [this](Context &context, const CooperateEvent &event) {
        this->UpdateVirtualDeviceIdMap(context, event);
    });
    AddHandler(CooperateEventType::DSOFTBUS_COOPERATE_WITH_OPTIONS,
        [this](Context &context, const CooperateEvent &event) {
            this->OnRemoteStartWithOptions(context, event);
    });
}

void StateMachine::OnEvent(Context &context, const CooperateEvent &event)
{
    if (auto iter = handlers_.find(event.type); iter != handlers_.end()) {
        iter->second(context, event);
    } else {
        Transfer(context, event);
    }
}

void StateMachine::TransiteTo(Context &context, CooperateState state)
{
    if ((state >= COOPERATE_STATE_FREE) &&
        (state < N_COOPERATE_STATES) &&
        (state != current_)) {
        states_[current_]->OnLeaveState(context);
        current_ = state;
        states_[current_]->OnEnterState(context);
        StatusChangeEvent event = {
            .networkId = IDSoftbusAdapter::GetLocalNetworkId(),
            .msg = CoordinationMessage::COORDINATION_STATUS_FREE,
        };
        if (state == COOPERATE_STATE_OUT) {
            event.msg = CoordinationMessage::COORDINATION_STATUS_OUT;
        }
        if (state == COOPERATE_STATE_IN) {
            event.msg = CoordinationMessage::COORDINATION_STATUS_IN;
        }
        context.eventMgr_.OnStatusChanged(event);
    }
}

void StateMachine::AddHandler(CooperateEventType event, std::function<void(Context&, const CooperateEvent&)> handler)
{
    handlers_.emplace(event, handler);
}

void StateMachine::OnQuit(Context &context)
{
    CALL_DEBUG_ENTER;
    RemoveWatches();
    RemoveMonitor(context);
}

void StateMachine::AddObserver(Context &context, const CooperateEvent &event)
{
    AddObserverEvent notice = std::get<AddObserverEvent>(event.event);
    context.AddObserver(notice.observer);
}

void StateMachine::RemoveObserver(Context &context, const CooperateEvent &event)
{
    RemoveObserverEvent notice = std::get<RemoveObserverEvent>(event.event);
    context.RemoveObserver(notice.observer);
}

void StateMachine::RegisterListener(Context &context, const CooperateEvent &event)
{
    RegisterListenerEvent notice = std::get<RegisterListenerEvent>(event.event);
    context.eventMgr_.RegisterListener(notice);
}

void StateMachine::UnregisterListener(Context &context, const CooperateEvent &event)
{
    UnregisterListenerEvent notice = std::get<UnregisterListenerEvent>(event.event);
    context.eventMgr_.UnregisterListener(notice);
}

void StateMachine::RegisterHotAreaListener(Context &context, const CooperateEvent &event)
{
    RegisterHotareaListenerEvent notice = std::get<RegisterHotareaListenerEvent>(event.event);
    context.hotArea_.AddListener(notice);
}

void StateMachine::UnregisterHotAreaListener(Context &context, const CooperateEvent &event)
{
    UnregisterHotareaListenerEvent notice = std::get<UnregisterHotareaListenerEvent>(event.event);
    context.hotArea_.RemoveListener(notice);
}

void StateMachine::EnableCooperate(Context &context, const CooperateEvent &event)
{
    CALL_INFO_TRACE;
    EnableCooperateEvent enableEvent = std::get<EnableCooperateEvent>(event.event);
    context.EnableCooperate(enableEvent);
    context.eventMgr_.EnableCooperate(enableEvent);
    context.hotArea_.EnableCooperate(enableEvent);
    observer_ = CommonEventObserver::CreateCommonEventObserver(
        [&context, this] (const std::string &commonEvent) {
            OnCommonEvent(context, commonEvent);
        }
    );
    context.commonEvent_.AddObserver(observer_);
    AddSessionObserver(context, enableEvent);
    AddMonitor(context);
    AddPreMonitor(context);
    auto devAddedCallback = [this, &context](int32_t deviceId, const std::string &type) {
        FI_HILOGI("Device added");
        bool isVirtualtrackpad = this->CheckIsVirtualTrackpad(deviceId);
        if (isVirtualtrackpad) {
            context.SetVirtualTrackpadDeviceId(deviceId);
        }
    };
    auto devRemovedCallback = [this, &context](int32_t deviceId, const std::string &type) {
        FI_HILOGI("Device removed, deviceId %{public}d", deviceId);
        if (deviceId == context.GetVirtualTrackpadDeviceId()) {
            ResetCooperate(context);
            context.ResetVirtualTrackpadDeviceId();
        }
    };
    CHKPV(env_);
    env_->GetInput().RegisterDevListener(devAddedCallback, devRemovedCallback);
    isCooperateEnable_ = true;
    Transfer(context, event);
}

void StateMachine::DisableCooperate(Context &context, const CooperateEvent &event)
{
    CALL_INFO_TRACE;
    CHKPV(env_);
    DisableCooperateEvent disableEvent = std::get<DisableCooperateEvent>(event.event);
    context.DisableCooperate(disableEvent);
    context.eventMgr_.DisableCooperate(disableEvent);
    context.commonEvent_.RemoveObserver(observer_);
    context.inputDevMgr_.RemoveAllVirtualInputDevice();
    RemoveSessionObserver(context, disableEvent);
    RemoveMonitor(context);
    RemovePreMonitor(context);
    env_->GetInput().UnregisterDevListener();
    context.ResetVirtualTrackpadDeviceId();
    isCooperateEnable_ = false;
    Transfer(context, event);
}

void StateMachine::StartCooperate(Context &context, const CooperateEvent &event)
{
    CALL_INFO_TRACE;
    CHKPV(env_);
    StartCooperateEvent startEvent = std::get<StartCooperateEvent>(event.event);
    if (!env_->GetDDM().CheckSrcIsSameAccount(startEvent.remoteNetworkId)) {
        FI_HILOGE("CheckSrcIsSameAccount failed");
        startEvent.errCode->set_value(COMMON_PERMISSION_CHECK_ERROR);
        CooperateRadarInfo radarInfo {
            .funcName =  __FUNCTION__,
            .bizState = static_cast<int32_t> (BizState::STATE_END),
            .bizStage = static_cast<int32_t> (BizCooperateStage::STAGE_CHECK_SAME_ACCOUNT),
            .stageRes = static_cast<int32_t> (BizCooperateStageRes::RES_FAIL),
            .bizScene = static_cast<int32_t> (BizCooperateScene::SCENE_ACTIVE),
            .errCode = static_cast<int32_t> (CooperateRadarErrCode::CHECK_SAME_ACCOUNT_FAILED),
            .hostName = "",
            .localNetId = Utility::DFXRadarAnonymize(context.Local().c_str()),
            .peerNetId = Utility::DFXRadarAnonymize(startEvent.remoteNetworkId.c_str())
        };
        CooperateRadar::ReportCooperateRadarInfo(radarInfo);
        return;
    }
    UpdateApplicationStateObserver(startEvent.pid);
    if (!context.IsAllowCooperate()) {
        FI_HILOGI("Not allow cooperate");
        startEvent.errCode->set_value(COMMON_NOT_ALLOWED_DISTRIBUTED);
        CooperateRadarInfo radarInfo {
            .funcName = __FUNCTION__,
            .bizState = static_cast<int32_t> (BizState::STATE_END),
            .bizStage = static_cast<int32_t> (BizCooperateStage::STAGE_CHECK_ALLOW_COOPERATE),
            .stageRes = static_cast<int32_t> (BizCooperateStageRes::RES_FAIL),
            .bizScene = static_cast<int32_t> (BizCooperateScene::SCENE_ACTIVE),
            .errCode = static_cast<int32_t> (CooperateRadarErrCode::CHECK_ALLOW_COOPERATE_FAILED),
            .hostName = "",
            .localNetId = Utility::DFXRadarAnonymize(context.Local().c_str()),
            .peerNetId = Utility::DFXRadarAnonymize(startEvent.remoteNetworkId.c_str())
        };
        CooperateRadar::ReportCooperateRadarInfo(radarInfo);
        return;
    }
    startEvent.errCode->set_value(RET_OK);
    Transfer(context, event);
}

void StateMachine::StopCooperate(Context &context, const CooperateEvent &event)
{
    CALL_DEBUG_ENTER;
    context.CloseDistributedFileConnection(context.Peer());
    context.OnStopCooperate();
    context.inputDevMgr_.RemoveAllVirtualInputDevice();
    Transfer(context, event);
}

void StateMachine::StartCooperateWithOptions(Context &context, const CooperateEvent &event)
{
    CALL_INFO_TRACE;
    CHKPV(env_);
    StartWithOptionsEvent withOptionsEvent = std::get<StartWithOptionsEvent>(event.event);
    if (!env_->GetDDM().CheckSrcIsSameAccount(withOptionsEvent.remoteNetworkId)) {
        FI_HILOGE("CheckSrcIsSameAccount failed");
        withOptionsEvent.errCode->set_value(COMMON_PERMISSION_CHECK_ERROR);
        CooperateRadarInfo radarInfo {
            .funcName =  __FUNCTION__,
            .bizState = static_cast<int32_t> (BizState::STATE_END),
            .bizStage = static_cast<int32_t> (BizCooperateStage::STAGE_CHECK_SAME_ACCOUNT),
            .stageRes = static_cast<int32_t> (BizCooperateStageRes::RES_FAIL),
            .bizScene = static_cast<int32_t> (BizCooperateScene::SCENE_ACTIVE),
            .errCode = static_cast<int32_t> (CooperateRadarErrCode::CHECK_SAME_ACCOUNT_FAILED),
            .hostName = "",
            .localNetId = Utility::DFXRadarAnonymize(context.Local().c_str()),
            .peerNetId = Utility::DFXRadarAnonymize(withOptionsEvent.remoteNetworkId.c_str())
        };
        CooperateRadar::ReportCooperateRadarInfo(radarInfo);
        return;
    }
    UpdateApplicationStateObserver(withOptionsEvent.pid);
    if (!context.IsAllowCooperate()) {
        FI_HILOGI("Not allow cooperate");
        withOptionsEvent.errCode->set_value(COMMON_NOT_ALLOWED_DISTRIBUTED);
        CooperateRadarInfo radarInfo {
            .funcName = __FUNCTION__,
            .bizState = static_cast<int32_t> (BizState::STATE_END),
            .bizStage = static_cast<int32_t> (BizCooperateStage::STAGE_CHECK_ALLOW_COOPERATE),
            .stageRes = static_cast<int32_t> (BizCooperateStageRes::RES_FAIL),
            .bizScene = static_cast<int32_t> (BizCooperateScene::SCENE_ACTIVE),
            .errCode = static_cast<int32_t> (CooperateRadarErrCode::CHECK_ALLOW_COOPERATE_FAILED),
            .hostName = "",
            .localNetId = Utility::DFXRadarAnonymize(context.Local().c_str()),
            .peerNetId = Utility::DFXRadarAnonymize(withOptionsEvent.remoteNetworkId.c_str())
        };
        CooperateRadar::ReportCooperateRadarInfo(radarInfo);
        return;
    }
    withOptionsEvent.errCode->set_value(RET_OK);
    Transfer(context, event);
}

void StateMachine::GetCooperateState(Context &context, const CooperateEvent &event)
{
    CALL_INFO_TRACE;
    GetCooperateStateEvent stateEvent = std::get<GetCooperateStateEvent>(event.event);
    UpdateApplicationStateObserver(stateEvent.pid);
    EventManager::CooperateStateNotice notice {
        .pid = stateEvent.pid,
        .msgId = MessageId::COORDINATION_GET_STATE,
        .userData = stateEvent.userData,
        .state = isCooperateEnable_,
    };
    context.eventMgr_.GetCooperateState(notice);
}

void StateMachine::OnProcessClientDied(Context &context, const CooperateEvent &event)
{
    CALL_INFO_TRACE;
    ClientDiedEvent notice = std::get<ClientDiedEvent>(event.event);
    context.eventMgr_.OnClientDied(notice);
    context.hotArea_.OnClientDied(notice);
    context.mouseLocation_.OnClientDied(notice);
    Transfer(context, event);
}

void StateMachine::RegisterEventListener(Context &context, const CooperateEvent &event)
{
    RegisterEventListenerEvent notice = std::get<RegisterEventListenerEvent>(event.event);
    context.mouseLocation_.AddListener(notice);
}

void StateMachine::UnregisterEventListener(Context &context, const CooperateEvent &event)
{
    UnregisterEventListenerEvent notice = std::get<UnregisterEventListenerEvent>(event.event);
    context.mouseLocation_.RemoveListener(notice);
}

void StateMachine::OnBoardOnline(Context &context, const CooperateEvent &event)
{
    CALL_INFO_TRACE;
    DDMBoardOnlineEvent onlineEvent = std::get<DDMBoardOnlineEvent>(event.event);

    auto ret = onlineBoards_.insert(onlineEvent.networkId);
    if (ret.second) {
        FI_HILOGD("Watch \'%{public}s\'", Utility::Anonymize(onlineEvent.networkId).c_str());
        Transfer(context, event);
    }
}

void StateMachine::OnBoardOffline(Context &context, const CooperateEvent &event)
{
    CALL_INFO_TRACE;
    DDMBoardOfflineEvent offlineEvent = std::get<DDMBoardOfflineEvent>(event.event);

    if (auto iter = onlineBoards_.find(offlineEvent.networkId); iter != onlineBoards_.end()) {
        onlineBoards_.erase(iter);
        FI_HILOGD("Remove watch \'%{public}s\'", Utility::Anonymize(offlineEvent.networkId).c_str());
        context.CloseDistributedFileConnection(offlineEvent.networkId);
        Transfer(context, event);
    }
}

void StateMachine::OnProfileChanged(Context &context, const CooperateEvent &event)
{
    CALL_INFO_TRACE;
    DDPCooperateSwitchChanged notice = std::get<DDPCooperateSwitchChanged>(event.event);
    context.eventMgr_.OnProfileChanged(notice);
    Transfer(context, event);
}

void StateMachine::OnPointerEvent(Context &context, const CooperateEvent &event)
{
    CALL_DEBUG_ENTER;
    InputPointerEvent pointerEvent = std::get<InputPointerEvent>(event.event);
    Coordinate cursorPos = context.CursorPosition();
    context.OnPointerEvent(pointerEvent);
    pointerEvent.position = cursorPos;
    Transfer(context, CooperateEvent { CooperateEventType::INPUT_POINTER_EVENT, pointerEvent });
}

void StateMachine::OnSoftbusSessionClosed(Context &context, const CooperateEvent &event)
{
    CALL_INFO_TRACE;
    DSoftbusSessionClosed notice = std::get<DSoftbusSessionClosed>(event.event);
    context.eventMgr_.OnSoftbusSessionClosed(notice);
    context.inputDevMgr_.OnSoftbusSessionClosed(notice);
    context.mouseLocation_.OnSoftbusSessionClosed(notice);
    context.CloseDistributedFileConnection(notice.networkId);
    Transfer(context, event);
}

void StateMachine::OnSoftbusSessionOpened(Context &context, const CooperateEvent &event)
{
    CALL_INFO_TRACE;
    CHKPV(env_);
    DSoftbusSessionOpened notice = std::get<DSoftbusSessionOpened>(event.event);
    context.inputDevMgr_.OnSoftbusSessionOpened(notice);
    env_->GetDSoftbus().StartHeartBeat(notice.networkId);
    Transfer(context, event);
}

void StateMachine::OnHotPlugEvent(Context &context, const CooperateEvent &event)
{
    CALL_INFO_TRACE;
    InputHotplugEvent notice = std::get<InputHotplugEvent>(event.event);
    context.inputDevMgr_.OnLocalHotPlug(notice);
    Transfer(context, event);
}

void StateMachine::OnRemoteInputDevice(Context &context, const CooperateEvent &event)
{
    CALL_INFO_TRACE;
    DSoftbusSyncInputDevice notice = std::get<DSoftbusSyncInputDevice>(event.event);
    context.inputDevMgr_.OnRemoteInputDevice(notice);
    Transfer(context, event);
}

void StateMachine::OnRemoteHotPlug(Context &context, const CooperateEvent &event)
{
    CALL_INFO_TRACE;
    DSoftbusHotPlugEvent notice = std::get<DSoftbusHotPlugEvent>(event.event);
    context.inputDevMgr_.OnRemoteHotPlug(notice);
    Transfer(context, event);
}

void StateMachine::OnSoftbusSubscribeMouseLocation(Context &context, const CooperateEvent &event)
{
    CALL_INFO_TRACE;
    DSoftbusSubscribeMouseLocation notice = std::get<DSoftbusSubscribeMouseLocation>(event.event);
    context.mouseLocation_.OnSubscribeMouseLocation(notice);
}

void StateMachine::OnSoftbusUnSubscribeMouseLocation(Context &context, const CooperateEvent &event)
{
    CALL_INFO_TRACE;
    DSoftbusUnSubscribeMouseLocation notice = std::get<DSoftbusUnSubscribeMouseLocation>(event.event);
    context.mouseLocation_.OnUnSubscribeMouseLocation(notice);
}

void StateMachine::OnSoftbusReplySubscribeMouseLocation(Context &context, const CooperateEvent &event)
{
    CALL_INFO_TRACE;
    DSoftbusReplySubscribeMouseLocation notice = std::get<DSoftbusReplySubscribeMouseLocation>(event.event);
    context.mouseLocation_.OnReplySubscribeMouseLocation(notice);
}

void StateMachine::OnSoftbusReplyUnSubscribeMouseLocation(Context &context, const CooperateEvent &event)
{
    CALL_INFO_TRACE;
    DSoftbusReplyUnSubscribeMouseLocation notice = std::get<DSoftbusReplyUnSubscribeMouseLocation>(event.event);
    context.mouseLocation_.OnReplyUnSubscribeMouseLocation(notice);
}

void StateMachine::OnSoftbusMouseLocation(Context &context, const CooperateEvent &event)
{
    CALL_DEBUG_ENTER;
    DSoftbusSyncMouseLocation notice = std::get<DSoftbusSyncMouseLocation>(event.event);
    context.mouseLocation_.OnRemoteMouseLocation(notice);
}

void StateMachine::OnRemoteStart(Context &context, const CooperateEvent &event)
{
    CALL_DEBUG_ENTER;
    CHKPV(env_);
    DSoftbusStartCooperate startEvent = std::get<DSoftbusStartCooperate>(event.event);
    CooperateRadarInfo radarInfo {
        .funcName =  __FUNCTION__,
        .bizState = static_cast<int32_t> (BizState::STATE_END),
        .bizScene = static_cast<int32_t> (BizCooperateScene::SCENE_PASSIVE),
        .hostName = "",
        .localNetId = Utility::DFXRadarAnonymize(context.Local().c_str()),
        .peerNetId = Utility::DFXRadarAnonymize(startEvent.originNetworkId.c_str())
    };
    bool checkSameAccount { false };
    if (startEvent.userId > 0) {
        checkSameAccount = env_->GetDDM().CheckSinkIsSameAccount(startEvent.originNetworkId, startEvent.userId,
            startEvent.accountId);
    } else {
        checkSameAccount = env_->GetDDM().CheckSameAccountToLocal(startEvent.originNetworkId);
    }
    if (!checkSameAccount) {
        radarInfo.bizStage = static_cast<int32_t> (BizCooperateStage::STAGE_PASSIVE_CHECK_SAME_ACCOUNT);
        radarInfo.stageRes = static_cast<int32_t> (BizCooperateStageRes::RES_FAIL);
        radarInfo.errCode = static_cast<int32_t> (CooperateRadarErrCode::PASSIVE_CHECK_SAME_ACCOUNT_FAILED);
        CooperateRadar::ReportCooperateRadarInfo(radarInfo);
    }
    if (!isCooperateEnable_) {
        radarInfo.bizStage = static_cast<int32_t> (BizCooperateStage::STAGE_CHECK_PEER_SWITCH);
        radarInfo.stageRes = static_cast<int32_t> (BizCooperateStageRes::RES_FAIL);
        radarInfo.errCode = static_cast<int32_t> (CooperateRadarErrCode::CHECK_PEER_SWITCH_FAILED);
        CooperateRadar::ReportCooperateRadarInfo(radarInfo);
    }
    if (!checkSameAccount || !isCooperateEnable_) {
        FI_HILOGE("CheckSameAccountToLocal failed, switch is : %{public}d, unchain", isCooperateEnable_);
        CooperateEvent stopEvent(
            CooperateEventType::STOP,
            StopCooperateEvent {
                .isUnchained = true
            }
        );
        Transfer(context, stopEvent);
        return;
    }
    Transfer(context, event);
}

void StateMachine::OnRemoteStartWithOptions(Context &context, const CooperateEvent &event)
{
    CALL_DEBUG_ENTER;
    DSoftbusCooperateOptions startEvent = std::get<DSoftbusCooperateOptions>(event.event);
    CooperateRadarInfo radarInfo {
        .funcName =  __FUNCTION__,
        .bizState = static_cast<int32_t> (BizState::STATE_END),
        .bizScene = static_cast<int32_t> (BizCooperateScene::SCENE_PASSIVE),
        .hostName = "",
        .localNetId = Utility::DFXRadarAnonymize(context.Local().c_str()),
        .peerNetId = Utility::DFXRadarAnonymize(startEvent.originNetworkId.c_str())
    };
    bool checkSameAccount { false };
    if (startEvent.userId > 0) {
        checkSameAccount = env_->GetDDM().CheckSinkIsSameAccount(startEvent.originNetworkId, startEvent.userId,
            startEvent.accountId);
    } else {
        checkSameAccount = env_->GetDDM().CheckSameAccountToLocal(startEvent.originNetworkId);
    }
    if (!checkSameAccount) {
        radarInfo.bizStage = static_cast<int32_t> (BizCooperateStage::STAGE_PASSIVE_CHECK_SAME_ACCOUNT);
        radarInfo.stageRes = static_cast<int32_t> (BizCooperateStageRes::RES_FAIL);
        radarInfo.errCode = static_cast<int32_t> (CooperateRadarErrCode::PASSIVE_CHECK_SAME_ACCOUNT_FAILED);
        CooperateRadar::ReportCooperateRadarInfo(radarInfo);
    }
    if (!isCooperateEnable_) {
        radarInfo.bizStage = static_cast<int32_t> (BizCooperateStage::STAGE_CHECK_PEER_SWITCH);
        radarInfo.stageRes = static_cast<int32_t> (BizCooperateStageRes::RES_FAIL);
        radarInfo.errCode = static_cast<int32_t> (CooperateRadarErrCode::CHECK_PEER_SWITCH_FAILED);
        CooperateRadar::ReportCooperateRadarInfo(radarInfo);
    }
    if (!checkSameAccount || !isCooperateEnable_) {
        FI_HILOGE("CheckSameAccountToLocal failed, switch is : %{public}d, unchain", isCooperateEnable_);
        CooperateEvent stopEvent(
            CooperateEventType::STOP,
            StopCooperateEvent {
                .isUnchained = true
            }
        );
        Transfer(context, stopEvent);
        return;
    }
    Transfer(context, event);
}

void StateMachine::UpdateVirtualDeviceIdMap(Context &context, const CooperateEvent &event)
{
    CALL_DEBUG_ENTER;
    UpdateVirtualDeviceIdMapEvent notice = std::get<UpdateVirtualDeviceIdMapEvent>(event.event);
    context.inputEventBuilder_.UpdateVirtualDeviceIdMap(notice.remote2VirtualIds);
}

void StateMachine::Transfer(Context &context, const CooperateEvent &event)
{
    states_[current_]->OnEvent(context, event);
}

sptr<AppExecFwk::IAppMgr> StateMachine::GetAppMgr()
{
    CALL_INFO_TRACE;
    auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
    CHKPP(saMgr);
    auto appMgrObj = saMgr->GetSystemAbility(APP_MGR_SERVICE_ID);
    CHKPP(appMgrObj);
    return iface_cast<AppExecFwk::IAppMgr>(appMgrObj);
}

int32_t StateMachine::RegisterApplicationStateObserver(Channel<CooperateEvent>::Sender sender,
    const EnableCooperateEvent &event)
{
    CALL_INFO_TRACE;
    auto bundleName = GetPackageName(event.tokenId);
    clientBundleNames_.push_back(bundleName);
    FI_HILOGI("Register application %{public}s state observer", bundleName.c_str());
    auto appMgr = GetAppMgr();
    CHKPR(appMgr, RET_ERR);
    appStateObserver_ = sptr<AppStateObserver>::MakeSptr(sender, event.pid);
    auto err = appMgr->RegisterApplicationStateObserver(appStateObserver_, clientBundleNames_);
    if (err != RET_OK) {
        appStateObserver_.clear();
        FI_HILOGE("IAppMgr::RegisterApplicationStateObserver fail, error:%{public}d", err);
        return RET_ERR;
    }
    return RET_OK;
}

void StateMachine::UnregisterApplicationStateObserver()
{
    CALL_INFO_TRACE;
    CHKPV(appStateObserver_);
    auto appMgr = GetAppMgr();
    CHKPV(appMgr);
    FI_HILOGI("Unregister application associateassistant state observer");
    auto err = appMgr->UnregisterApplicationStateObserver(appStateObserver_);
    if (err != RET_OK) {
        FI_HILOGE("IAppMgr::UnregisterApplicationStateObserver fail, error:%{public}d", err);
    }
    appStateObserver_.clear();
}

void StateMachine::UpdateApplicationStateObserver(int32_t clientPid)
{
    CALL_INFO_TRACE;
    CHKPV(appStateObserver_);
    appStateObserver_->UpdateClientPid(clientPid);
}

void StateMachine::AddSessionObserver(Context &context, const EnableCooperateEvent &event)
{
    CALL_INFO_TRACE;
    RegisterApplicationStateObserver(context.Sender(), event);
}

std::string StateMachine::GetPackageName(Security::AccessToken::AccessTokenID tokenId)
{
    CALL_INFO_TRACE;
    std::string bundleName {"Default"};
    int32_t tokenType = Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(tokenId);
    switch (tokenType) {
        case Security::AccessToken::ATokenTypeEnum::TOKEN_HAP: {
            Security::AccessToken::HapTokenInfo hapInfo;
            if (Security::AccessToken::AccessTokenKit::GetHapTokenInfo(tokenId, hapInfo) != RET_OK) {
                FI_HILOGE("Get hap token info failed");
            } else {
                bundleName = hapInfo.bundleName;
            }
            break;
        }
        case Security::AccessToken::ATokenTypeEnum::TOKEN_NATIVE:
        case Security::AccessToken::ATokenTypeEnum::TOKEN_SHELL: {
            Security::AccessToken::NativeTokenInfo tokenInfo;
            if (Security::AccessToken::AccessTokenKit::GetNativeTokenInfo(tokenId, tokenInfo) != RET_OK) {
                FI_HILOGE("Get native token info failed");
            } else {
                bundleName = tokenInfo.processName;
            }
            break;
        }
        default: {
            FI_HILOGW("token type not match");
            break;
        }
    }
    return bundleName;
}

void StateMachine::RemoveSessionObserver(Context &context, const DisableCooperateEvent &event)
{
    UnregisterApplicationStateObserver();
}

void StateMachine::OnCommonEvent(Context &context, const std::string &commonEvent)
{
    FI_HILOGD("Current common event:%{public}s", commonEvent.c_str());
    CHKPV(env_);
    if (commonEvent == EventFwk::CommonEventSupport::COMMON_EVENT_SCREEN_ON ||
        commonEvent == EventFwk::CommonEventSupport::COMMON_EVENT_SCREEN_UNLOCKED) {
        if ((screenEventTimer_ >= 0) && (env_->GetTimerManager().IsExist(screenEventTimer_))) {
            env_->GetTimerManager().RemoveTimer(screenEventTimer_);
            screenEventTimer_ = -1;
        }
    }
    if (commonEvent == EventFwk::CommonEventSupport::COMMON_EVENT_SCREEN_OFF ||
        commonEvent == EventFwk::CommonEventSupport::COMMON_EVENT_SCREEN_LOCKED) {
        context.inputEventBuilder_.SetStopByScreenOffOrLock(true);
        FI_HILOGD("Receive common event:%{public}s, stop cooperate", commonEvent.c_str());
        auto ret = context.Sender().Send(CooperateEvent(
            CooperateEventType::STOP,
            StopCooperateEvent{
                .isUnchained = false
            }));
        if (ret != Channel<CooperateEvent>::NO_ERROR) {
            FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
        }
        screenEventTimer_ = env_->GetTimerManager().AddTimer(SCREEN_LOCKED_TIMEOUT, REPEAT_ONCE,
            [sender = context.Sender(), this]() mutable {
                auto res = sender.Send(CooperateEvent(
                    CooperateEventType::STOP,
                    StopCooperateEvent{
                        .isUnchained = true
                    }));
                if (res != Channel<CooperateEvent>::NO_ERROR) {
                    FI_HILOGE("Failed to send event via channel, error:%{public}d", res);
                }
                screenEventTimer_ = -1;
            });
    }
}

void StateMachine::AddMonitor(Context &context)
{
    CALL_INFO_TRACE;
    if (monitorId_ >= 0) {
        return;
    }
    CHKPV(env_);
    monitorId_ = env_->GetInput().AddMonitor([&context, this] (
            std::shared_ptr<MMI::PointerEvent> pointerEvent) mutable {
            context.hotArea_.ProcessData(pointerEvent);
            context.mouseLocation_.ProcessData(pointerEvent);

            MMI::PointerEvent::PointerItem pointerItem;
            if (!pointerEvent->GetPointerItem(pointerEvent->GetPointerId(), pointerItem)) {
                FI_HILOGE("Corrupted pointer event");
                return;
            }
            auto pointerAction = pointerEvent->GetPointerAction();
            auto sourceType = pointerEvent->GetSourceType();
            if (pointerEvent->HasFlag(MMI::InputEvent::EVENT_FLAG_SIMULATE) &&
                (pointerAction == MMI::PointerEvent::POINTER_ACTION_PULL_IN_WINDOW ||
                pointerAction == MMI::PointerEvent::POINTER_ACTION_PULL_OUT_WINDOW)) {
                FI_HILOGW("PointerAction:%{public}d is simulated, skip", pointerAction);
                return;
            }
            auto ret = context.Sender().Send(CooperateEvent(
                CooperateEventType::INPUT_POINTER_EVENT,
                InputPointerEvent {
                    .deviceId = pointerEvent->GetDeviceId(),
                    .pointerAction = pointerAction,
                    .sourceType = sourceType,
                    .position = Coordinate {
                        .x = pointerItem.GetDisplayX(),
                        .y = pointerItem.GetDisplayY(),
                    },
                    .currentDisplayId = pointerEvent->GetTargetDisplayId(),
                    .pressedButtons = pointerEvent->GetPressedButtons(),
                }));
            if (ret != Channel<CooperateEvent>::NO_ERROR) {
                FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
            }
        }, nullptr, MMI::HANDLE_EVENT_TYPE_MOUSE);
    if (monitorId_ < 0) {
        FI_HILOGE("MMI::Add Monitor fail");
    }
}

void StateMachine::AddPreMonitor(Context &context)
{
    CALL_INFO_TRACE;
    if (preMonitorId_ >= 0) {
        return;
    }
    CHKPV(env_);
    std::vector<int32_t> keys;
    keys.push_back(MMI::KeyEvent::KEYCODE_KEY_PEN_AIR_MOUSE);
    preMonitorId_ = env_->GetInput().AddPreMonitor(nullptr, [&context, this]
        (std::shared_ptr<MMI::KeyEvent> keyEvent) mutable {
            CHKPV(keyEvent);
            if (keyEvent->GetKeyCode() == MMI::KeyEvent::KEYCODE_KEY_PEN_AIR_MOUSE) {
                if (keyEvent->GetKeyAction() == MMI::KeyEvent::KEY_ACTION_DOWN) {
                    FI_HILOGI("Air mouse key down");
                    env_->GetDeviceManager().SetPencilAirMouse(true);
                } else {
                    FI_HILOGI("Air mouse key up or cancel or unknow");
                    env_->GetDeviceManager().SetPencilAirMouse(false);
                }
            }
        }, MMI::HANDLE_EVENT_TYPE_PRE_KEY, keys);
    if (preMonitorId_ < 0) {
        FI_HILOGE("MMI::Add Monitor fail");
    }
}

void StateMachine::RemoveMonitor(Context &context)
{
    CALL_INFO_TRACE;
    CHKPV(env_);
    if (monitorId_ < 0) {
        return;
    }
    env_->GetInput().RemoveMonitor(monitorId_);
    monitorId_ = -1;
}

void StateMachine::RemovePreMonitor(Context &context)
{
    CALL_INFO_TRACE;
    CHKPV(env_);
    if (preMonitorId_ < 0) {
        return;
    }
    env_->GetInput().RemovePreMonitor(preMonitorId_);
    preMonitorId_ = -1;
}

void StateMachine::RemoveWatches()
{
    CALL_INFO_TRACE;
    for (const auto& board : onlineBoards_) {
        FI_HILOGD("Remove watch \'%{public}s\'", Utility::Anonymize(board).c_str());
    }
    onlineBoards_.clear();
}
bool StateMachine::IsCooperateEnable()
{
    return isCooperateEnable_;
}

void StateMachine::ResetCooperate(Context &context)
{
    CALL_INFO_TRACE;
    auto ret = context.Sender().Send(CooperateEvent(
        CooperateEventType::STOP_ABOUT_VIRTUALTRACKPAD,
        StopCooperateEvent {}));
    if (ret != Channel<CooperateEvent>::NO_ERROR) {
        FI_HILOGE("Failed to send event via channel, error:%{public}d", ret);
    }
}

bool StateMachine::CheckIsVirtualTrackpad(int32_t deviceId)
{
    CALL_INFO_TRACE;
    bool isLocalPointerDevice = false;
    MMI::InputManager::GetInstance()->GetDevice(deviceId, [&isLocalPointerDevice, this] (
        std::shared_ptr<MMI::InputDevice> device) -> bool {
            CHKPR(device, false);
            if (device->GetName() == VIRTUAL_TRACK_PAD_NAME) {
                isLocalPointerDevice = true;
                FI_HILOGI("Has virtualTrackpad");
                return isLocalPointerDevice;
            }
            return isLocalPointerDevice;
        });
    return isLocalPointerDevice;
}

} // namespace Cooperate
} // namespace DeviceStatus
} // namespace Msdp
} // namespace OHOS