/*
 * Copyright (C) 2021-2023 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 FRAMEWORKS_INPUTMETHOD_ABILITY_INCLUDE_INPUT_METHOD_ABILITY_H
#define FRAMEWORKS_INPUTMETHOD_ABILITY_INCLUDE_INPUT_METHOD_ABILITY_H

#include <thread>

#include "calling_window_info.h"
#include "concurrent_map.h"
#include "context.h"
#include "iinput_control_channel.h"
#include "iinput_data_channel.h"
#include "iinput_method_agent.h"
#include "iinput_method_core.h"
#include "iinput_method_system_ability.h"
#include "input_attribute.h"
#include "input_control_channel_proxy.h"
#include "input_data_channel_proxy.h"
#include "input_method_engine_listener.h"
#include "input_method_panel.h"
#include "input_method_types.h"
#include "input_method_utils.h"
#include "input_status_info.h"
#include "iremote_object.h"
#include "keyboard_listener.h"
#include "key_event_consumer_proxy.h"
#include "text_input_client_listener.h"
#include "msg_handler_callback_interface.h"
#include "private_command_interface.h"
#include "system_cmd_channel_proxy.h"
#include "inputmethod_message_handler.h"
#include "input_data_channel_proxy_wrap.h"
#include "ime_mirror_manager.h"

namespace OHOS {
namespace MiscServices {
class InputMethodAbility : public RefBase, public PrivateCommandInterface {
public:
    static InputMethodAbility &GetInstance();
    int32_t SetCoreAndAgent();
    int32_t InitConnect();
    int32_t RegisterProxyIme(uint64_t displayId);
    int32_t UnregisterProxyIme(uint64_t displayId, UnRegisteredType type = UnRegisteredType::REMOVE_PROXY_IME);
    int32_t BindImeMirror();
    int32_t UnbindImeMirror();
    int32_t InsertText(const std::string &text, const AsyncIpcCallBack &callback = nullptr);
    void SetImeListener(std::shared_ptr<InputMethodEngineListener> imeListener);
    std::shared_ptr<InputMethodEngineListener> GetImeListener();
    void SetKdListener(std::shared_ptr<KeyboardListener> kdListener);
    void SetTextInputClientListener(std::shared_ptr<TextInputClientListener> textInputClientListener);
    int32_t DeleteForward(int32_t length, const AsyncIpcCallBack &callback = nullptr);
    int32_t DeleteBackward(int32_t length, const AsyncIpcCallBack &callback = nullptr);
    int32_t HideKeyboardSelf();

    int32_t SendExtendAction(int32_t action, const AsyncIpcCallBack &callback = nullptr);
    int32_t GetTextBeforeCursor(int32_t number, std::u16string &text, const AsyncIpcCallBack &callback = nullptr);
    int32_t GetTextAfterCursor(int32_t number, std::u16string &text, const AsyncIpcCallBack &callback = nullptr);
    int32_t SendFunctionKey(int32_t funcKey, const AsyncIpcCallBack &callback = nullptr);
    int32_t MoveCursor(int32_t keyCode, const AsyncIpcCallBack &callback = nullptr);
    int32_t SelectByRange(int32_t start, int32_t end, const AsyncIpcCallBack &callback = nullptr);
    int32_t SelectByMovement(int32_t direction, const AsyncIpcCallBack &callback = nullptr);
    int32_t DispatchKeyEvent(
        const std::shared_ptr<MMI::KeyEvent> &keyEvent, uint64_t cbId, const sptr<IRemoteObject> &channelObject);
    void SetCallingWindow(uint32_t rawEditorWindowId, const FocusedInfo &focusedInfo);
    int32_t GetEnterKeyType(int32_t &keyType);
    int32_t GetInputPattern(int32_t &inputPattern);
    int32_t GetTextIndexAtCursor(int32_t &index, const AsyncIpcCallBack &callback = nullptr);
    int32_t GetTextConfig(TextTotalConfig &textConfig);
    int32_t AdjustKeyboard();
    int32_t CreatePanel(const std::shared_ptr<AbilityRuntime::Context> &context, const PanelInfo &panelInfo,
        std::shared_ptr<InputMethodPanel> &inputMethodPanel);
    int32_t DestroyPanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel);
    int32_t ShowPanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel);
    int32_t HidePanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel);
    bool IsCurrentIme();
    bool IsEnable(uint64_t displayId);
    bool IsCallbackRegistered(const std::string &type);
    bool IsSystemApp();
    InputType GetInputType();
    int32_t ExitCurrentInputType();
    int32_t IsPanelShown(const PanelInfo &panelInfo, bool &isShown);
    int32_t GetSecurityMode(int32_t &security);
    int32_t OnSecurityChange(int32_t security);
    int32_t OnConnectSystemCmd(const sptr<IRemoteObject> &channel);
    void OnClientInactive(const sptr<IRemoteObject> &channel);
    void NotifyKeyboardHeight(uint32_t panelHeight, PanelFlag panelFlag);
    int32_t SendPrivateCommand(const std::unordered_map<std::string, PrivateDataValue> &privateCommand,
        bool validateDefaultIme = true) override;
    int32_t ReceivePrivateCommand(const std::unordered_map<std::string, PrivateDataValue> &privateCommand) override;
    bool IsDefaultIme();
    int32_t GetCallingWindowInfo(CallingWindowInfo &windowInfo);
    int32_t SetPreviewText(const std::string &text, const Range &range, const AsyncIpcCallBack &callback = nullptr);
    int32_t FinishTextPreview(const AsyncIpcCallBack &callback = nullptr);
    int32_t NotifyPanelStatus(bool isUseParameterFlag = false, PanelFlag panelFlag = FLG_FIXED,
        bool isCheckFuncButton = false);
    InputAttribute GetInputAttribute();
    void OnSetInputType(InputType inputType, uint64_t displayId);
    int32_t SendMessage(const ArrayBuffer &arrayBuffer);
    int32_t RecvMessage(const ArrayBuffer &arrayBuffer);
    int32_t RegisterMsgHandler(const std::shared_ptr<MsgHandlerCallbackInterface> &msgHandler = nullptr);
    int32_t OnCallingDisplayIdChanged(uint64_t editorDisplayId, uint64_t keyboardDisplayId);
    int32_t OnSendPrivateData(const std::unordered_map<std::string, PrivateDataValue> &privateCommand);
    bool HandleUnconsumedKey(const std::shared_ptr<MMI::KeyEvent> &keyEvent);
    int32_t OnResponse(uint64_t msgId, int32_t code, const ResponseData &data);
    int32_t IsCapacitySupport(int32_t capacity, bool &isSupport);
    AttachOptions GetAttachOptions();
    int32_t HandleKeyEventResult(uint64_t cbId, bool consumeResult, const sptr<IRemoteObject> &channelObject);
    void RemoveDeathRecipient();
    void SetConfigurationUpdate(std::function<void(Rosen::DisplayId displayId)> configurationUpdate);

public:
    /* called from TaskManager worker thread */
    int32_t StartInput(const InputClientInfo &clientInfo, bool isBindFromClient);
    int32_t StopInput(sptr<IRemoteObject> channelObj, uint32_t sessionId, int32_t clientSessionId = -1);
    int32_t ShowKeyboard(int32_t requestKeyboardReason);
    int32_t HideKeyboard();
    int32_t OnDiscardTypingText();
    int32_t OnNotifyPreemption();

    void OnInitInputControlChannel(sptr<IRemoteObject> channelObj);
    void OnSetSubtype(SubProperty subProperty);
    void OnCursorUpdate(int32_t positionX, int32_t positionY, int32_t height);
    void OnSelectionChange(std::u16string text, int32_t oldBegin, int32_t oldEnd, int32_t newBegin, int32_t newEndg);
    void OnAttributeChange(InputAttribute attribute);
    void OnFunctionKey(int32_t funcKey);
    SysPanelStatus GetSysPanelStatus();

    int32_t OnStopInputService(bool isTerminateIme);
    HiSysEventClientInfo GetBindClientInfo();
    int32_t GetSoftKeyboardInfo(BoundImeInfo &imeInfo);
