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

enum MessageMouseType {
    LBUTTONDOWN = 0,
    LBUTTONUP,
    LBUTTONDOWNDBLCLK,
    RBUTTONDOWN,
    RBUTTONUP,
    RBUTTONDOWNDBLCLK,
    XBUTTON1DOWN,
    XBUTTON1UP,
    XBUTTON2DOWN,
    XBUTTON2UP,
    MOUSEMOVE,
    MOUSEWHEEL,
    KEYPRESSED,
    KEYPRESSED_DOWN,
    KEYPRESSED_DOWN_UP,
    KEYPRESSED_UP,
    STOP_HOOK
};

#define REMOTE_CONTROL_MSG_TYPE   0
#define REMOTE_CONTROL_X_COOR     1
#define REMOTE_CONTROL_Y_COOR     3
#define REMOTE_CONTROL_X_DIM      5
#define REMOTE_CONTROL_Y_DIM      9
#define REMOTE_CONTROL_VK        13
#define REMOTE_CONTROL_UNICODE   15
#define REMOTE_CONTROL_UNICODE_1 16

enum MouseType {
    Arrow = 0,
    Hand,
    Wait,
    AppStarting,
    Ibeam,
    Cross,
    Help,
    No,
    SizeAll,
    SizeWs,
    SizeNwse,
    SizeWe,
    UpArrow
};

enum CompressionType {
    PNG = 0,
    JPEG,
    PLAIN,
    WEBP,
    MOVE,
    AVIF
};

enum AppSharingAppType {
    MYAPPS_APP = 0,
    REMOTECONTROL_APP,
    REMOTECONTROLPORTABLE_APP
};

#define MAX_SCTP_MTU  1125

#define WEBP_MIN_SIZE  12  // RIFF + FileSize + WEBP
#define JPEG_MIN_SIZE   4
#define PNG_MIN_SIZE   45  // 33 + 12 header + end chunk
#define AVIF_MIN_SIZE 100

static const byte jpegHeader[2] = { 0xFF, 0xD8 };  // JPEG, Start of Image
static const byte pngHeader[8] = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };  // PNG
static const byte pngHeader2[8] = { 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52 }; // IHDR

struct Png_infos {
    char name_png[256];
    int offset_png; //where we stopped last time we read the "file"
    unsigned char *datas_png;
};

typedef struct pixel_ {
    byte blue;
    byte green;
    byte red;
    byte alpha;
} pixel_t;

typedef struct rgb_ {
    byte blue;
    byte green;
    byte red;
} rgb_t;

#define NUM_STANDARD_CURSORS      14
#define NUM_NON_STANDARD_CURSORS  5

enum AppSharingMessages {
    CREATE_SESSION = 0x0,
    CREATE_SESSION_ACK,
    DELETE_SESSION,
    DELETE_SESSION_ACK,
    UPDATE_SESSION,
    UPDATE_SESSION_ACK,
    IMAGE_MESSAGE,
    IMAGE_MESSAGE_ACK,
    MOUSE_CURSOR,
    MOUSE_MOVE,
    INFO_MESSAGE,
    INFO_MESSAGE_ACK,
    LOW_QUALITY_IMAGE_MESSAGE,
    DELETE_IMAGE_MESSAGE,
    DELETE_IMAGE_MESSAGE_ACK,
    INFO_KEYBOARD_MESSAGE,
    INFO_KEYBOARD_MESSAGE_ACK,
    MOUSE_TYPE_CHANGED,
    CLIPBOARD_UPDATE,
    CLIPBOARD_UPDATE_ACK,
    RCP_IMAGE_MESSAGE = 64,
    RCP_MULTI_IMAGE_MESSAGE,
    RCP_CREATE_SESSION,
    RCP_CREATE_SESSION_ACK
};

enum AppSharingInfoMessages {
    ADD_PARTICIPANT = 0,
    REMOVE_PARTICIPANT,
    GIVE_CONTROL,
    TAKE_CONTROL,
    REQUEST_CONTROL,
    KEYBOARD,
    MOUSE,
    INFO_KEYBOARD_MESSAGE_SEQ,
    RCP_NEW_PICTURE = 64,
    RCP_LOST_SEQUENCE,
    RCP_FULL_SCREEN_MODE,
    RCP_PREVIEW_MODE,
    RCP_INFO_KEYBOARD_MESSAGE_LOST,
    RCP_IGNORE_INFO_MESSAGE_SEQ,
    RCP_IGNORE_INFO_KEYBOARD_MESSAGE_SEQ
};

