/*
 * Copyright (C) 2021 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.
 */

#ifndef SERVICES_INCLUDE_INPUT_METHOD_SYSTEM_ABILITY_H
#define SERVICES_INCLUDE_INPUT_METHOD_SYSTEM_ABILITY_H

#include "identity_checker_impl.h"
#include "ime_info_inquirer.h"
#include "input_method_system_ability_stub.h"
#include "input_method_types.h"
#include "input_status_info.h"
#include "input_type_manager.h"
#include "inputmethod_dump.h"
#include "inputmethod_trace.h"
#include "system_ability.h"
#include "user_session_manager.h"

namespace OHOS {
namespace MiscServices {
enum class ServiceRunningState { STATE_NOT_START, STATE_RUNNING };
class InputMethodSystemAbility : public SystemAbility, public InputMethodSystemAbilityStub {
    DECLARE_SYSTEM_ABILITY(InputMethodSystemAbility);

public:
    DISALLOW_COPY_AND_MOVE(InputMethodSystemAbility);
    InputMethodSystemAbility(int32_t systemAbilityId, bool runOnCreate);
    InputMethodSystemAbility();
    ~InputMethodSystemAbility();
    int32_t OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override;
    ErrCode StartInput(const InputClientInfoInner &inputClientInfoInner, std::vector<sptr<IRemoteObject>> &agents,
        std::vector<BindImeInfo> &imeInfos) override;
    ErrCode ShowCurrentInput(uint32_t type) override;
    ErrCode ShowCurrentInput(uint64_t displayId, uint32_t type) override;
    ErrCode HideCurrentInput() override;
    ErrCode HideCurrentInput(uint64_t displayId) override;
    ErrCode ShowInput(const sptr<IInputClient> &client, uint32_t windowId,
        uint32_t type = static_cast<uint32_t>(ClientType::INNER_KIT), int32_t requestKeyboardReason = 0) override;
    ErrCode HideInput(const sptr<IInputClient> &client, uint32_t windowId) override;
    ErrCode StopInputSession(uint32_t windowId) override;
    ErrCode ReleaseInput(const sptr<IInputClient> &client, uint32_t sessionId, int32_t clientSessionId) override;
    ErrCode RequestHideInput(uint32_t windowId, uint64_t displayId, bool isFocusTriggered, int32_t userId) override;
    ErrCode GetDefaultInputMethod(Property &prop, bool isBrief, int32_t userId) override;
    ErrCode GetInputMethodConfig(ElementName &inputMethodConfig, int32_t userId) override;
    ErrCode GetCurrentInputMethod(int32_t userId, Property &resultValue) override;
    ErrCode GetCurrentInputMethodSubtype(SubProperty &resultValue, int32_t userId) override;
    ErrCode ListInputMethod(uint32_t status, std::vector<Property> &props, int32_t userId) override;
    ErrCode ListCurrentInputMethodSubtype(std::vector<SubProperty> &subProps, int32_t userId) override;
    ErrCode ListInputMethodSubtype(const std::string &bundleName, std::vector<SubProperty> &subProps,
        int32_t userId) override;
    ErrCode SwitchInputMethod(const std::string &bundleName, const std::string &subName, uint32_t trigger,
        int32_t userId) override;
    ErrCode DisplayOptionalInputMethod() override;
    ErrCode SetCoreAndAgent(const sptr<IInputMethodCore> &core, const sptr<IRemoteObject> &agent) override;
    ErrCode InitConnect() override;
    ErrCode PanelStatusChange(uint32_t status, const ImeWindowInfo &info) override;
    ErrCode NotifyInputStart(const InputStartInfo &inputStartInfo) override;
    ErrCode NotifyInputStop(const InputStopInfo &inputStopInfo) override;
    ErrCode NotifySoftKeyBoardInfoChanged(const BoundImeInfo &oldImeInfo, const BoundImeInfo &newImeInfo) override;
    ErrCode GetSoftKeyboardInfo(int32_t userId, BoundImeInfo &imeInfo) override;
    ErrCode UpdateListenEventFlag(const InputClientInfoInner &clientInfoInner, uint32_t eventFlag) override;
    ErrCode SetCallingWindow(uint32_t windowId, const sptr<IInputClient> &client) override;
    ErrCode GetInputStartInfo(InputStartInfo &inputStartInfo) override;
    ErrCode SendPrivateData(const Value &value) override;

