/* Copyright 2017-present Renesas Electronics Corporation and other contributors
 *
 * 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.
 */

#include "iotjs_def.h"

#if defined(USE_POSIX_BRIDGE)
#include "peripheral_io.h"
#include "iotjs_module_aligned_buffer.h"
#include "iotjs_module_graphics.h"


IOTJS_DEFINE_NATIVE_HANDLE_INFO_THIS_MODULE(graphics);

struct iotjs_graphics_platform_data_s {
  graphics_h handle;
};

jerry_value_t iotjs_graphics_set_platform_config(iotjs_graphics_t* graphics,
                                             const jerry_value_t jconfig) {
  return jerry_create_undefined();
}

void iotjs_graphics_create_platform_data(iotjs_graphics_t* graphics) {
  graphics->platform_data = IOTJS_ALLOC(iotjs_graphics_platform_data_t);
}

void iotjs_graphics_destroy_platform_data(
    iotjs_graphics_platform_data_t* platform_data) {
  IOTJS_RELEASE(platform_data);
}


IOTJS_DEFINE_PERIPH_CREATE_FUNCTION(graphics);

bool iotjs_graphics_init(iotjs_graphics_t* graphics) {
  graphics_h handle = initFrameBuffer(graphics->frame_buffer.addr,
                        graphics->frame_buffer.width,
                        graphics->frame_buffer.height,
                        graphics->frame_buffer.format);
  if( !handle ) {
    return false;
  }
  graphics->platform_data->handle = handle;

  return true;
}

bool iotjs_graphics_draw_image(iotjs_graphics_t* graphics) {
  int ret = drawImage(graphics->platform_data->handle,
                        graphics->shape.image.bitmap,
                        graphics->shape.image.x,
                        graphics->shape.image.y,
                        graphics->shape.image.width,
                        graphics->shape.image.height);
  return (ret == 0);
}

bool iotjs_graphics_draw_line(iotjs_graphics_t* graphics) {
  int ret = drawLine(graphics->platform_data->handle,
                        graphics->shape.line.startX,
                        graphics->shape.line.startY,
                        graphics->shape.line.endX,
                        graphics->shape.line.endY,
                        graphics->shape.line.color);
  return (ret == 0);
}

bool iotjs_graphics_draw_rect(iotjs_graphics_t* graphics) {
  int ret = drawRect(graphics->platform_data->handle,
                        graphics->shape.rect.x,
                        graphics->shape.rect.y,
                        graphics->shape.rect.width,
                        graphics->shape.rect.height,
                        graphics->shape.rect.color,
                        graphics->shape.rect.fill);
  return (ret == 0);
}

bool iotjs_graphics_draw_arc(iotjs_graphics_t* graphics) {
  int ret = drawArc(graphics->platform_data->handle,
                        graphics->shape.arc.centerX,
                        graphics->shape.arc.centerY,
                        graphics->shape.arc.radius,
                        graphics->shape.arc.startAngle,
                        graphics->shape.arc.endAngle,
                        graphics->shape.arc.color);
  return (ret == 0);
}

bool iotjs_graphics_draw_circle(iotjs_graphics_t* graphics) {
  int ret = drawCircle(graphics->platform_data->handle,
                        graphics->shape.circle.centerX,
                        graphics->shape.circle.centerY,
                        graphics->shape.circle.radius,
                        graphics->shape.circle.color,
                        graphics->shape.circle.fill);
  return (ret == 0);
}

bool iotjs_graphics_draw_ellipse(iotjs_graphics_t* graphics) {
  int ret = drawEllipse(graphics->platform_data->handle,
                        graphics->shape.ellipse.centerX,
                        graphics->shape.ellipse.centerY,
                        graphics->shape.ellipse.radiusX,
                        graphics->shape.ellipse.radiusY,
                        graphics->shape.ellipse.color,
                        graphics->shape.ellipse.fill);
  return (ret == 0);
}