enum MOUSE_KEY {
    MOUSE_LEFT = 0,
    MOUSE_RIGHT,
    MOUSE_CENTER,
    MOUSE_TAB0,
    MOUSE_TAB1,
    MOUSE_XB1,
    MOUSE_XB2
};

class UImageBuffer {
public:
    virtual void Add(unsigned int id, const char * name, const char * description, const char * hwId, const char * icon,  const char * thumbnail, void * handle, bool isDesktop = false) {};
    virtual void Update(unsigned int id, const char * name, const char * description, const char * hwId, const char * icon,  const char * thumbnail) {};
    virtual void Remove(unsigned int id) {};
    virtual void ReloadApplicationList() {};
    virtual void MousePosition(int coorX, int coorY, int type, unsigned int appId) {};
    virtual void UpdateResolution(int dimX, int dimY, unsigned int appId) {};
    virtual void CloseComplete() {};
    virtual void ClipboardUpdate(const char * clipboard, int len) {};
    virtual void ImageBufferSample(unsigned int appId, const void* buf, int len, int width, int height, dword timestamp, dword duration) {};
    virtual void HasEncodedBlocks(int appId) {};
    virtual void IsSecureDesktop(bool secure) {};
    virtual void ForceSendData(int appId) {};
};


class IImageBuffer {
public:
    static IImageBuffer * CreateImageBuffer(class IIoMux * const iomux, class UImageBuffer * const user, class IInstanceLog * const log, class MediaConfiguration * mediaConfiguration);

    virtual ~IImageBuffer() {};
    virtual void Capture(unsigned int appId, class IScreenBuffer * screenBuffer, int coder = 192) = 0;  // MakeCapture, CreateDiffBlocks and CompressDiffBlocks
    virtual class IImage* GetImageBlock(unsigned int appId) { return NULL; };

    virtual bool Mark(unsigned int appId, int coorX, int coorY, int dimX, int dimY) = 0;
    virtual void Clean(unsigned int appId) = 0;
    virtual bool GetWindowPosition(byte appId, word * x, word * y, int * aspectRatio) = 0;
    virtual void RequestNewImage(unsigned int appId) {};

    virtual void SubscribeApplications() = 0;
    virtual void UnsubscribeApplications(void) = 0;

    virtual void CloseImageBuffer(void) = 0;
    virtual void ForceCapture(byte appId) {};

    virtual void ClipboardUpdate(const byte* clipboard, int len, bool ignoreUpdate) {};
    virtual void RegisterForClipboardUpdates() {};

    virtual void SetMouseAspectRation(int aspectRatio) {};
    virtual void MouseWheel(int delta) {};
    virtual void MouseButtonDown(enum MOUSE_KEY key) {};
    virtual void MouseButtonUp(enum MOUSE_KEY key) {};
};

class IImage {
public:
    IImage(unsigned char *buf, int len) {
        this->buf = buf;
        this->len = len;
        this->version = 0;
        this->update = 0;
        this->movePosX = 0;
        this->movePosY = 0;
        this->posX = 0;
        this->posY = 0;
        this->dimX = 128;
        this->dimY = 128;
        this->type = CompressionType::JPEG;
        this->picId = 0;
        this->first = false;
        this->last = false;
        this->numEqual = 0;
        this->ref = 0;
        this->id = 0;
        this->moveBlocks = false;
        this->doNotRedraw = false;
    };
    ~IImage() { if(this->buf) free(this->buf); };

    int x;
    int y;
    int movePosX;
    int movePosY;
    int posX;
    int posY;
    int dimX;
    int dimY;
    int version;
    int update;
    CompressionType type;
    unsigned char *buf;
    int len;
    word picId;
    bool first;
    bool last;
    int numEqual;
    int ref;
    int id;
    bool moveBlocks;
    bool doNotRedraw;
};

