/*---------------------------------------------------------------------------*/
/* signalingApp.h                                                            */
/* copyright (c) innovaphone 2021                                            */
/*                                                                           */
/*---------------------------------------------------------------------------*/

class SignalingAppCall : public istd::listElement<SignalingAppCall>
{
public:
    SignalingAppCall(const char*uuid, const char* number, int numOffset, const char* sip, const char * name, const char * diverting, const char * called, bool incoming, int videoMode = 0)
    {
        this->uuid = _strdup(uuid);
        this->number = _strdup(number);
        this->sip = _strdup(sip);
        this->name = _strdup(name);
        this->diverting = _strdup(diverting);
        this->called = _strdup(called);
        this->connected = false;
        this->hold = false;
        this->showIncomingCallUI = false;
        this->incoming = incoming;
        this->videoMode = videoMode;
        this->numOffset = numOffset;
    }
    ~SignalingAppCall() {
        if (this->uuid) free(this->uuid);
        if (this->number) free(this->number);
        if (this->sip) free(this->sip);
        if (this->name) free(this->name);
        if (this->diverting) free(this->diverting);
        if (this->called) free(this->called);
    }

    bool incoming;
    bool connected;
    bool hold;
    bool showIncomingCallUI;
    char * uuid;
    char * number;
    char * sip;
    char * name;
    char * diverting;
    char * called;
    int videoMode;
    int numOffset;
};

class SignalingAppPhoneApps : public istd::listElement<SignalingAppPhoneApps>
{
public:
    SignalingAppPhoneApps(const char * hw, const char * app, const char * title, const char * url)
    {
        this->hw = _strdup(hw);
        this->app = _strdup(app);
        this->title = _strdup(title);
        this->url = _strdup(url);
    }
    ~SignalingAppPhoneApps() {
        if (this->hw) free(this->hw);
        if (this->app) free(this->app);
        if (this->title) free(this->title);
        if (this->url) free(this->url);
    }

    char * hw;
    char * app;
    char * title;
    char * url;
};

class SignalingApiLookupConsumer : public ApiConsumer
{
    class SignalingApp* signaling;

    void ApiConsumerRecv(const char* provider, const char* src, class json_io& msg, word base) override;

public:
    SignalingApiLookupConsumer(class SignalingApp* client);
    ~SignalingApiLookupConsumer();

    void Lookup(const char * src, const char * number, const char * prefixIntl, const char * prefixNtl, const char * prefixExt, const char * country, const char * area, const char * subscriber);
};

class SignalingApiAvatarConsumer : public ApiConsumer
{
    class SignalingApp * client;
    char * url;
    char * base;
    char * domain;
    char * filename;
    char * token;
    char salt[17];

    void ApiConsumerUpdate(class json_io & model, word base) override;

public:
    SignalingApiAvatarConsumer(class SignalingApp * client);
    ~SignalingApiAvatarConsumer();

    char * GetAvatarUrl(const char * sip, const char * dn, const char * domain, const char * appdomain, const char * currentUserSip);
};

class SignalingApiPhoneConsumer : public ApiConsumer
{
    class SignalingApp * signaling;

    void ApiConsumerUpdate(class json_io & model, word base) override;
    void ApiConsumerDefaultProvider(const char * defaultApiProvider) override;

public:
    SignalingApiPhoneConsumer(class SignalingApp * client);
    ~SignalingApiPhoneConsumer();

    void ConfigureSoftphone(const char * appname);
};

class DefaultApiProviderTimer : public ITimer {
public:
    DefaultApiProviderTimer(IIoMux* ioMux, UTimerSubclass<DefaultApiProviderTimer>* owner) : ITimer(ioMux, owner) {};
};

class StartCallTimer : public ITimer {
public:
    StartCallTimer(IIoMux* ioMux, UTimerSubclass<StartCallTimer>* owner) : ITimer(ioMux, owner) {};
};

class SignalingApp : public IShutdownHandler, public IInstanceLog, public USignaling, public ApiWebsocketClient, public UCallKit, public ULauncherApi, public ISignalingApp, public ISignalingConfig, public UNotifications, public URemoteServices, public USearchContact, public UTimerSubclass<DefaultApiProviderTimer>, public UTimerSubclass<StartCallTimer> {
    friend class SignalingApiProvider;
    