    ErrCode IsCurrentIme(bool &resultValue) override;
    ErrCode IsInputTypeSupported(int32_t type, bool &resultValue) override;
    ErrCode IsCurrentImeByPid(int32_t pid, bool &resultValue, int32_t userId) override;
    ErrCode StartInputType(int32_t type, bool isPersistence) override;
    ErrCode StartInputTypeAsync(int32_t type, bool isPersistence) override;
    ErrCode ExitCurrentInputType() override;
    ErrCode IsPanelShown(const PanelInfo &panelInfo, bool &isShown) override;
    ErrCode IsPanelShown(uint64_t displayId, const PanelInfo &panelInfo, bool &isShown) override;
    ErrCode GetSecurityMode(int32_t &security) override;
    ErrCode ConnectSystemCmd(const sptr<IRemoteObject> &channel, sptr<IRemoteObject> &agent) override;
    // Deprecated because of no permission check, kept for compatibility
    ErrCode HideCurrentInputDeprecated(uint32_t windowId) override;
    ErrCode ShowCurrentInputDeprecated(uint32_t windowId) override;
    int Dump(int fd, const std::vector<std::u16string> &args) override;
    void DumpAllMethod(int fd);
    ErrCode IsDefaultIme() override;
    ErrCode IsDefaultImeSet(bool &resultValue, int32_t userId) override;
    ErrCode EnableIme(const std::string &bundleName, const std::string &extensionName, int32_t status,
        int32_t userId) override;
    ErrCode GetInputMethodState(int32_t &status) override;
    ErrCode IsSystemApp(bool &resultValue) override;
    int32_t RegisterProxyIme(
        uint64_t displayId, const sptr<IInputMethodCore> &core, const sptr<IRemoteObject> &agent) override;
    ErrCode UnregisterProxyIme(uint64_t displayId, int32_t type) override;
    ErrCode IsRestrictedDefaultImeByDisplay(uint64_t displayId, bool &resultValue) override;
    ErrCode IsKeyboardCallingProcess(int32_t pid, uint32_t windowId, bool &isKeyboardCallingProcess) override;
    ErrCode IsCapacitySupport(int32_t capacity, bool &isSupport) override;
    ErrCode BindImeMirror(const sptr<IInputMethodCore> &core, const sptr<IRemoteObject> &agent) override;
    ErrCode UnbindImeMirror() override;
    ErrCode GetCursorInfo(int32_t userId, CursorInfoInner &cursorInfo) override;
    int32_t SetEDCDefaultInputMethod(const std::string &edcBackupImeName) override;
    int32_t GetCallingUserId();
    int32_t GetCallingUserId(int32_t &outputUserId, int32_t inputUserId = -1);

protected:
    void OnStart() override;
    void OnStop() override;
    int32_t OnIdle(const SystemAbilityOnDemandReason &idleReason) override;
    int32_t OnExtension(const std::string &extension, MessageParcel &data, MessageParcel &reply) override;

private:
    int32_t Init();
    void Initialize();

