#include "zori.h"
#include "zori_page.h"
#include "zori_screen.h"

struct zori_screen * zori_widget_to_screen(struct zori_widget * widget) {
  return ZORI_CONTAINER_OF(widget, struct zori_screen, widget);
}


/** Handles a mouse axis event and then pass it on to the active page. */
int zori_screen_on_mouse_axes(union zori_event * event) { 
    struct zori_screen * screen = zori_widget_to_screen(event->any.widget);

    screen->cursors.mouse.p.x = event->sys.ev->mouse.x;
    screen->cursors.mouse.p.y = event->sys.ev->mouse.y;
    
    if (screen->active_page) {
      return zori_widget_raise_system_event(&screen->active_page->widget, 
        event->sys.ev);
    }
    return ZORI_HANDLE_PASS;
}

/** Handles a system event by passing it on to the active page.  */
int zori_screen_on_sysevent(union zori_event * event) { 
    struct zori_screen * screen = zori_widget_to_screen(event->any.widget);
  
    if (screen->active_page) {
      return zori_widget_raise_system_event(&screen->active_page->widget, 
        event->sys.ev);
    }
    return ZORI_HANDLE_PASS;
}
 

void zori_draw_cursor(const struct zori_cursor * cursor, const struct zori_style * style) {
  if (cursor->bitmap) {
    al_draw_bitmap(cursor->bitmap, cursor->p.x, cursor->p.y,  0);
  } else {
    float x1, x2, x3, y1, y2, y3;
    x1 = cursor->p.x;
    y1 = cursor->p.y;
    x2 = x1 + 24 + 8;
    y2 = y1 + 24 - 8;
    x3 = x1 + 24 - 8;
    y3 = y1 + 24 + 8;  
    al_draw_filled_triangle(x1, y1, x2, y2, x3, y3, style->fore.color);
    al_draw_triangle(x1, y1, x2, y2, x3, y3, style->back.color, 1.0);
  }
};


void zori_draw_cursors(const struct zori_cursors * cursors, const struct zori_style * style) {
  zori_draw_cursor(&cursors->keyjoy, style);
  zori_draw_cursor(&cursors->mouse, style);
};
 
int zori_screen_on_overdraw(union zori_event * event) {
  struct zori_screen * screen = zori_widget_to_screen(event->any.widget);
  zori_draw_cursors(&screen->cursors, &screen->widget.style);
  return ZORI_HANDLE_PASS;
}

/* Handlers must beset up for many events on screen to funnel them all into 
 * the active page. */
struct zori_handler zori_screen_handlers[] = {
  { ZORI_SYSTEM_EVENT_KEY_DOWN          , zori_screen_on_sysevent       , NULL }, 
  { ZORI_SYSTEM_EVENT_KEY_UP            , zori_screen_on_sysevent       , NULL },
  { ZORI_SYSTEM_EVENT_KEY_CHAR          , zori_screen_on_sysevent       , NULL },
  { ZORI_SYSTEM_EVENT_MOUSE_BUTTON_DOWN , zori_screen_on_sysevent       , NULL },
  { ZORI_SYSTEM_EVENT_MOUSE_BUTTON_UP   , zori_screen_on_sysevent       , NULL },
  { ZORI_SYSTEM_EVENT_MOUSE_AXES        , zori_screen_on_mouse_axes     , NULL },
  { ZORI_EVENT_OVERDRAW                 , zori_screen_on_overdraw       , NULL },
  { -1, NULL, NULL }
};


struct zori_screen * 
zori_screen_init(struct zori_screen * screen, zori_display * display) {
  memset(&screen->cursors, 0, sizeof(screen->cursors));
  /* the keyjoy cursor is hidden off-screen to begin with. */
  screen->cursors.keyjoy.p.x = - 64;
  screen->cursors.keyjoy.p.y = - 64;
  
  screen->display     = display; 
  screen->active_page = NULL; 
  return screen;
}

struct zori_screen * zori_screen_new(zori_id id, zori_display * display) {
  struct zori_screen * screen = NULL; zori_rebox box;
  box.at.x = 0;
  box.at.y = 0;
  if (!display) return NULL;
  screen = calloc(1, sizeof(*screen));
  if (!screen) return NULL;
  box.size.x = al_get_display_width(display);
  box.size.y = al_get_display_height(display);
  zori_widget_initall(&screen->widget, ZORI_WIDGET_TYPE_SCREEN, id, &zori_get_root()->widget, 
                      &box, NULL, ZORI_ARRAY_AND_AMOUNT(zori_screen_handlers)); 
  if (!zori_screen_init(screen, display)) {
    free(screen);
    screen = NULL;
  }
  return screen;
}


zori_id zori_new_screen(zori_id id, zori_display * display) {
  struct zori_screen * screen = zori_screen_new(id, display);
  if (!screen) return ZORI_ID_ENOMEM;
  return screen->widget.id;
}


zori_id zori_active_page(zori_id screen_id) {
  struct zori_screen * screen = zori_widget_to_screen(zori_get_widget(screen_id));
  if (!screen) {
    return ZORI_ID_EINVAL;
  }
  if (!screen->active_page) {
    return ZORI_ID_EINVAL;
  }
  return screen->active_page->widget.id;
}



zori_id zori_screen_go(zori_id screen_id, zori_id page_id, void * data) { 
  struct zori_screen * screen = zori_widget_to_screen(zori_get_widget(screen_id));
  struct zori_page   * page = zori_widget_to_page(zori_get_widget(page_id));
  
  if ((screen) && (page)) {
    screen->active_page = page;
    zori_widget_raise_action_event(&page->widget);
    return page->widget.id;
  } else {
    return ZORI_ID_EINVAL;
  }
}