    IIoMux * iomux;
    class ISignaling * signaling;
    class IInstanceLog * log;
    bool closing;
    bool closed;
    class ICallKit * callKit;
    class USignalingApp * signalingAppUser;
    class DefaultApiProviderTimer defProviderTimer;
    class StartCallTimer startCallTimer;
    unsigned startCallTime;
    class INotifications * notifications;
    class ULauncherApi * launcherApi;
    class ILauncherApi * iLauncherApi;
    class IRemoteServices * remoteServices;
    class ISearchContact * searchContact;

    char * url;
    char * sec;
    char * phys;
    char * app;
    char * usr;
    char * pwd;
    char * domain;
    char * appdomain;
    unsigned timeout;
    char * hw;
    unsigned hwTimeout;
    char * currentUserSip;
    char * excludeInterfaces;
    bool cxSupported;
    bool registered;
    int uiRunning;
    char * uuidTerminateNotify;
    char * uuidTerminateNotifyConf;
    char * lastMissedCallUuid;
    bool showNotifications;

    int langId;

    char * defaultApiProvider;
    bool defaultApiProviderRemoved;

    class SignalingApiAvatarConsumer * signalingAvatarConsumer;
    class SignalingApiPhoneConsumer * signalingPhoneConsumer;
    class SignalingApiLookupConsumer * signalingLookupConsumer;

    istd::list<class SignalingAppPhoneApps> phoneApps;
    istd::list<class SignalingAppCall> calls;

    char * workingPath;
    bool dnd;

    bool remoteServicesClientConnected;
    bool remoteServicesServerConnected;

    char * windowTitle;
    char * startCallSip;
    char * startCallNum;
    char * startCallName;
    StartCallVideoMode startCallVideoMode;
    bool startCallSendingComplete;

    void TryClose();

    void SignalingClosing(class ISignaling *signaling) override;
    void ClientState(bool up, bool localInit) override;
    void SaveCredentials(const char * url, const char * sec, const char * phys, const char * app, const char * usr, const char * pwd, const char * domain, const char * appdomain, unsigned timeout) override;
    void SaveRegistration(const char* hw, const char* phys, unsigned timeout) override;
    void RegistrationState(bool up) override;
    void UserSession(bool up) override;
    void SetDnd(bool dnd) override;
    void SendEvent(int code, char * error, char * src) override;
    bool UseRemoteClientServices() override { return this->remoteServicesClientConnected; };
    bool UseRemoteServices() override { return this->remoteServicesServerConnected; };
    void SoftphoneAppWindowTitle(const char* title) override;
    void BringWindowToForeground() override;
    bool HasCredentials() override;

    bool IsSoftPhoneStandardApp();

    void SelectRingtone(const char* ringtoneId) override;
    void ReportNewIncomingCall(const char * uuid, const char * number, int numOffset, const char * sip, const char * name, const char * diverting, const char * called,
                               bool hasVideo, bool supportsDTMF, bool supportsHolding, bool supportsGrouping, bool supportsUngrouping) override;
    void ReportCallEnded(const char * uuid, int reason) override;
    void ReportMissedCall(const char * uuid, const char * number, int numOffset, const char * sip, const char * name, int reason) override;
    void ReportCallConnected(const char * uuid, bool connected, const char* number, int numOffset, const char* sip, const char* name, const char* diverting, const char* called,
                             bool hasVideo, bool supportsDTMF, bool supportsHolding, bool supportsGrouping, bool supportsUngrouping) override;
    void ReportCallHold(const char * uuid) override;
    void ReportCallRetrieve(const char * uuid) override;
    void RequestStartCall(const char * uuid, const char * number, const char * name, bool video, bool sendingComplete) override;
    void RequestStartRinging(const char* uuid) override;
    void ReportOutgoingCallAlerting(const char * uuid, const char * name, const char * sip, const char * num, int numOffset) override;
    void ReportNameIdentification(const char* uuid, const char* number, const char* sip, const char* name, const char* diverting, const char* called,
                                  bool hasVideo, bool supportsDTMF, bool supportsHolding, bool supportsGrouping, bool supportsUngrouping) override;
    void Lookup(const char * src, const char * number, const char * prefixIntl, const char * prefixNtl, const char * prefixExt, const char * country, const char * area, const char * subscriber) override;

