/**
 * xrdp: A Remote Desktop Protocol server.
 *
 * Copyright (C) Jay Sorg 2004-2012
 *
 * 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.
 *
 * freerdp wrapper
 */

#include "xrdp-freerdp.h"
#include "xrdp-color.h"

#define GET_MOD(_inst) ((struct mod*)((_inst)->param1))
#define SET_MOD(_inst, _mod) ((_inst)->param1) = _mod

struct my_bitmap
{
    char *data;
    int width;
    int height;
    int bpp;
};

struct my_cursor
{
    char *andmask;
    int andbpp;
    char *xormask;
    int xorbpp;
    int width;
    int height;
    int hotx;
    int hoty;
};

/*****************************************************************************/
/* return error */
static int DEFAULT_CC
lib_mod_start(struct mod *mod, int w, int h, int bpp)
{
    LIB_DEBUG(mod, "in lib_mod_start");
    g_writeln("lib_mod_start: w %d h %d bpp %d", w, h, bpp);
    mod->width = w;
    mod->height = h;
    mod->bpp = bpp;

    if (bpp == 24)
    {
        mod->settings->server_depth = 32;
    }
    else
    {
        mod->settings->server_depth = mod->bpp;
    }

    mod->settings->width = mod->width;
    mod->settings->height = mod->height;
    LIB_DEBUG(mod, "out lib_mod_start");
    return 0;
}

/******************************************************************************/
/* return error */
static int DEFAULT_CC
lib_mod_connect(struct mod *mod)
{
    int code;

    LIB_DEBUG(mod, "in lib_mod_connect");
    code = mod->inst->rdp_connect(mod->inst);
    g_writeln("lib_mod_connect: code %d", code);
    LIB_DEBUG(mod, "out lib_mod_connect");
    return code;
}

/******************************************************************************/
/* return error */
static int DEFAULT_CC
lib_mod_event(struct mod *mod, int msg, long param1, long param2,
              long param3, long param4)
{
    LIB_DEBUG(mod, "in lib_mod_event");
    int ext;

    //g_writeln("%d %d %d %d %d", msg, param1, param2, param3, param4);
    switch (msg)
    {
        case 15:
            ext = param4 & 0x100 ? 1 : 0;
            mod->inst->rdp_send_input_scancode(mod->inst, 0, ext, param3);
            break;
        case 16:
            ext = param4 & 0x100 ? 1 : 0;
            mod->inst->rdp_send_input_scancode(mod->inst, 1, ext, param3);
            break;
        case 17:
            mod->inst->rdp_sync_input(mod->inst, param4);
            break;
        case 100:
            mod->inst->rdp_send_input_mouse(mod->inst, PTRFLAGS_MOVE,
                                            param1, param2);
            break;
        case 101:
            mod->inst->rdp_send_input_mouse(mod->inst, PTRFLAGS_BUTTON1,
                                            param1, param2);
            break;
        case 102:
            mod->inst->rdp_send_input_mouse(mod->inst,
                                            PTRFLAGS_BUTTON1 | PTRFLAGS_DOWN,
                                            param1, param2);
            break;
        case 103:
            mod->inst->rdp_send_input_mouse(mod->inst,
                                            PTRFLAGS_BUTTON2, param1, param2);
            break;
        case 104:
            mod->inst->rdp_send_input_mouse(mod->inst,
                                            PTRFLAGS_BUTTON2 | PTRFLAGS_DOWN,
                                            param1, param2);
            break;
        case 105:
            mod->inst->rdp_send_input_mouse(mod->inst,
                                            PTRFLAGS_BUTTON3, param1, param2);
            break;
        case 106:
            mod->inst->rdp_send_input_mouse(mod->inst,
                                            PTRFLAGS_BUTTON3 | PTRFLAGS_DOWN,
                                            param1, param2);
            break;
        case 107:
            mod->inst->rdp_send_input_mouse(mod->inst,
                                            PTRFLAGS_WHEEL | 0x0078, 0, 0);
            break;
        case 108:
            break;
        case 109:
            mod->inst->rdp_send_input_mouse(mod->inst,
                                            PTRFLAGS_WHEEL |
                                            PTRFLAGS_WHEEL_NEGATIVE | 0x0088, 0, 0);
            break;
        case 110:
            break;
    }

    LIB_DEBUG(mod, "out lib_mod_event");
    return 0;
}

