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

class RingtoneItem : public istd::listElement<RingtoneItem> {
public:
    RingtoneItem(const char * ident, const char * title, bool remote = false) {
        this->ident = _strdup(ident);
        this->title = _strdup(title);
        this->wasRemoved = false;
        this->isSelected = false;
        this->isRemote = remote;
    }
    ~RingtoneItem() {
        if (this->ident) free(this->ident);
        if (this->title) free(this->title);
    }
    char * title;
    char * ident;
    bool wasRemoved;
    bool isSelected;
    bool isRemote;
};

class RingerDeviceItem : public istd::listElement<RingerDeviceItem> {
public:
    RingerDeviceItem(const char * deviceId, enum RingerDeviceType type, unsigned int capabilities, const char * name, bool remote = false) {
        this->deviceId = _strdup(deviceId);
        this->name = _strdup(name);
        this->wasRemoved = false;
        this->isSelected = false;
        this->type = type;
        this->capabilities = capabilities;
        this->isRemote = remote;
    }
    ~RingerDeviceItem() {
        if (this->deviceId) free(this->deviceId);
        if (this->name) free(this->name);
    }
    char * deviceId;
    char* name;
    enum RingerDeviceType type;
    unsigned int capabilities;
    bool wasRemoved;
    bool isSelected;
    bool isRemote;
};

class RingerIoClose {};

class RingerIo : public IRingerIo, public URinger,
    public UIoExecSubclass<RingerIoClose>
{
    void SetExec(IIoMux * iomux, UIoExecSubclass<RingerIoClose> * ioContext, RingerIoClose * execContext) { iomux->SetExec(ioContext, execContext); };
    void IoExec(RingerIoClose * context);

    class IIoMux * iomux;
    class IRinger * ringer;
    class URingerIo * user;
    class UDeviceIo * deviceIoUser;
    class URingtone * ringtoneUser;
    class IInstanceLog * log;
    class USelectDeviceIo * selectDeviceUser;
    class MediaConfiguration* mediaConfiguration;

    int execCnt;
    bool shutDown;

    class RingerDeviceItem * FindRingerDevice(const char * deviceId);
    istd::list<class RingerDeviceItem> devicesList;

    class RingtoneItem * FindRingtone(const char * ident, const char * title, bool checkTitle);
    istd::list<class RingtoneItem> ringtonesList;

    class RingtoneItem * FindNotificationTone(const char * ident, const char * title);
    istd::list<class RingtoneItem> notificationToneList;

    istd::list<class SelectedDeviceIo> selectedDevices;
    istd::list<class SelectedDeviceIo> selectedRingtones;

    class SelectedDeviceIo * FindRingtone(const char * app);

    void ReadSelectedDevices();
    void ReadSelectedRingtones();
    void WriteSelectedDevices();
    void WriteSelectedRingtones();
    char * softphoneApp;
    bool selectedDeviceRemoved;
    bool selectedRingtoneRemoved;

    istd::list<class UDeviceIoHelper> remoteDeviceUsers;
    istd::list<class URingtoneHelper> remoteRingtoneUsers;

public:
    RingerIo(class IIoMux * const iomux, class IRinger * const ringer, class IInstanceLog * log, class MediaConfiguration* mediaConfiguration);
    ~RingerIo();

    void Initialize(class URingerIo * const user, class UDeviceIo * const deviceUser, class URingtone* const ringtoneUser) override;

    // IRingerIo methods
    void QueryDevices(void * context) override;
    void CleanRemoteDevices() override;
    void SelectDevice(const char * app, const char * device) override;
    const char * GetDeviceIo(const char * app) override;
    const char * StartDevice(void * context, void * src, const char *deviceId, int deviceMode) override { return NULL; }
    void StopDevice(void * context, const char *deviceId) override {};
    void SelectRingtone(const char *app, const char *ringtone) override;
    const char * GetRingtone(const char *app) override;
    void AddRemoteUDeviceIoUser(UDeviceIo* user) override {
        if (!remoteDeviceUsers.empty()) {
            class UDeviceIoHelper* h = remoteDeviceUsers.front();
            while (h) {
                if (h->user == user) return;
                h = h->goNext();
            }
        }
        remoteDeviceUsers.push_back(new class UDeviceIoHelper(user));
    };
    void RemoveRemoteUDeviceIoUser(UDeviceIo* user) override {
        if (!remoteDeviceUsers.empty()) {
            class UDeviceIoHelper* h = remoteDeviceUsers.front();
            while (h) {
                if (h->user == user) {
                    h->remove();
                    delete h;
                    return;
                }
                h = h->goNext();
            }
        }
    };

    void AddRemoteURingtoneUser(URingtone* user) override {
        if (!remoteRingtoneUsers.empty()) {
            class URingtoneHelper* h = remoteRingtoneUsers.front();
            while (h) {
                if (h->user == user) return;
                h = h->goNext();
            }
        }
        remoteRingtoneUsers.push_back(new class URingtoneHelper(user));
    };
    void RemoveRemoteURingtoneUser(URingtone* user) override {
        if (!remoteRingtoneUsers.empty()) {
            class URingtoneHelper* h = remoteRingtoneUsers.front();
            while (h) {
                if (h->user == user) {
                    h->remove();
                    delete h;
                    return;
                }
                h = h->goNext();
            }
        }
    };

    void QueryRingtones(void * context) override;
    void RingtoneStart(const char *deviceId, int deviceMode, const char *ident) override;
    void RingtoneStop(const char *deviceId) override;

    void QueryNotificationTones(void * context) override;
    void NotificationTonePlay(const char *deviceId, int deviceMode, const char *ident) override;

    void SetUSelectDeviceIoUser(USelectDeviceIo* user) override { this->selectDeviceUser = user; };
    void Close(class URingerIo * user) override;

    // URinger
    void RingerDeviceList(void * context) override;
    void RingtoneList(void * context) override;
    void NotificationToneList(void * context) override;
    void CloseRingerComplete() override;

    void RemoteMediaIoDeviceAdded(const char* deviceId, int deviceType, unsigned deviceCapabilities, const char* deviceName, bool selected = false) override;
    void RemoteMediaIoDeviceRemoved(const char* deviceId) override;
    void RemoteMediaIoQueryDevicesResult() override;

    void RemoteRingerIoRingtoneAdded(const char* ident, const char* title, bool selected) override;
    void RemoteRingerIoRingtoneRemoved(const char* ident, const char* title) override;
    void RemoteRingerIoQueryRingtonesResult() override;

    void RemoteRingerIoNotificationToneAdded(const char* ident, const char* title, bool selected) override;
    void RemoteRingerIoNotificationToneRemoved(const char* ident, const char* title) override;
    void RemoteRingerIoQueryNotificationTonesResult() override;

};