bool iotjs_graphics_draw_polygon(iotjs_graphics_t* graphics) {
  int ret = drawPolygon(graphics->platform_data->handle,
                        graphics->shape.polygon.centerX,
                        graphics->shape.polygon.centerY,
                        graphics->shape.polygon.radius,
                        graphics->shape.polygon.sides,
                        graphics->shape.polygon.color,
                        graphics->shape.polygon.fill);
  return (ret == 0);
}

bool iotjs_graphics_draw_text(iotjs_graphics_t* graphics) {
  const char* text = iotjs_string_data( &graphics->shape.text.text );
  int ret = drawText(graphics->platform_data->handle,
                        text,
                        graphics->shape.text.x,
                        graphics->shape.text.y,
                        graphics->shape.text.size,
                        graphics->shape.text.color,
                        graphics->shape.text.background);
  iotjs_string_destroy( &graphics->shape.text.text );
  return (ret == 0);
}

static void iotjs_graphics_destroy(iotjs_graphics_t* graphics) {
  deinitFrameBuffer(graphics->platform_data->handle);
  iotjs_graphics_destroy_platform_data(graphics->platform_data);
  IOTJS_RELEASE(graphics);
}

static void graphics_worker(uv_work_t* work_req) {
  iotjs_periph_reqwrap_t* req_wrap =
      (iotjs_periph_reqwrap_t*)(iotjs_reqwrap_from_request(
          (uv_req_t*)work_req));
  iotjs_graphics_t* graphics = (iotjs_graphics_t*)req_wrap->data;

  switch (req_wrap->op) {
    case kGraphicsOpDrawImage:
      req_wrap->result = iotjs_graphics_draw_image(graphics);
      break;
    case kGraphicsOpDrawLine:
      req_wrap->result = iotjs_graphics_draw_line(graphics);
      break;
    case kGraphicsOpDrawRect:
      req_wrap->result = iotjs_graphics_draw_rect(graphics);
      break;
    case kGraphicsOpDrawArc:
      req_wrap->result = iotjs_graphics_draw_arc(graphics);
      break;
    case kGraphicsOpDrawCircle:
      req_wrap->result = iotjs_graphics_draw_circle(graphics);
      break;
    case kGraphicsOpDrawEllipse:
      req_wrap->result = iotjs_graphics_draw_ellipse(graphics);
      break;
    case kGraphicsOpDrawPolygon:
      req_wrap->result = iotjs_graphics_draw_polygon(graphics);
      break;
    case kGraphicsOpDrawText:
      req_wrap->result = iotjs_graphics_draw_text(graphics);
      break;
    default:
      IOTJS_ASSERT(!"Invalid Operation");
  }
}

static jerry_value_t graphics_set_configuration(iotjs_graphics_t* graphics,
                                            jerry_value_t jconfig) {
  jerry_value_t jbuf = iotjs_jval_get_property(jconfig, "buf");
  if (jerry_value_is_object(jbuf)) {
    iotjs_aligned_buffer_wrap_t* buffer_wrap = iotjs_aligned_buffer_wrap_from_jbuffer(jbuf);
    graphics->frame_buffer.addr = iotjs_aligned_buffer_wrap_native_buffer_ptr(buffer_wrap);
  } else {
    jerry_release_value(jbuf);
    return JS_CREATE_ERROR(TYPE, "Invalid config.buf");
  }
  jerry_release_value(jbuf);

  jerry_value_t jwidth = iotjs_jval_get_property(jconfig, "width");
  if (jerry_value_is_number(jwidth)) {
    graphics->frame_buffer.width = iotjs_jval_as_number(jwidth);
  } else {
    jerry_release_value(jwidth);
    return JS_CREATE_ERROR(TYPE, "Invalid config.width");
  }
  jerry_release_value(jwidth);

  jerry_value_t jheight = iotjs_jval_get_property(jconfig, "height");
  if (jerry_value_is_number(jheight)) {
    graphics->frame_buffer.height = iotjs_jval_as_number(jheight);
  } else {
    jerry_release_value(jheight);
    return JS_CREATE_ERROR(TYPE, "Invalid config.height");
  }
  jerry_release_value(jheight);

  jerry_value_t jformat = iotjs_jval_get_property(jconfig, "format");
  if (jerry_value_is_number(jformat)) {
    graphics->frame_buffer.format = (display_pixel_format_t)iotjs_jval_as_number(jformat);
  } else {
    graphics->frame_buffer.format = DISPLAY_PIXELFORMAT_MAX;
  }
  jerry_release_value(jformat);
  if(graphics->frame_buffer.format >= DISPLAY_PIXELFORMAT_MAX) {
    return JS_CREATE_ERROR(TYPE, "Invalid config.format");
  }

  return jerry_create_undefined();
}