/******************************************************************************/
/* return error */
static int DEFAULT_CC
lib_mod_signal(struct mod *mod)
{
    LIB_DEBUG(mod, "in lib_mod_signal");
    g_writeln("lib_mod_signal:");
    LIB_DEBUG(mod, "out lib_mod_signal");
    return 0;
}

/******************************************************************************/
/* return error */
static int DEFAULT_CC
lib_mod_end(struct mod *mod)
{
    g_writeln("lib_mod_end:");
    return 0;
}

/******************************************************************************/
/* return error */
static int DEFAULT_CC
lib_mod_set_param(struct mod *mod, char *name, char *value)
{
    g_writeln("lib_mod_set_param: name [%s] value [%s]", name, value);

    if (g_strcmp(name, "hostname") == 0)
    {
        g_strncpy(mod->settings->hostname, value, sizeof(mod->settings->hostname));
    }
    else if (g_strcmp(name, "ip") == 0)
    {
        g_strncpy(mod->settings->server, value, sizeof(mod->settings->server));
    }
    else if (g_strcmp(name, "port") == 0)
    {
        mod->settings->tcp_port_rdp = g_atoi(value);
    }
    else if (g_strcmp(name, "keylayout") == 0)
    {
        mod->settings->keyboard_layout = g_atoi(value);
    }
    else if (g_strcmp(name, "name") == 0)
    {
    }
    else if (g_strcmp(name, "lib") == 0)
    {
    }
    else
    {
        g_writeln("lib_mod_set_param: unknown name [%s] value [%s]", name, value);
    }

    return 0;
}

/******************************************************************************/
static int DEFAULT_CC
mod_session_change(struct mod *v, int a, int b)
{
    g_writeln("mod_session_change:");
    return 0;
}

/******************************************************************************/
static int DEFAULT_CC
mod_get_wait_objs(struct mod *v, tbus *read_objs, int *rcount,
                  tbus *write_objs, int *wcount, int *timeout)
{
    void **rfds;
    void **wfds;

    rfds = (void **)read_objs;
    wfds = (void **)write_objs;
    return v->inst->rdp_get_fds(v->inst, rfds, rcount, wfds, wcount);
}

/******************************************************************************/
static int DEFAULT_CC
mod_check_wait_objs(struct mod *v)
{
    return v->inst->rdp_check_fds(v->inst);
}

/******************************************************************************/
static void DEFAULT_CC
ui_error(rdpInst *inst, const char *text)
{
    g_writeln("ui_error: %s", text);
}

/******************************************************************************/
static void DEFAULT_CC
ui_warning(rdpInst *inst, const char *text)
{
    g_writeln("ui_warning: %s", text);
}

/******************************************************************************/
static void DEFAULT_CC
ui_unimpl(rdpInst *inst, const char *text)
{
    g_writeln("ui_unimpl: %s", text);
}

/******************************************************************************/
static void DEFAULT_CC
ui_begin_update(rdpInst *inst)
{
    struct mod *mod;

    mod = GET_MOD(inst);
    mod->server_begin_update(mod);
}

/******************************************************************************/
static void DEFAULT_CC
ui_end_update(rdpInst *inst)
{
    struct mod *mod;

    mod = GET_MOD(inst);
    mod->server_end_update(mod);
}

/******************************************************************************/
static void DEFAULT_CC
ui_desktop_save(rdpInst *inst, int offset, int x, int y,
                int cx, int cy)
{
    g_writeln("ui_desktop_save:");
}

/******************************************************************************/
static void DEFAULT_CC
ui_desktop_restore(rdpInst *inst, int offset, int x, int y,
                   int cx, int cy)
{
    g_writeln("ui_desktop_restore:");
}