    std::thread workThreadHandler; /*!< thread handler of the WorkThread */
    std::shared_ptr<PerUserSession> GetSessionFromMsg(const Message *msg);
    int32_t PrepareForOperateKeyboard(std::shared_ptr<PerUserSession> &session, uint32_t windowId = 0,
        const sptr<IRemoteObject> &abilityToken = nullptr);
    int32_t SwitchByCondition(const Condition &condition, const std::shared_ptr<ImeInfo> &info, int32_t userId);
    int32_t GetUserId(int32_t uid);
    uint64_t GetCallingDisplayId(int32_t userId, sptr<IRemoteObject> abilityToken = nullptr);
    std::shared_ptr<IdentityChecker> identityChecker_ = nullptr;
    int32_t PrepareInput(int32_t userId, InputClientInfo &clientInfo, const FocusedInfo &focusedInfo);
    void WorkThread();
    int32_t OnHideKeyboardSelf(const Message *msg);
    void OnSysMemChanged();
    int32_t OnSysImeImageCreated(const Message *msg);
    int32_t OnMakeSysImeImage();
    int32_t GetCpuUsage();
    bool IsNeedSwitch(int32_t userId, const std::string &bundleName, const std::string &subName);
    int32_t CheckEnableAndSwitchPermission();
    int32_t CheckSwitchPermission(int32_t userId, const SwitchInfo &switchInfo, SwitchTrigger trigger);
    bool IsStartInputTypePermitted(int32_t userId);
    int32_t SwitchInputMethodInner(int32_t userId, const std::string &bundleName, const std::string &subName,
        SwitchTrigger trigger);
    int32_t OnSwitchInputMethod(int32_t userId, const SwitchInfo &switchInfo, SwitchTrigger trigger);
    int32_t StartSwitch(int32_t userId, const SwitchInfo &switchInfo, const std::shared_ptr<PerUserSession> &session);
    int32_t OnStartInputType(int32_t userId, const SwitchInfo &switchInfo,
        bool isCheckPermission, bool isPersistence = true);
    int32_t SwitchToEDCBackupInputMethod(int32_t userId, const std::string &edcBackupImeName,
        const std::shared_ptr<ImeInfo> &imeInfo);
    int32_t HandleEDCInputMethodAutoSwitch(int32_t userId, const std::string &edcBackupImeName);
    bool SetEDCBackupInputMethod(int32_t userId, const std::string &backupIme);
    bool GetEDCBackupInputMethod(int32_t userId, std::string &backupIme);
    void HandleEDCInputMethodInstall(int32_t userId, const std::string &installedBundleName);
    void HandleEDCInputMethodRemove(int32_t userId, const std::string &removedBundleName);
    int32_t HandlePackageEvent(const Message *msg);
    int32_t HandleUpdateLargeMemoryState(const Message *msg);
    int32_t OnPackageRemoved(int32_t userId, const std::string &packageName);
    int32_t OnPackageUpdated(int32_t userId, const std::string &packageName);
    void OnScreenUnlock(const Message *msg);
    void OnScreenLock(const Message *msg);
    int32_t OnDisplayOptionalInputMethod();
    void SubscribeCommonEvent();
    int32_t SwitchInputType(int32_t userId, const SwitchInfo &switchInfo, bool isPersistence = true);
    void StartNewUserIme(int32_t userId);
    void GetValidSubtype(const std::string &subName, const std::shared_ptr<ImeInfo> &info);
    ServiceRunningState state_;
    void InitServiceHandler();

    void HandleFocusChanged(bool isFocused, uint64_t displayId, int32_t pid, int32_t uid);
    void HandleWmsConnected(int32_t userId, int32_t screenId, pid_t pid);
    void HandleWmsDisconnected(int32_t userId, int32_t screenId, pid_t pid);

    void HandleWmsStarted();
    void HandleMemStarted();
    void HandleDataShareReady();
    void HandleOsAccountStarted();
    void HandleImeCfgCapsState(int32_t userId);
    void HandlePasteboardStarted();