static jerry_value_t graphics_get_image_param(iotjs_graphics_t* graphics,
                                            const jerry_value_t jargv[],
                                            const jerry_length_t jargc) {
  if(jargc < 4) {
    return JS_CREATE_ERROR(TYPE, "Invalid Arguments");
  }

  jerry_value_t jimage = JS_GET_ARG(1, object);
  jerry_value_t jbuf = iotjs_jval_get_property(jimage, "bitmap");
  if (jerry_value_is_object(jbuf)) {
    iotjs_aligned_buffer_wrap_t* buffer_wrap = iotjs_aligned_buffer_wrap_from_jbuffer(jbuf);
    graphics->shape.image.bitmap = iotjs_aligned_buffer_wrap_native_buffer_ptr(buffer_wrap);
  } else {
    jerry_release_value(jbuf);
    return JS_CREATE_ERROR(TYPE, "Invalid image.bitmap");
  }
  jerry_release_value(jbuf);

  jerry_value_t jwidth = iotjs_jval_get_property(jimage, "width");
  if (jerry_value_is_number(jwidth)) {
    graphics->shape.image.width = iotjs_jval_as_number(jwidth);
  } else {
    jerry_release_value(jwidth);
    return JS_CREATE_ERROR(TYPE, "Invalid image.width");
  }
  jerry_release_value(jwidth);

  jerry_value_t jheight = iotjs_jval_get_property(jimage, "height");
  if (jerry_value_is_number(jheight)) {
    graphics->shape.image.height = iotjs_jval_as_number(jheight);
  } else {
    jerry_release_value(jheight);
    return JS_CREATE_ERROR(TYPE, "Invalid image.height");
  }
  jerry_release_value(jheight);

  graphics->shape.image.x = JS_GET_ARG(2, number);
  graphics->shape.image.y = JS_GET_ARG(3, number);

  return jerry_create_undefined();
}

static jerry_value_t graphics_get_line_param(iotjs_graphics_t* graphics,
                                            const jerry_value_t jargv[],
                                            const jerry_length_t jargc) {
  if(jargc < 6) {
    return JS_CREATE_ERROR(TYPE, "Invalid Arguments");
  }

  graphics->shape.line.startX = JS_GET_ARG(1, number);
  graphics->shape.line.startY = JS_GET_ARG(2, number);
  graphics->shape.line.endX = JS_GET_ARG(3, number);
  graphics->shape.line.endY = JS_GET_ARG(4, number);
  graphics->shape.line.color = JS_GET_ARG(5, number);

  return jerry_create_undefined();
}

static jerry_value_t graphics_get_rect_param(iotjs_graphics_t* graphics,
                                            const jerry_value_t jargv[],
                                            const jerry_length_t jargc) {
  if(jargc < 7) {
    return JS_CREATE_ERROR(TYPE, "Invalid Arguments");
  }

  graphics->shape.rect.x = JS_GET_ARG(1, number);
  graphics->shape.rect.y = JS_GET_ARG(2, number);
  graphics->shape.rect.width = JS_GET_ARG(3, number);
  graphics->shape.rect.height = JS_GET_ARG(4, number);
  graphics->shape.rect.color = JS_GET_ARG(5, number);
  graphics->shape.rect.fill = JS_GET_ARG(6, boolean);

  return jerry_create_undefined();
}