/******************************************************************************/
static RD_HBITMAP DEFAULT_CC
ui_create_bitmap(rdpInst *inst, int width, int height, uint8 *data)
{
    struct my_bitmap *bm;
    struct mod *mod;
    int size;
    int bpp;
    char *bmpdata;

    mod = GET_MOD(inst);
    bpp = mod->bpp == 24 ? 32 : mod->bpp;
    bm = (struct my_bitmap *)g_malloc(sizeof(struct my_bitmap), 1);
    bm->width = width;
    bm->height = height;
    bm->bpp = bpp;
    bmpdata = convert_bitmap(mod->settings->server_depth, bpp,
                             data, width, height, mod->cmap);

    if (bmpdata == (char *)data)
    {
        size = width * height * ((bpp + 7) / 8);
        bm->data = (char *)g_malloc(size, 0);
        g_memcpy(bm->data, bmpdata, size);
    }
    else
    {
        bm->data = bmpdata;
    }

    return bm;
}

/******************************************************************************/
static void DEFAULT_CC
ui_paint_bitmap(rdpInst *inst, int x, int y, int cx, int cy, int width,
                int height, uint8 *data)
{
    struct mod *mod;
    char *bmpdata;

    mod = GET_MOD(inst);
    bmpdata = convert_bitmap(mod->settings->server_depth, mod->bpp,
                             data, width, height, mod->cmap);

    if (bmpdata != 0)
    {
        mod->server_paint_rect(mod, x, y, cx, cy, bmpdata, width, height, 0, 0);
    }

    if (bmpdata != (char *)data)
    {
        g_free(bmpdata);
    }
}

/******************************************************************************/
static void DEFAULT_CC
ui_destroy_bitmap(rdpInst *inst, RD_HBITMAP bmp)
{
    struct my_bitmap *bm;

    bm = (struct my_bitmap *)bmp;
    g_free(bm->data);
    g_free(bm);
}

/******************************************************************************/
static void DEFAULT_CC
ui_line(rdpInst *inst, uint8 opcode, int startx, int starty, int endx,
        int endy, RD_PEN *pen)
{
    g_writeln("ui_line:");
}

/******************************************************************************/
static void DEFAULT_CC
ui_rect(rdpInst *inst, int x, int y, int cx, int cy, uint32 color)
{
    struct mod *mod;

    mod = GET_MOD(inst);
    color = convert_color(mod->settings->server_depth, mod->bpp,
                          color, mod->cmap);
    mod->server_set_fgcolor(mod, color);
    mod->server_fill_rect(mod, x, y, cx, cy);
}

/******************************************************************************/
static void DEFAULT_CC
ui_polygon(rdpInst *inst, uint8 opcode, uint8 fillmode, RD_POINT *point,
           int npoints, RD_BRUSH *brush, uint32 bgcolor, uint32 fgcolor)
{
    g_writeln("ui_polygon:");
}

/******************************************************************************/
static void DEFAULT_CC
ui_polyline(rdpInst *inst, uint8 opcode, RD_POINT *points, int npoints,
            RD_PEN *pen)
{
    g_writeln("ui_polyline:");
}

/******************************************************************************/
static void DEFAULT_CC
ui_ellipse(rdpInst *inst, uint8 opcode, uint8 fillmode, int x, int y,
           int cx, int cy, RD_BRUSH *brush, uint32 bgcolor, uint32 fgcolor)
{
    g_writeln("ui_ellipse:");
}

/******************************************************************************/
static void DEFAULT_CC
ui_add_char(rdpInst *inst, uint8 font, uint16 character, sint16 offset,
            sint16 baseline, uint16 width, uint16 height, uint8 *data)
{
    struct mod *mod;

    //g_writeln("ui_add_char:");
    mod = GET_MOD(inst);
    mod->server_add_char(mod, font, character, offset, baseline,
                         width, height, (char *)data);
}