private:
    std::mutex controlChannelLock_;
    std::shared_ptr<InputControlChannelProxy> controlChannel_ = nullptr;

    std::mutex dataChannelLock_;
    sptr<IRemoteObject> dataChannelObject_ = nullptr;
    std::shared_ptr<InputDataChannelProxyWrap> dataChannelProxyWrap_ = nullptr;
    sptr<InputDeathRecipient> dataChannelDeathRecipient_{ nullptr };

    std::mutex systemCmdChannelLock_;
    sptr<SystemCmdChannelProxy> systemCmdChannelProxy_ = nullptr;

    std::shared_ptr<InputMethodEngineListener> imeListener_;
    std::shared_ptr<KeyboardListener> kdListener_;
    std::shared_ptr<TextInputClientListener> textInputClientListener_;

    std::mutex abilityLock_;
    sptr<IInputMethodSystemAbility> abilityManager_ { nullptr };
    sptr<InputDeathRecipient> deathRecipient_ { nullptr };
    InputMethodAbility();
    ~InputMethodAbility();
    InputMethodAbility(const InputMethodAbility &) = delete;
    InputMethodAbility &operator=(const InputMethodAbility &) = delete;
    sptr<IInputMethodSystemAbility> GetImsaProxy();
    void OnRemoteSaDied(const wptr<IRemoteObject> &object);

    sptr<SystemCmdChannelProxy> GetSystemCmdChannelProxy();
    void ClearSystemCmdChannel();

    void SetInputDataChannel(const sptr<IRemoteObject> &object);
    std::shared_ptr<InputDataChannelProxyWrap> GetInputDataChannelProxyWrap();
    std::shared_ptr<InputDataChannelProxy> GetInputDataChannelProxy();
    void ClearDataChannel(const sptr<IRemoteObject> &channel);
    void SetInputControlChannel(sptr<IRemoteObject> &object);
    void ClearInputControlChannel();
    std::shared_ptr<InputControlChannelProxy> GetInputControlChannel();

    void Initialize();
    int32_t InvokeStartInputCallbackWithInfoRestruct(const TextTotalConfig &textConfig, bool isNotifyInputStart);
    int32_t InvokeStartInputCallback(const TextTotalConfig &textConfig, bool isNotifyInputStart);
    void HandleRequestKeyboardReasonChanged(const RequestKeyboardReason &requestKeyboardReason);
    void InvokeAttachOptionsCallback(const AttachOptions &options, bool isFirstNotify = false);
    void SetAttachOptions(const AttachOptions &options);
    void ClearAttachOptions();
    int32_t HideKeyboard(Trigger trigger, uint32_t sessionId, int32_t clientSessionId = -1);
    std::shared_ptr<InputMethodPanel> GetSoftKeyboardPanel();
    /* param flag: ShowPanel is async, show/hide softkeyboard in alphabet keyboard attached,
       flag will be changed before finishing show/hide */
    int32_t ShowPanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel, PanelFlag flag, Trigger trigger);
    int32_t HidePanel(const std::shared_ptr<InputMethodPanel> &inputMethodPanel, PanelFlag flag, Trigger trigger,
        uint32_t sessionId, int32_t clientSessionId = -1);
    void SetInputAttribute(const InputAttribute &inputAttribute);
    void ClearInputAttribute();
    void NotifyPanelStatusInfo(PanelStatusInfo &info);
    int32_t HideKeyboardImplWithoutLock(int32_t cmdId, uint32_t sessionId, int32_t clientSessionId = -1);
    int32_t ShowKeyboardWithoutLock(int32_t cmdId, InputStartScene scene);
    int32_t ShowKeyboardImplWithoutLock(int32_t cmdId);
    void NotifyPanelStatusInfo(PanelStatusInfo &info, std::shared_ptr<InputDataChannelProxy> &channelProxy);
    void ClearInputType();
    std::shared_ptr<MsgHandlerCallbackInterface> GetMsgHandlerCallback();
    int32_t StartInputInner(const InputClientInfo &clientInfo, bool isBindFromClient);
    bool NotifyInfoToWmsInStartInput(const TextTotalConfig &textConfig);
    void SetBindClientInfo(const InputClientInfo &clientInfo);
    void ClearBindClientInfo();
    void ReportImeStartInput(int32_t eventCode, int32_t errCode, bool isShowKeyboard, int64_t consumeTime = -1);
    void ClearBindInfo(const sptr<IRemoteObject> &channel);
    void OnInputDataChannelDied(const sptr<IRemoteObject> &dataChannelObject);
    void UpdatePrivateCommand(const std::unordered_map<std::string, PrivateDataValue> &privateCommand);
    void PushPrivateCommand();
    void SetSysPanelStatus(const SysPanelStatus &sysPanelStatus);
    bool IsSystemPanelSupported();
    void ConfigurationUpdate(Rosen::DisplayId displayId);
    void NotifyInputStartToClients(InputStartScene scene, bool isShowKeyboard = true);
    void NotifyInputStopToClients();

    ConcurrentMap<PanelType, std::shared_ptr<InputMethodPanel>> panels_ {};
    std::atomic_bool isBound_ { false };
    std::atomic_bool isProxyIme_{ false };

    sptr<IInputMethodCore> coreStub_ { nullptr };
    sptr<IInputMethodAgent> agentStub_ { nullptr };
    std::mutex imeCheckMutex_;
    bool isCurrentIme_ = false;

    double positionY_ = 0;
    double height_ = 0;

    std::mutex defaultImeCheckMutex_;
    bool isDefaultIme_ = false;
    std::mutex inputAttrLock_;
    InputAttribute inputAttribute_ {};
    std::recursive_mutex keyboardCmdLock_;
    int32_t cmdId_ = 0;
    std::mutex attachOptionsLock_;
    AttachOptions attachOptions_;  // isShowKeyboard not be maintained at present

    std::mutex inputTypeLock_;
    InputType inputType_ = InputType::NONE;
    std::atomic<bool> isImeTerminating_ = false;
    std::atomic_bool isShowAfterCreate_ { false };
    std::atomic<int32_t> securityMode_ = -1;
    std::mutex msgHandlerMutex_;
    std::shared_ptr<MsgHandlerCallbackInterface> msgHandler_;

    std::mutex systemAppCheckMutex_;
    bool isSystemApp_ = false;

    std::mutex bindClientInfoLock_;
    HiSysEventClientInfo bindClientInfo_;
    bool isInputStartNotified_ = false;
    ImeMirrorManager imeMirrorMgr_;

    std::mutex privateCommandLock_;
    std::vector<std::unordered_map<std::string, PrivateDataValue>> privateCommandData_;

    std::mutex sysPanelStatusLock_;
    SysPanelStatus sysPanelStatus_ { InputType::NONE, 0, 0, 0 } ;
    
    std::mutex isSysPanelSupportMutex_;
    std::atomic<int32_t> isSysPanelSupport_ = 0;
    
    bool IsDisplayChanged(uint64_t oldDisplayId, uint64_t newDisplayId);
    std::function<void(Rosen::DisplayId displayId)> configurationUpdate_;
};
} // namespace MiscServices
} // namespace OHOS
#endif // FRAMEWORKS_INPUTMETHOD_ABILITY_INCLUDE_INPUT_METHOD_ABILITY_H