static jerry_value_t graphics_get_arc_param(iotjs_graphics_t* graphics,
                                            const jerry_value_t jargv[],
                                            const jerry_length_t jargc) {
  if(jargc < 7) {
    return JS_CREATE_ERROR(TYPE, "Invalid Arguments");
  }

  graphics->shape.arc.centerX = JS_GET_ARG(1, number);
  graphics->shape.arc.centerY = JS_GET_ARG(2, number);
  graphics->shape.arc.radius = JS_GET_ARG(3, number);
  graphics->shape.arc.startAngle = JS_GET_ARG(4, number);
  graphics->shape.arc.endAngle = JS_GET_ARG(5, number);
  graphics->shape.arc.color = JS_GET_ARG(6, number);

  return jerry_create_undefined();
}

static jerry_value_t graphics_get_circle_param(iotjs_graphics_t* graphics,
                                            const jerry_value_t jargv[],
                                            const jerry_length_t jargc) {
  if(jargc < 6) {
    return JS_CREATE_ERROR(TYPE, "Invalid Arguments");
  }

  graphics->shape.circle.centerX = JS_GET_ARG(1, number);
  graphics->shape.circle.centerY = JS_GET_ARG(2, number);
  graphics->shape.circle.radius = JS_GET_ARG(3, number);
  graphics->shape.circle.color = JS_GET_ARG(4, number);
  graphics->shape.circle.fill = JS_GET_ARG(5, boolean);

  return jerry_create_undefined();
}

static jerry_value_t graphics_get_ellipse_param(iotjs_graphics_t* graphics,
                                            const jerry_value_t jargv[],
                                            const jerry_length_t jargc) {
  if(jargc < 7) {
    return JS_CREATE_ERROR(TYPE, "Invalid Arguments");
  }

  graphics->shape.ellipse.centerX = JS_GET_ARG(1, number);
  graphics->shape.ellipse.centerY = JS_GET_ARG(2, number);
  graphics->shape.ellipse.radiusX = JS_GET_ARG(3, number);
  graphics->shape.ellipse.radiusY = JS_GET_ARG(4, number);
  graphics->shape.ellipse.color = JS_GET_ARG(5, number);
  graphics->shape.ellipse.fill = JS_GET_ARG(6, boolean);

  return jerry_create_undefined();
}

static jerry_value_t graphics_get_polygon_param(iotjs_graphics_t* graphics,
                                            const jerry_value_t jargv[],
                                            const jerry_length_t jargc) {
  if(jargc < 7) {
    return JS_CREATE_ERROR(TYPE, "Invalid Arguments");
  }

  graphics->shape.polygon.centerX = JS_GET_ARG(1, number);
  graphics->shape.polygon.centerY = JS_GET_ARG(2, number);
  graphics->shape.polygon.radius = JS_GET_ARG(3, number);
  graphics->shape.polygon.sides = JS_GET_ARG(4, number);
  graphics->shape.polygon.color = JS_GET_ARG(5, number);
  graphics->shape.polygon.fill = JS_GET_ARG(6, boolean);

  return jerry_create_undefined();
}

static jerry_value_t graphics_get_text_param(iotjs_graphics_t* graphics,
                                            const jerry_value_t jargv[],
                                            const jerry_length_t jargc) {
  if(jargc < 7) {
    return JS_CREATE_ERROR(TYPE, "Invalid Arguments");
  }

  graphics->shape.text.text = JS_GET_ARG(1, string);
  graphics->shape.text.x = JS_GET_ARG(2, number);
  graphics->shape.text.y = JS_GET_ARG(3, number);
  graphics->shape.text.size = JS_GET_ARG(4, number);
  graphics->shape.text.color = JS_GET_ARG(5, number);
  graphics->shape.text.background = JS_GET_ARG(6, number);

  return jerry_create_undefined();
}

JS_FUNCTION(GraphicsCons) {
//  DJS_CHECK_THIS();
  DJS_CHECK_ARGS(2, object, object);

  // Create Graphics object
  jerry_value_t jgraphics = JS_GET_ARG(0, object);
  iotjs_graphics_t* graphics = graphics_create(jgraphics);

  jerry_value_t jconfig = JS_GET_ARG(1, object);

  // set configuration
  jerry_value_t res = iotjs_graphics_set_platform_config(graphics, jconfig);
  if (jerry_value_is_error(res)) {
    return res;
  }

  res = graphics_set_configuration(graphics, jconfig);
  if (jerry_value_is_error(res)) {
    return res;
  }

  if (!iotjs_graphics_init(graphics)) {
    return JS_CREATE_ERROR(COMMON, "Init error, cannot init Frame Buffer");
  }

  return jerry_create_undefined();
}