/******************************************************************************/
static void DEFAULT_CC
ui_draw_text(rdpInst *inst, uint8 font, uint8 flags,
             uint8 opcode, int mixmode,
             int x, int y, int clipx, int clipy, int clipcx, int clipcy,
             int boxx, int boxy, int boxcx, int boxcy, RD_BRUSH *brush,
             uint32 bgcolor, uint32 fgcolor, uint8 *text, uint8 length)
{
    struct mod *mod;

    //g_writeln("ui_draw_text: flags %d mixmode %d x %d y %d", flags, mixmode, x, y);
    //g_writeln("%d %d %d %d %d %d %d %d", clipx, clipy, clipcx, clipcy, boxx, boxy, boxcx, boxcy);
    mod = GET_MOD(inst);
    fgcolor = convert_color(mod->settings->server_depth, mod->bpp,
                            fgcolor, mod->cmap);
    mod->server_set_fgcolor(mod, fgcolor);
    bgcolor = convert_color(mod->settings->server_depth, mod->bpp,
                            bgcolor, mod->cmap);
    mod->server_set_bgcolor(mod, bgcolor);
    mod->server_draw_text(mod, font, flags, mixmode,
                          clipx, clipy, clipx + clipcx, clipy + clipcy,
                          boxx, boxy, boxx + boxcx, boxy + boxcy, x, y,
                          (char *)text, length);
}

/******************************************************************************/
static void DEFAULT_CC
ui_start_draw_glyphs(rdpInst *inst, uint32 bgcolor, uint32 fgcolor)
{
    g_writeln("ui_start_draw_glyphs:");
}

/******************************************************************************/
static void DEFAULT_CC
ui_draw_glyph(rdpInst *inst, int x, int y, int cx, int cy,
              RD_HGLYPH glyph)
{
    g_writeln("ui_draw_glyph:");
}

/******************************************************************************/
static void DEFAULT_CC
ui_end_draw_glyphs(rdpInst *inst, int x, int y, int cx, int cy)
{
    g_writeln("ui_end_draw_glyphs:");
}

/******************************************************************************/
static uint32 DEFAULT_CC
ui_get_toggle_keys_state(rdpInst *inst)
{
    g_writeln("ui_get_toggle_keys_state:");
    return 0;
}

/******************************************************************************/
static void DEFAULT_CC
ui_bell(rdpInst *inst)
{
    g_writeln("ui_bell:");
}

/******************************************************************************/
static void DEFAULT_CC
ui_destblt(rdpInst *inst, uint8 opcode, int x, int y, int cx, int cy)
{
    struct mod *mod;

    g_writeln("ui_destblt:");
    mod = GET_MOD(inst);
    mod->server_set_opcode(mod, opcode);
    mod->server_fill_rect(mod, x, y, cx, cy);
    mod->server_set_opcode(mod, 0xcc);
}

/******************************************************************************/
static void DEFAULT_CC
ui_patblt(rdpInst *inst, uint8 opcode, int x, int y, int cx, int cy,
          RD_BRUSH *brush, uint32 bgcolor, uint32 fgcolor)
{
    struct mod *mod;
    uint8 idata[8];
    int index;

    mod = GET_MOD(inst);
    mod->server_set_opcode(mod, opcode);
    fgcolor = convert_color(mod->settings->server_depth, mod->bpp,
                            fgcolor, mod->cmap);
    mod->server_set_fgcolor(mod, fgcolor);
    bgcolor = convert_color(mod->settings->server_depth, mod->bpp,
                            bgcolor, mod->cmap);
    mod->server_set_bgcolor(mod, bgcolor);
    mod->server_set_mixmode(mod, 1);

    if (brush->bd != 0)
    {
        if (brush->bd->color_code == 1) /* 8x8 1 bpp */
        {
            for (index = 0; index < 8; index++)
            {
                idata[index] = ~(brush->bd->data[index]);
            }

            mod->server_set_brush(mod, brush->xorigin, brush->yorigin,
                                  brush->style, idata);
        }
        else
        {
            g_writeln("ui_patblt: error color_code %d", brush->bd->color_code);
        }
    }
    else
    {
        for (index = 0; index < 8; index++)
        {
            idata[index] = ~(brush->pattern[index]);
        }

        mod->server_set_brush(mod, brush->xorigin, brush->yorigin,
                              brush->style, idata);
    }

    mod->server_fill_rect(mod, x, y, cx, cy);
    mod->server_set_opcode(mod, 0xcc);
    mod->server_set_mixmode(mod, 0);
}