class ILowQualityImage {
public:
    ILowQualityImage(unsigned char *buf, int len) {
        this->buf = buf;
        this->len = len;
        this->type = CompressionType::JPEG;
    };
    ~ILowQualityImage() { if(this->buf) free(this->buf); };

    CompressionType type;
    unsigned char *buf;
    int len;
};

#define MAX_X_BLOCKS 30
#define MAX_Y_BLOCKS 17

class IScreenBuffer {
public:
    static IScreenBuffer * Create(class IInstanceLog * const log);
    virtual ~IScreenBuffer() {}

    // Stores a new version of a block or an update of an existing block
    // Called by an image source (capture, unreliable network transmission)
    // Drop blocks and updates with an older version
    // Queue updates that need the block with the right version or previous updates
    // Only trigger calls in IScreenSink for the consistent part of the current block
    //virtual void Set(byte x, byte y, class IImage * image, byte version, byte update) = 0;
    virtual void Set(class IImage * image) = 0;
    virtual void Set(class ILowQualityImage * image) = 0;

    // Returns the number of updates of the specified block
    // Called by IScreenSink to get the image for displaying or network transmission
    virtual byte GetNumUpdates(byte x, byte y) = 0;

    // Returns the current version of the specified block
    // Called by IScreenSink to get the image for displaying or network transmission
    virtual class IImage * Get(byte x, byte y) = 0;
    virtual class ILowQualityImage * GetLowQuality() = 0;

    // Returns the specified update of the specified block
    // Called by IScreenSink to get the image for displaying or network transmission
    virtual class IImage * GetUpdate(byte x, byte y, byte update) = 0;

    virtual void RegisterScreenSink(class IScreenSink * sink) = 0;
    virtual void UnregisterScreenSink(class IScreenSink * sink) = 0;

    virtual void UpdateAppResolution(int w, int h) = 0;

    // Clear ScreenBuffer. 
    // LowQualityImage arrived
    virtual void Clear() = 0;
};

class IScreenSink {
public:
    static IScreenSink * Create(class IIoMux * const iomux, class UScreenSink * const user, class IScreenBuffer * const screenBuffer, byte sessionId, int bitrate, int waitingMsForAck, const char * appName, const char * appDesc, const char * senderName, class IInstanceLog * const log);
    virtual ~IScreenSink() {}

    // Notification that a new version of a block is ready for displaying / transmission
    // Senders should mark this block version in the local state
    virtual void ImageAdded(byte x, byte y, byte version) {};
    virtual void LowQualityImageAdded() {};

    // Notification that a new update of a block is ready for displaying / transmission
    // Senders should mark this update in the local state
    virtual void ImageUpdated(byte x, byte y, byte update) {};

    virtual void UpdateAppResolution(int w, int h) {};

    virtual void Recv(void * buf, int len) {};
    virtual void RecvAck(unsigned num) {};

    virtual void Stop() {};
};

class UScreenSink {
public:
    virtual void SendSinkMessage(void * buf, size_t len, unsigned num) = 0;
    virtual void ReceiveMessage(void * buf, size_t len) = 0;
    virtual void ReportBlockLost(int appId, int posX, int posY, int dimX, int dimY) {};
    virtual void RequestNewImage(int appId) {};
};

class IRemoteControl {
public:
    static IRemoteControl * Create(class IIoMux * const iomux, class URemoteControl * const user, class IInstanceLog * const log, AppSharingAppType appType = AppSharingAppType::MYAPPS_APP);
    virtual ~IRemoteControl() {}

    virtual void SendCommand(word coorX, word coorY, int aspectRatio, const char * cmd, int len) = 0;
    virtual void MouseMove(word coorX, word coorY, word rPosX, word rPosY, word posX, word posY, int aspectRatio) = 0;
    virtual void Close() = 0;
    virtual void IsSecureDesktop(bool secure) {};
    virtual void StartAdminCapture() {};
};

class URemoteControl {
public:
    virtual void MouseWheel(int delta) {};
    virtual void MouseButtonDown(enum MOUSE_KEY key) {};
    virtual void MouseButtonUp(enum MOUSE_KEY key) {};
    virtual void RemoteControlCloseComplete() = 0;
};