JS_FUNCTION(DrawImage) {
  DJS_CHECK_ARGS(4, object, object, number, number);
  JS_DECLARE_OBJECT_PTR(0, graphics, graphics);

  jerry_value_t res = graphics_get_image_param(graphics, jargv, jargc);
  if (jerry_value_is_error(res)) {
    return res;
  }

  iotjs_ext_periph_call_async(graphics, JS_GET_ARG_IF_EXIST(4, function), kGraphicsOpDrawImage,
                          graphics_worker);
  return jerry_create_undefined();
}

JS_FUNCTION(DrawImageSync) {
  DJS_CHECK_ARGS(4, object, object, number, number);
  JS_DECLARE_OBJECT_PTR(0, graphics, graphics);

  jerry_value_t res = graphics_get_image_param(graphics, jargv, jargc);
  if (jerry_value_is_error(res)) {
    return res;
  }

  if(!iotjs_graphics_draw_image(graphics)) {
    return JS_CREATE_ERROR(COMMON, "Draw error, cannot draw Image");
  }

  return jerry_create_undefined();
}

JS_FUNCTION(DrawLine) {
//  DJS_CHECK_ARGS(6, object, number, number, number, number, number);
  JS_DECLARE_OBJECT_PTR(0, graphics, graphics);

  jerry_value_t res = graphics_get_line_param(graphics, jargv, jargc);
  if (jerry_value_is_error(res)) {
    return res;
  }

  iotjs_ext_periph_call_async(graphics, JS_GET_ARG_IF_EXIST(6, function), kGraphicsOpDrawLine,
                          graphics_worker);
  return jerry_create_undefined();
}

JS_FUNCTION(DrawLineSync) {
//  DJS_CHECK_ARGS(6, object, number, number, number, number, number);
  JS_DECLARE_OBJECT_PTR(0, graphics, graphics);

  jerry_value_t res = graphics_get_line_param(graphics, jargv, jargc);
  if (jerry_value_is_error(res)) {
    return res;
  }

  if(!iotjs_graphics_draw_line(graphics)) {
    return JS_CREATE_ERROR(COMMON, "Draw error, cannot draw Line");
  }

  return jerry_create_undefined();
}

JS_FUNCTION(DrawRect) {
//  DJS_CHECK_ARGS(7, object, number, number, number, number, number, boolean);
  JS_DECLARE_OBJECT_PTR(0, graphics, graphics);

  jerry_value_t res = graphics_get_rect_param(graphics, jargv, jargc);
  if (jerry_value_is_error(res)) {
    return res;
  }

  iotjs_ext_periph_call_async(graphics, JS_GET_ARG_IF_EXIST(7, function), kGraphicsOpDrawRect,
                          graphics_worker);
  return jerry_create_undefined();
}

JS_FUNCTION(DrawRectSync) {
//  DJS_CHECK_ARGS(7, object, number, number, number, number, number, boolean);
  JS_DECLARE_OBJECT_PTR(0, graphics, graphics);

  jerry_value_t res = graphics_get_rect_param(graphics, jargv, jargc);
  if (jerry_value_is_error(res)) {
    return res;
  }

  if(!iotjs_graphics_draw_rect(graphics)) {
    return JS_CREATE_ERROR(COMMON, "Draw error, cannot draw Rectangle");
  }

  return jerry_create_undefined();
}

JS_FUNCTION(DrawArc) {
//  DJS_CHECK_ARGS(7, object, number, number, number, number, number, number);
  JS_DECLARE_OBJECT_PTR(0, graphics, graphics);

  jerry_value_t res = graphics_get_arc_param(graphics, jargv, jargc);
  if (jerry_value_is_error(res)) {
    return res;
  }

  iotjs_ext_periph_call_async(graphics, JS_GET_ARG_IF_EXIST(7, function), kGraphicsOpDrawArc,
                          graphics_worker);
  return jerry_create_undefined();
}