/******************************************************************************/
static void DEFAULT_CC
ui_screenblt(rdpInst *inst, uint8 opcode, int x, int y, int cx, int cy,
             int srcx, int srcy)
{
    struct mod *mod;

    mod = GET_MOD(inst);
    mod->server_set_opcode(mod, opcode);
    mod->server_screen_blt(mod, x, y, cx, cy, srcx, srcy);
    mod->server_set_opcode(mod, 0xcc);
}

/******************************************************************************/
static void DEFAULT_CC
ui_memblt(rdpInst *inst, uint8 opcode, int x, int y, int cx, int cy,
          RD_HBITMAP src, int srcx, int srcy)
{
    struct my_bitmap *bitmap;
    struct mod *mod;
    char *bmpdata;

    mod = GET_MOD(inst);
    bitmap = (struct my_bitmap *)src;
    mod->server_set_opcode(mod, opcode);
    mod->server_paint_rect(mod, x, y, cx, cy, bitmap->data,
                           bitmap->width, bitmap->height, srcx, srcy);
    mod->server_set_opcode(mod, 0xcc);
}

/******************************************************************************/
static void DEFAULT_CC
ui_triblt(rdpInst *inst, uint8 opcode, int x, int y, int cx, int cy,
          RD_HBITMAP src, int srcx, int srcy, RD_BRUSH *brush,
          uint32 bgcolor, uint32 fgcolor)
{
    g_writeln("ui_triblt:");
}

/******************************************************************************/
static RD_HGLYPH DEFAULT_CC
ui_create_glyph(rdpInst *inst, int width, int height, uint8 *data)
{
    g_writeln("ui_create_glyph:");
    return 0;
}

/******************************************************************************/
static void DEFAULT_CC
ui_destroy_glyph(rdpInst *inst, RD_HGLYPH glyph)
{
    g_writeln("ui_destroy_glyph:");
}

/******************************************************************************/
static int DEFAULT_CC
ui_select(rdpInst *inst, int rdp_socket)
{
    return 1;
}

/******************************************************************************/
static void DEFAULT_CC
ui_set_clip(rdpInst *inst, int x, int y, int cx, int cy)
{
    struct mod *mod;

    mod = GET_MOD(inst);
    mod->server_set_clip(mod, x, y, cx, cy);
}

/******************************************************************************/
static void DEFAULT_CC
ui_reset_clip(rdpInst *inst)
{
    struct mod *mod;

    mod = GET_MOD(inst);
    mod->server_reset_clip(mod);
}

/******************************************************************************/
static void DEFAULT_CC
ui_resize_window(rdpInst *inst)
{
    g_writeln("ui_resize_window:");
}

/******************************************************************************/
static void DEFAULT_CC
ui_set_cursor(rdpInst *inst, RD_HCURSOR cursor)
{
    struct mod *mod;
    struct my_cursor *cur;

    //g_writeln("ui_set_cursor:");
    mod = GET_MOD(inst);
    cur = (struct my_cursor *)cursor;

    if (cur != 0)
    {
        mod->server_set_cursor(mod, cur->hotx, cur->hoty,
                               cur->xormask, cur->andmask);
    }
    else
    {
        g_writeln("ui_set_cursor: nil cursor");
    }
}

/******************************************************************************/
static void DEFAULT_CC
ui_destroy_cursor(rdpInst *inst, RD_HCURSOR cursor)
{
    struct my_cursor *cur;

    //g_writeln("ui_destroy_cursor:");
    cur = (struct my_cursor *)cursor;

    if (cur != 0)
    {
        g_free(cur->andmask);
        g_free(cur->xormask);
    }

    g_free(cur);
}