    int32_t InitAccountMonitor();
    static std::shared_ptr<AppExecFwk::EventHandler> serviceHandler_;
    std::atomic<int32_t> userId_;
    bool stop_ = false;
    void InitMonitors();
    int32_t InitKeyEventMonitor();
    bool InitWmsMonitor();
    void InitSystemLanguageMonitor();
    bool InitMemMgrMonitor();
    bool InitFocusChangedMonitor(int32_t userId);
    bool InitPasteboardMonitor();
    bool InitHaMonitor();
    void SubscribeAppMgrService();
    bool InitWmsConnectionMonitor(int32_t userId);
    bool InitWindowDisplayChangedMonitor(int32_t userId);
    bool InitDisplayGroupMonitor(int32_t userId);
    bool InitWindowMonitors(int32_t userId);
    void RemoveWindowMonitors(int32_t userId);
    int32_t SwitchByCombinationKey(uint32_t state);
    int32_t SwitchMode(int32_t userId);
    int32_t SwitchLanguage(int32_t userId);
    int32_t SwitchType(int32_t userId);
    int32_t GenerateClientInfo(int32_t userId, InputClientInfo &clientInfo, const FocusedInfo &focusedInfo = {});
    void RegisterSecurityModeObserver();
    int32_t EnsureImeAvailable(int32_t userId, InputClientInfo &inputClientInfo);
    int32_t IsDefaultImeFromTokenId(int32_t userId, uint32_t tokenId);
    void DealSwitchRequest(int32_t userId);
    bool IsCurrentIme(int32_t userId, uint32_t tokenId);
    int32_t StartInputType(int32_t userId, InputType type, bool isPersistence = true);
    // if switch input type need to switch ime, then no need to hide panel first.
    void NeedHideWhenSwitchInputType(int32_t userId, InputType type, bool &needHide);
    bool GetDeviceFunctionKeyState(int32_t functionKey, bool &isEnable);
    bool ModifyImeCfgWithWrongCaps(int32_t userId);
    void HandleBundleScanFinished();
    int32_t StartInputInner(InputClientInfo &inputClientInfo, std::vector<sptr<IRemoteObject>> &agents,
        std::vector<BindImeInfo> &imeInfos, bool &failedByUnavailableIme);
    std::pair<bool, FocusedInfo> IsFocusedOrBroker(int64_t callingPid, uint32_t callingTokenId, int32_t userId,
        uint32_t windowId = 0, const sptr<IRemoteObject> &abilityToken = nullptr);
    int32_t ShowInputInner(sptr<IInputClient> client, uint32_t windowId, int32_t requestKeyboardReason = 0);
    int32_t ShowCurrentInputInner();
    int32_t ShowCurrentInputInner(uint64_t displayId);
    std::pair<int64_t, std::string> GetCurrentImeInfoForHiSysEvent(int32_t userId);
    int32_t GetScreenLockIme(int32_t userId, std::string &ime);
    int32_t GetAlternativeIme(int32_t userId, std::string &ime);
    static InputType GetSecurityInputType(const InputClientInfo &inputClientInfo);
    int32_t StartSecurityIme(int32_t &userId, InputClientInfo &inputClientInfo);
#ifdef IMF_ON_DEMAND_START_STOP_SA_ENABLE
    int64_t GetTickCount();
    void ResetDelayUnloadTask(uint32_t code = 0);
    bool IsImeInUse();
#endif
    std::mutex checkMutex_;
    int32_t EnableIme(int32_t userId, const std::string &bundleName, const std::string &extensionName = "",
        EnabledStatus status = EnabledStatus::BASIC_MODE);
    void OnCurrentImeStatusChanged(int32_t userId, const std::string &bundleName, EnabledStatus newStatus);
    void DataShareCallback(const std::string &key);
    bool IsValidBundleName(const std::string &bundleName);
    std::string GetRestoreBundleName(MessageParcel &data);
    int32_t RestoreInputmethod(std::string &bundleName);
    void IncreaseAttachCount();
    void DecreaseAttachCount();
    bool IsTmpIme(int32_t userId, uint32_t tokenId);
    bool IsTmpImeSwitchSubtype(int32_t userId, uint32_t tokenId, const SwitchInfo &switchInfo);
    void SendMessageToWorkThread(int32_t eventId);

    void ResetAllImes();
    void RestartAllForegroundImes();
    void StopAllBackgroundImes();

    int32_t OnUserSwitched(const Message *msg);
    int32_t OnUserRemoved(const Message *msg);
    int32_t OnUserStop(const Message *msg);
    void HandleUserSwitchedOut(int32_t userId, uint64_t displayId);
    void HandleUserSwitchedIn(int32_t userId, uint64_t displayId);
    void InitAllUsersWindowMonitors();
    void InitUserInfo(int32_t userId, uint64_t displayId);
    void UpdateUserInfo(int32_t userId, uint64_t displayId);

    class AttachStateGuard {
    public:
        explicit AttachStateGuard(InputMethodSystemAbility &ability) : ability_(ability)
        {
            ability_.IncreaseAttachCount();
        }
        ~AttachStateGuard()
        {
            ability_.DecreaseAttachCount();
        }

    private:
        InputMethodSystemAbility &ability_;
    };

    std::atomic<bool> isBundleScanFinished_ = false;
    std::atomic<bool> isScbEnable_ = false;
    std::mutex switchImeMutex_;
    std::atomic<bool> switchTaskExecuting_ = false;
    std::atomic<uint32_t> targetSwitchCount_ = 0;
    std::atomic<bool> isAccountSaFirstStart_{ true };
    std::atomic<bool> waitAccountReadyToInit_{ false };
};
} // namespace MiscServices
} // namespace OHOS
#endif // SERVICES_INCLUDE_INPUT_METHOD_SYSTEM_ABILITY_H