    void Shutdown() override;
    void ShutdownTimeout() override {};

    void ApiWebsocketClientCloseComplete() override;

    void CxSupported(bool supported) override;
    void CxStartCallAction(const char * uuid, const char * number, const char * name, bool video) override;
    void CxAnswerCallAction(const char * uuid) override;
    void CxEndCallAction(const char * uuid, enum CxCallError callError) override;
    void CxSetHeldCallAction(const char * uuid, bool held) override;
    void CxSetMutedCallAction(const char * uuid, bool muted) override;
    void CxAudioRouteChanged(const char * uuid, const char * deviceId) override;
    void CxSetGroupCallAction(const char * uuid, const char * with) override;
    void CxPlayDTMFCallAction(const char * uuid, const char * digits) override;
    void CxCallError(const char * uuid, enum CxCallError callError) override;
    void CxShowIncomingCallUi(const char * uuid) override;
    void CxCheckIncomingCall(const char * uuid) override;

    void LauncherApiSetLangId(const char* langId) override;

    void SetExcludeInterfaces(const char * excludeInf) override;
    void SetNoVpnAddresses(bool noVpnAddresses) override;
    void SetCurrentUserSip(const char * sip) override;
    void SetRecordingParameters(const char* url, bool forceUrl, bool isRecordingByDefaultOn, bool forceDefaultOn, bool recordExternalOnly, bool forceExternalOnly) override;

    void TimerOnTimeout(DefaultApiProviderTimer* timer) override;
    void TimerOnTimeout(StartCallTimer* timer) override;

    void LocalNotificationClicked(const char* ref, enum LocalNotificationAction action, const char* replyText) override;

    void ReportIncomingCall(const char* uuid, const char* name, const char* sip, const char* num, const char* diverting, const char* called, const char* app, const char* domain, const char* appdomain, bool noAccept);
    void ReportMissedCall(const char* uuid, const char* name, const char* sip, const char* num, int numOffset, const char* diverting, const char* called, const char* app, const char* domain, const char* appdomain);
    void RemoveNotification(const char* ref);
    void NotificationHoldTerminateCall(const char* uuid, const char* name, const char* sip, const char* num, const char* diverting, const char* called, const char* app, const char* domain, const char* appdomain);
    void NotificationTerminateCall(const char* uuid, const char* name, const char* sip, const char* num, const char* diverting, const char* called, const char* app, const char* domain, const char* appdomain);

    void PhoneAnswerCallAction(const char* uuid);
    void PhoneEndCallAction(const char* uuid, int callError);

    bool StartCall(const char* sip, const char* num, const char* dn, StartCallVideoMode videoMode, bool sendingComplete = true) override;

    void ClientConnected() override;
    void ClientDisconnected() override;
    void ServerConnected() override;
    void ServerDisconnected() override;
    void Message(const char* type, class json_io& msg, word base) override {};

    void SearchContactResult(const char* src, class json_io& msg, word base) override;
    void SearchContactCloseResult() override;

public:
    SignalingApp(IIoMux * const iomux, class ULauncherApi* launcherApi, class ILauncherApi* iLauncherApi, class ISocketProvider * localSocketProvider, class ISocketProvider * tcpSocketProvider, class ISocketProvider * tlsSocketProvider, class IDns * dns, class IInstanceLog * const log, class INotifications* notifications, const char * apiRelayUrl, const char * servicePassword, const char * workingPath, const char * apiRelayPath = nullptr, class IRemoteServices* remoteServices = nullptr, class ICallKit * callKit = nullptr, class USignalingApp * signalingAppUser = nullptr);
    virtual ~SignalingApp();

    const char * GetAppName() const { return "SignalingApp"; }
    const char * GetAppDomain() const { return NULL; }

    void SetSignaling(ISignaling *signaling);
    void SetSearchContactProvider(class ISearchContact* searchContact) { this->searchContact = searchContact; };

    char * GetAvatarUrl(const char * sip, const char * dn, const char * domain, const char * appdomain);
    void PhoneAppAvailable(const char * hw, const char * app, const char * title, const char * url);
    void DefaultApiProvider(const char * defaultApiProvider);
    void RegistrationCheck();
    void LookupInfo(const char * src, class json_io& msg, word base);
};