#define RGB24(_r, _g, _b)  \
    (_r << 16) | (_g << 8) | _b;

/******************************************************************************/
static int
l_get_pixel(tui8 *data, int x, int y, int width, int height, int bpp)
{
    int start;
    int shift;
    tui16 *src16;
    tui32 *src32;
    int red, green, blue;

    switch (bpp)
    {
        case 1:
            width = (width + 7) / 8;
            start = (y * width) + x / 8;
            shift = x % 8;
            return (data[start] & (0x80 >> shift)) != 0;
        case 8:
            return data[y * width + x];
        case 15:
        case 16:
            src16 = (uint16 *) data;
            return src16[y * width + x];
        case 24:
            data += y * width * 3;
            data += x * 3;
            red = data[0];
            green = data[1];
            blue = data[2];
            return RGB24(red, green, blue);
        case 32:
            src32 = (uint32 *) data;
            return src32[y * width + x];
        default:
            g_writeln("l_get_pixel: unknown bpp %d", bpp);
            break;
    }

    return 0;
}

/******************************************************************************/
static void
l_set_pixel(tui8 *data, int x, int y, int width, int height,
            int bpp, int pixel)
{
    int start;
    int shift;
    int *dst32;
    tui8 *dst8;

    if (bpp == 1)
    {
        width = (width + 7) / 8;
        start = (y * width) + x / 8;
        shift = x % 8;

        if (pixel)
        {
            data[start] = data[start] | (0x80 >> shift);
        }
        else
        {
            data[start] = data[start] & ~(0x80 >> shift);
        }
    }
    else if (bpp == 24)
    {
        dst8 = data + (y * width + x) * 3;
        *(dst8++) = (pixel >> 16) & 0xff;
        *(dst8++) = (pixel >> 8) & 0xff;
        *(dst8++) = (pixel >> 0) & 0xff;
    }
    else if (bpp == 32)
    {
        dst32 = (int *) data;
        dst32[y * width + x] = pixel;
    }
    else
    {
        g_writeln("l_set_pixel: unknown bpp %d", bpp);
    }
}


/******************************************************************************/
/* andmask = mask = 32 * 32 / 8
   xormask = data = 32 * 32 * 3 */
static RD_HCURSOR DEFAULT_CC
ui_create_cursor(rdpInst *inst, unsigned int x, unsigned int y,
                 int width, int height, uint8 *andmask,
                 uint8 *xormask, int bpp)
{
    struct mod *mod;
    struct my_cursor *cur;
    int i;
    int j;
    int jj;
    int apixel;
    int xpixel;
    char *dst;

    mod = GET_MOD(inst);
    g_writeln("ui_create_cursor: x %d y %d width %d height %d bpp %d",
              x, y, width, height, bpp);
    cur = (struct my_cursor *)g_malloc(sizeof(struct my_cursor), 1);
    cur->width = width;
    cur->height = height;
    cur->hotx = x;
    cur->hoty = y;
    cur->andmask = g_malloc(32 * 32 * 4, 1);
    cur->xormask = g_malloc(32 * 32 * 4, 1);

    for (j = 0; j < height; j++)
    {
        jj = (bpp != 1) ? j : (height - 1) - j;

        for (i = 0; i < width; i++)
        {
            apixel = l_get_pixel(andmask, i, jj, width, height, 1);
            xpixel = l_get_pixel(xormask, i, jj, width, height, bpp);
            xpixel = convert_color(bpp, 24, xpixel, mod->cmap);
            l_set_pixel(cur->andmask, i, j, width, height, 1, apixel);
            l_set_pixel(cur->xormask, i, j, width, height, 24, xpixel);
        }
    }

    return (RD_HCURSOR)cur;
}

/******************************************************************************/
static void DEFAULT_CC
ui_set_null_cursor(rdpInst *inst)
{
    g_writeln("ui_set_null_cursor:");
}

