/*---------------------------------------------------------------------------*/
/* webcam.h                                                                  */
/* copyright (c) innovaphone 2018                                            */
/*                                                                           */
/*---------------------------------------------------------------------------*/

class WebcamActive : public istd::listElement<WebcamActive>
{
public:
    WebcamActive(class Webcam * const webcam) {
        this->webcam = webcam;
        this->context = NULL;
        this->outputFormat = NULL;
        this->started = 0;
    }
    ~WebcamActive() {
        if(this->outputFormat) free(this->outputFormat);
    };

    void * context;
    class Webcam * webcam;
    struct VideoFrameFormat * outputFormat;
    int started;
};

class WebcamProviderClose {};

class Webcam : public IWebcam, public istd::listElement<class Webcam>,
    public WebcamProviderClose
{
    friend class WebcamProvider;

    class IInstanceLog * const log;
    class UWebcam * const webcamUser;
    class WebcamProvider * const provider;

    char * id;
    bool facingFront;
    int orientation;

    int width;
    int height;
    unsigned int defStride;
    int selectedStream;
    unsigned int sampleSize;
    unsigned int avgBitrate;

    enum MediaType type;
    bool shutDown;
    char * utf8FriendlyName;

    int numOutputFormats;
    bool webCamLost;

    void * context;
    struct VideoFrameFormat outputFormat;

public:
    Webcam(class WebcamProvider * const provider, class UWebcam * const webcamUser, void * context, class IInstanceLog * const log);
    ~Webcam();

    // IWebcam
    struct VideoFrameFormat * Start(int width, int height, bool hdVideo) override;
    void Stop() override;
    void Close() override;
    const char * GetWebcamId() override { return this->id; };
    unsigned GetWebcamCapabilities() override { return this->facingFront ? WEBCAM_CAPABILITY_FACING_FRONT : 0; };
    const char * GetWebcamName() override { return this->utf8FriendlyName; };
    void * GetContext() override { return this->context; };
    void FullIntraRequest();

    bool Initialize(const char * id, bool facingFront, int orientation, const char * description);
};

class WebcamProvider : public IWebcamProvider, public istd::listElement<class WebcamProvider>,
    public UIoExecSubclass<WebcamProviderClose>
{
    friend class Webcam;

    class IIoMux * const iomux;
    class UWebcam * const webcamUser;
    class UWebcamProvider * const webcamProviderUser;
    class IInstanceLog * const log;

    void SetExec(IIoMux * iomux, UIoExecSubclass<WebcamProviderClose> * ioContext, WebcamProviderClose * execContext) { iomux->SetExec(ioContext, execContext); };
    void IoExec(WebcamProviderClose * context);

    istd::list<class WebcamActive> webcams;

    bool queryDevicesPending;
    void * queryDevicesContext;

    bool shutDown;
    int execCnt;

public:
    WebcamProvider(class IIoMux * const iomux, class UWebcamProvider * const webcamProviderUser, class UWebcam * const webcamUser, class IInstanceLog * const log);
    ~WebcamProvider();

    //IWebcamProvider
    void QueryDevices(void * context) override;
    void Close() override;

    void WebcamAdded(const char * id, bool facing_front, int orientation, void * context, const char * description);
    void WebcamRemoved(const char * id);
    void WebcamQueryResult(void * context);
    void WebcamFailed(const char * id, void * context);
    void WebcamSample(const char * id, dword timestamp, int length, const byte *data, const struct VideoFrameFormat * format);
};