JS_FUNCTION(DrawArcSync) {
//  DJS_CHECK_ARGS(7, object, number, number, number, number, number, number);
  JS_DECLARE_OBJECT_PTR(0, graphics, graphics);

  jerry_value_t res = graphics_get_arc_param(graphics, jargv, jargc);
  if (jerry_value_is_error(res)) {
    return res;
  }

  if(!iotjs_graphics_draw_arc(graphics)) {
    return JS_CREATE_ERROR(COMMON, "Draw error, cannot draw Arc");
  }

  return jerry_create_undefined();
}

JS_FUNCTION(DrawCircle) {
//  DJS_CHECK_ARGS(6, object, number, number, number, number, boolean);
  JS_DECLARE_OBJECT_PTR(0, graphics, graphics);

  jerry_value_t res = graphics_get_circle_param(graphics, jargv, jargc);
  if (jerry_value_is_error(res)) {
    return res;
  }

  iotjs_ext_periph_call_async(graphics, JS_GET_ARG_IF_EXIST(6, function), kGraphicsOpDrawCircle,
                          graphics_worker);
  return jerry_create_undefined();
}

JS_FUNCTION(DrawCircleSync) {
//  DJS_CHECK_ARGS(6, object, number, number, number, number, boolean);
  JS_DECLARE_OBJECT_PTR(0, graphics, graphics);

  jerry_value_t res = graphics_get_circle_param(graphics, jargv, jargc);
  if (jerry_value_is_error(res)) {
    return res;
  }

  if(!iotjs_graphics_draw_circle(graphics)) {
    return JS_CREATE_ERROR(COMMON, "Draw error, cannot draw Circle");
  }

  return jerry_create_undefined();
}

JS_FUNCTION(DrawEllipse) {
//  DJS_CHECK_ARGS(7, object, number, number, number, number, number, boolean);
  JS_DECLARE_OBJECT_PTR(0, graphics, graphics);

  jerry_value_t res = graphics_get_ellipse_param(graphics, jargv, jargc);
  if (jerry_value_is_error(res)) {
    return res;
  }

  iotjs_ext_periph_call_async(graphics, JS_GET_ARG_IF_EXIST(7, function), kGraphicsOpDrawEllipse,
                          graphics_worker);
  return jerry_create_undefined();
}

JS_FUNCTION(DrawEllipseSync) {
//  DJS_CHECK_ARGS(7, object, number, number, number, number, number, boolean);
  JS_DECLARE_OBJECT_PTR(0, graphics, graphics);

  jerry_value_t res = graphics_get_ellipse_param(graphics, jargv, jargc);
  if (jerry_value_is_error(res)) {
    return res;
  }

  if(!iotjs_graphics_draw_ellipse(graphics)) {
    return JS_CREATE_ERROR(COMMON, "Draw error, cannot draw Ellipse");
  }

  return jerry_create_undefined();
}

JS_FUNCTION(DrawPolygon) {
//  DJS_CHECK_ARGS(7, object, number, number, number, number, number, boolean);
  JS_DECLARE_OBJECT_PTR(0, graphics, graphics);

  jerry_value_t res = graphics_get_polygon_param(graphics, jargv, jargc);
  if (jerry_value_is_error(res)) {
    return res;
  }

  iotjs_ext_periph_call_async(graphics, JS_GET_ARG_IF_EXIST(7, function), kGraphicsOpDrawPolygon,
                          graphics_worker);
  return jerry_create_undefined();
}

JS_FUNCTION(DrawPolygonSync) {
//  DJS_CHECK_ARGS(7, object, number, number, number, number, number, boolean);
  JS_DECLARE_OBJECT_PTR(0, graphics, graphics);

  jerry_value_t res = graphics_get_polygon_param(graphics, jargv, jargc);
  if (jerry_value_is_error(res)) {
    return res;
  }

  if(!iotjs_graphics_draw_polygon(graphics)) {
    return JS_CREATE_ERROR(COMMON, "Draw error, cannot draw Polygon");
  }

  return jerry_create_undefined();
}