/******************************************************************************/
static void DEFAULT_CC
ui_set_default_cursor(rdpInst *inst)
{
    g_writeln("ui_set_default_cursor:");
}

/******************************************************************************/
static RD_HPALETTE DEFAULT_CC
ui_create_palette(rdpInst *inst, RD_PALETTE *colors)
{
    struct mod *mod;
    int index;
    int red;
    int green;
    int blue;
    int pixel;
    int count;
    int *cmap;

    mod = GET_MOD(inst);
    g_writeln("ui_create_palette:");
    count = 256;

    if (count > colors->count)
    {
        count = colors->count;
    }

    cmap = (int *)g_malloc(256 * 4, 1);

    for (index = 0; index < count; index++)
    {
        red = colors->entries[index].red;
        green = colors->entries[index].green;
        blue = colors->entries[index].blue;
        pixel = COLOR24RGB(red, green, blue);
        cmap[index] = pixel;
    }

    return (RD_HPALETTE)cmap;
}

/******************************************************************************/
static void DEFAULT_CC
ui_move_pointer(rdpInst *inst, int x, int y)
{
    g_writeln("ui_move_pointer:");
}

/******************************************************************************/
static void DEFAULT_CC
ui_set_palette(rdpInst *inst, RD_HPALETTE map)
{
    struct mod *mod;

    mod = GET_MOD(inst);
    g_writeln("ui_set_palette:");
    g_memcpy(mod->cmap, map, 256 * 4);
    g_free(map);
}

/******************************************************************************/
static RD_HBITMAP DEFAULT_CC
ui_create_surface(rdpInst *inst, int width, int height, RD_HBITMAP old)
{
    g_writeln("ui_create_surface:");
    return 0;
}

/******************************************************************************/
static void DEFAULT_CC
ui_set_surface(rdpInst *inst, RD_HBITMAP surface)
{
    g_writeln("ui_set_surface:");
}

/******************************************************************************/
static void DEFAULT_CC
ui_destroy_surface(rdpInst *inst, RD_HBITMAP surface)
{
    g_writeln("ui_destroy_surface:");
}

/******************************************************************************/
static void DEFAULT_CC
ui_channel_data(rdpInst *inst, int chan_id, char *data, int data_size,
                int flags, int total_size)
{
    g_writeln("ui_channel_data:");
}

/******************************************************************************/
static RD_BOOL DEFAULT_CC
ui_authenticate(rdpInst *inst)
{
    return 1;
}

/******************************************************************************/
static int DEFAULT_CC
ui_decode(rdpInst *inst, uint8 *data, int data_size)
{
    return 0;
}

/******************************************************************************/
static RD_BOOL DEFAULT_CC
ui_check_certificate(rdpInst *inst, const char *fingerprint,
                     const char *subject, const char *issuer, RD_BOOL verified)
{
    return 1;
}

/******************************************************************************/
struct mod *EXPORT_CC
mod_init(void)
{
    struct mod *mod;

    //g_writeln("1");
    //freerdp_global_init();
    //g_writeln("2");
    mod = (struct mod *)g_malloc(sizeof(struct mod), 1);
    mod->size = sizeof(struct mod);
    mod->version = CURRENT_MOD_VER;
    mod->handle = (tbus)mod;
    mod->mod_connect = lib_mod_connect;
    mod->mod_start = lib_mod_start;
    mod->mod_event = lib_mod_event;
    mod->mod_signal = lib_mod_signal;
    mod->mod_end = lib_mod_end;
    mod->mod_set_param = lib_mod_set_param;
    mod->mod_session_change = mod_session_change;
    mod->mod_get_wait_objs = mod_get_wait_objs;
    mod->mod_check_wait_objs = mod_check_wait_objs;
    mod->settings = (struct rdp_set *)g_malloc(sizeof(struct rdp_set), 1);

    mod->settings->width = 1280;
    mod->settings->height = 1024;
    mod->settings->encryption = 1;
    mod->settings->rdp_security = 1;
    mod->settings->tls_security = 1;
    mod->settings->server_depth = 16;
    mod->settings->bitmap_cache = 1;
    mod->settings->bitmap_compression = 1;
    mod->settings->performanceflags =
        PERF_DISABLE_WALLPAPER | PERF_DISABLE_FULLWINDOWDRAG | PERF_DISABLE_MENUANIMATIONS;
    mod->settings->new_cursors = 1;
    mod->settings->rdp_version = 5;
    mod->settings->text_flags = 1;

    mod->inst = freerdp_new(mod->settings);

    if (mod->inst == 0)
    {
        return 0;
    }

    SET_MOD(mod->inst, mod);
    mod->inst->ui_error = ui_error;
    mod->inst->ui_warning = ui_warning;
    mod->inst->ui_unimpl = ui_unimpl;
    mod->inst->ui_begin_update = ui_begin_update;
    mod->inst->ui_end_update = ui_end_update;
    mod->inst->ui_desktop_save = ui_desktop_save;
    mod->inst->ui_desktop_restore = ui_desktop_restore;
    mod->inst->ui_create_bitmap = ui_create_bitmap;
    mod->inst->ui_paint_bitmap = ui_paint_bitmap;
    mod->inst->ui_destroy_bitmap = ui_destroy_bitmap;
    mod->inst->ui_line = ui_line;
    mod->inst->ui_rect = ui_rect;
    mod->inst->ui_polygon = ui_polygon;
    mod->inst->ui_polyline = ui_polyline;
    mod->inst->ui_ellipse = ui_ellipse;
    mod->inst->ui_add_char = ui_add_char;
    mod->inst->ui_draw_text = ui_draw_text;
    mod->inst->ui_start_draw_glyphs = ui_start_draw_glyphs;
    mod->inst->ui_draw_glyph = ui_draw_glyph;
    mod->inst->ui_end_draw_glyphs = ui_end_draw_glyphs;
    mod->inst->ui_get_toggle_keys_state = ui_get_toggle_keys_state;
    mod->inst->ui_bell = ui_bell;
    mod->inst->ui_destblt = ui_destblt;
    mod->inst->ui_patblt = ui_patblt;
    mod->inst->ui_screenblt = ui_screenblt;
    mod->inst->ui_memblt = ui_memblt;
    mod->inst->ui_triblt = ui_triblt;
    mod->inst->ui_create_glyph = ui_create_glyph;
    mod->inst->ui_destroy_glyph = ui_destroy_glyph;
    mod->inst->ui_select = ui_select;
    mod->inst->ui_set_clip = ui_set_clip;
    mod->inst->ui_reset_clip = ui_reset_clip;
    mod->inst->ui_resize_window = ui_resize_window;
    mod->inst->ui_set_cursor = ui_set_cursor;
    mod->inst->ui_destroy_cursor = ui_destroy_cursor;
    mod->inst->ui_create_cursor = ui_create_cursor;
    mod->inst->ui_set_null_cursor = ui_set_null_cursor;
    mod->inst->ui_set_default_cursor = ui_set_default_cursor;
    mod->inst->ui_create_palette = ui_create_palette;
    mod->inst->ui_move_pointer = ui_move_pointer;
    mod->inst->ui_set_palette = ui_set_palette;
    mod->inst->ui_create_surface = ui_create_surface;
    mod->inst->ui_set_surface = ui_set_surface;
    mod->inst->ui_destroy_surface = ui_destroy_surface;
    mod->inst->ui_channel_data = ui_channel_data;

    mod->inst->ui_authenticate = ui_authenticate;
    mod->inst->ui_decode = ui_decode;
    mod->inst->ui_check_certificate = ui_check_certificate;

    return mod;
}

/******************************************************************************/
int EXPORT_CC
mod_exit(struct mod *mod)
{
    if (mod == 0)
    {
        return 0;
    }

    freerdp_free(mod->inst);
    g_free(mod->settings);
    g_free(mod);
    //freerdp_global_finish();
    return 0;
}