JS_FUNCTION(DrawText) {
//  DJS_CHECK_ARGS(7, object, string, number, number, number, number, number);
  JS_DECLARE_OBJECT_PTR(0, graphics, graphics);

  jerry_value_t res = graphics_get_text_param(graphics, jargv, jargc);
  if (jerry_value_is_error(res)) {
    return res;
  }

  iotjs_ext_periph_call_async(graphics, JS_GET_ARG_IF_EXIST(7, function), kGraphicsOpDrawText,
                          graphics_worker);
  return jerry_create_undefined();
}

JS_FUNCTION(DrawTextSync) {
//  DJS_CHECK_ARGS(7, object, string, number, number, number, number, number);
  JS_DECLARE_OBJECT_PTR(0, graphics, graphics);

  jerry_value_t res = graphics_get_text_param(graphics, jargv, jargc);
  if (jerry_value_is_error(res)) {
    return res;
  }

  if(!iotjs_graphics_draw_text(graphics)) {
    return JS_CREATE_ERROR(COMMON, "Draw error, cannot draw Text");
  }

  return jerry_create_undefined();
}

#endif	// #if defined(USE_POSIX_BRIDGE)


jerry_value_t InitGraphics() {

#if defined(USE_POSIX_BRIDGE)
  jerry_value_t jgraphics_cons = jerry_create_external_function(GraphicsCons);
  iotjs_jval_set_method(jgraphics_cons, "drawImage", DrawImageSync);
  iotjs_jval_set_method(jgraphics_cons, "drawImageSync", DrawImageSync);
  iotjs_jval_set_method(jgraphics_cons, "drawLine", DrawLineSync);
  iotjs_jval_set_method(jgraphics_cons, "drawLineSync", DrawLineSync);
  iotjs_jval_set_method(jgraphics_cons, "drawRect", DrawRectSync);
  iotjs_jval_set_method(jgraphics_cons, "drawRectSync", DrawRectSync);
  iotjs_jval_set_method(jgraphics_cons, "drawArc", DrawArcSync);
  iotjs_jval_set_method(jgraphics_cons, "drawArcSync", DrawArcSync);
  iotjs_jval_set_method(jgraphics_cons, "drawCircle", DrawCircleSync);
  iotjs_jval_set_method(jgraphics_cons, "drawCircleSync", DrawCircleSync);
  iotjs_jval_set_method(jgraphics_cons, "drawEllipse", DrawEllipseSync);
  iotjs_jval_set_method(jgraphics_cons, "drawEllipseSync", DrawEllipseSync);
  iotjs_jval_set_method(jgraphics_cons, "drawPolygon", DrawPolygonSync);
  iotjs_jval_set_method(jgraphics_cons, "drawPolygonSync", DrawPolygonSync);
  iotjs_jval_set_method(jgraphics_cons, "drawText", DrawTextSync);
  iotjs_jval_set_method(jgraphics_cons, "drawTextSync", DrawTextSync);

  // Buffer Format
  jerry_value_t jformat = jerry_create_object();
//  iotjs_jval_set_property_number(jformat, "YCBCR422", DISPLAY_PIXELFORMAT_YCBCR422);
  iotjs_jval_set_property_number(jformat, "RGB565", DISPLAY_PIXELFORMAT_RGB565);
  iotjs_jval_set_property_number(jformat, "RGB888", DISPLAY_PIXELFORMAT_RGB888);
  iotjs_jval_set_property_number(jformat, "ARGB8888", DISPLAY_PIXELFORMAT_ARGB8888);
  iotjs_jval_set_property_number(jformat, "ARGB4444", DISPLAY_PIXELFORMAT_ARGB4444);
  iotjs_jval_set_property_number(jformat, "MAX", DISPLAY_PIXELFORMAT_MAX);
  iotjs_jval_set_property_jval(jgraphics_cons, "BUFFERFORMAT", jformat);
  jerry_release_value(jformat);

#else	// #if defined(USE_POSIX_BRIDGE)
  jerry_value_t jgraphics_cons = jerry_create_object();
#endif	// #if defined(USE_POSIX_BRIDGE)

  return jgraphics_cons;
}
