/*
 routes.c
 --------
 25/10/25

 A pictorial representation of the driver routing.
*/

#include "wimp.h"
#include "main.h"
#include "lib.h"
#include "drivers.h"

void line(void *start, int x1, int y1, int x2, int y2, int colour); //line.s
void rectangle(void *start, int x1, int y1, int x2, int y2, int colour); //rectangle.s

// icon size in pixels
#define PLOT_HEIGHT 956 // to suit DRIVER_LIMIT number of drivers = 32*30-4
#define PLOT_WIDTH  128

// desktop 256 colour palette colours
#define BLACK         0
#define RED          23
#define GREY         44
#define GREEN        67
#define YELLOW      119
#define BLUE        138
#define MAGENTA     158
#define LILAC       187
#define CYAN        235
#define PALE_GREY   253 // wimp window background
#define WHITE       255

int col[4] = {PALE_GREY, BLACK, GREEN, RED};
char col_str[4][8];

/*
 * driver_info
 * -----------
 * Returns 1 if window opened, 0 if closed.
 */
static int driver_info(int window, int icon, driver_t *d)
{
  _kernel_swi_regs regs;
  int blk[9];

  regs.r[1] = (int)blk;
  blk[0] = ro.handle[WIN_DRV_INFO];
  _kernel_swi(Wimp_GetWindowState, &regs, &regs);
  int open = (blk[8] >> 16) & 1;

  static int last_icon = -1;
  if((icon < 0) || (icon > 63) || (open && (last_icon == icon)))
  {
    _kernel_swi(Wimp_CloseWindow, &regs, &regs);
    last_icon = -1;
    return 0;
  }
  last_icon = icon;
  update_info_icons(blk, window, d);
  return 1;
}


/*
 * set_routes_window_extent
 * ------------------------
 */
static void set_routes_window_extent(int num_drvs)
{
  _kernel_swi_regs regs;
  int blk[44];
  int win = ro.handle[WIN_ROUTE_MAP];

  blk[0] = win;
  regs.r[1] = (int)blk + 1;
  _kernel_swi(Wimp_GetWindowInfo, &regs, &regs);
  // resize window
  regs.r[0] = win;
  regs.r[1] = (int)&blk[11];
  blk[12] = blk[14] - 92 - (num_drvs * 60); // y min
  _kernel_swi(Wimp_SetExtent, &regs, &regs);
  // if it's open, re-open it
  regs.r[1] = (int)blk;
  blk[0] = win;
  _kernel_swi(Wimp_GetWindowState, &regs, &regs);
  if(blk[8] & (1<<16))
  {
    blk[7] = ro.handle[WIN_ROUTE_PANE];
    _kernel_swi(Wimp_OpenWindow, &regs, &regs);
  }
}


/*
 * update_routes
 * -------------
 * Redraws the routes window, updates the driver icons. The
 * actual routes are drawn by activity() below, which runs regularly.
 */
void update_routes(void)
{
  set_routes_window_extent(drivers);

  int y = drivers * 30;
  memset(ro.route_map, col[0], y * PLOT_WIDTH); // background
  rectangle(ro.route_map, 0, y, PLOT_WIDTH, y - 4, PALE_GREY); // bottom border

  int i, win = ro.handle[WIN_ROUTE_MAP];

  for(i=0; i<drivers; i++)
  {
    driver_t *dr = &driver[i];
    icon_text_change(name_or_product(dr), win, ICON_ROUTE_SRC+(2*i));
    icon_disabled_change(!(dr->flags & (1<<CAN_SEND)), win, ICON_ROUTE_SRC+(2*i));
    icon_text_change(name_or_product(dr), win, ICON_ROUTE_DST+(2*i));
    icon_disabled_change(!(dr->flags & (1<<CAN_RECEIVE)), win, ICON_ROUTE_DST+(2*i));
  }
  icon_state_change(0, win, ICON_ROUTE_MAP);
}


/*
 * activity
 * --------
 * Runs every 100ms. Draws the connection lines, coloured according to the activity count
 * from the support module.
 * if 'now' = 1, ignore the execution delay timer
 */
void activity(int now)
{
  int i, j, n, y, map, colour;

  if(!now)
  {
    static int t;
    if(++t < 5)
      return;
    t = 0;
  }

  for(i=0; i<drivers; i++)
    if((map = *driver[i].map) != 0)
    {
      n = driver[i].map[1]; // activity count
      driver[i].map[1] = 0;

      if(n > 20)
        colour = col[3]; // heavy traffic
      else if(n > 0)
        colour = col[2]; // any traffic (active)
      else
        colour = col[1]; // no traffic (idle)

      y = 13 + (i * 30);
      for(j=0; j<drivers; j++)
        if(map & (1 << (driver[j].number - 1)))
        {
          line(ro.route_map, 0, y, PLOT_WIDTH-1, 13 + (j * 30), colour);
          line(ro.route_map, 0, y+1, PLOT_WIDTH-1, 14 + (j * 30), colour); // make lines a bit thicker
        }
    }
  icon_state_change(0, ro.handle[WIN_ROUTE_MAP], ICON_ROUTE_MAP);
}


/*
 * route_map_mouse_click
 * ---------------------
 */
int route_map_mouse_click(int *blk, int state)
{
  // route map window
  if(blk[3] == ro.handle[WIN_ROUTE_MAP])
  {
    if((blk[2] == MOUSE_SELECT) || (blk[2] == MOUSE_ADJUST))
    {
      if(blk[4] < (2*DRIVER_LIMIT))
        drag_start(blk[3], blk[4], blk[2]);
    }
    else if(blk[2] == MOUSE_MENU)
    {
      if(blk[4] == ICON_ROUTE_MAP)
        open_menu(blk[0] - 64, blk[1], MENU_ROUTE_MAP, (int)&route_map_menu);
      else
        driver_info(blk[3], blk[4], &driver[blk[4] / 2]);
    }
  }
  if(blk[3] == ro.handle[WIN_ROUTE_PANE])
  {
    if(blk[2] == MOUSE_MENU)
      open_menu(blk[0] - 64, blk[1], MENU_ROUTE_MAP, (int)&route_map_menu);
  }
  else if(blk[3] == ro.handle[WIN_SAVE])
  {
    switch(blk[4])
    {
      case ICON_SAVE_SPR:
        if(blk[2] == 4*16) // start a drag
          drag_start(blk[3], blk[4], blk[2]);
        break;
    }
  }
  else
    return 0;

  return 1;
};


/*
 * route_map_menu_selection
 * ------------------------
 * blk = from WimpPoll, b = from GetPointerInfo
 */
int route_map_menu_selection(int *blk, int *b)
{
  _kernel_swi_regs regs;
  int i;

  switch(ro.cur_menu)
  {
    case MENU_ROUTE_MAP:
      switch(blk[0])
      {
        case 0: // panic
          if(blk[1] == -1)
            action_panic();
          else
          {
            ro.panic ^= (1 << blk[1]);
            for(i=0; i<PANIC_OPTIONS; i++)
              panic_menu.item[i].item_flags = (panic_menu.item[i].item_flags & ~IT_TICKED) | ((ro.panic >> i) & 1);
          }
          break;

        case 1: // clear all
          clear_connections();
          break;

        case 2: // route mao colours
          if((blk[2] == 0) && (blk[1] >= 0) && (blk[1] <= 3))
          {
            col[blk[1]] = atoi(col_str[blk[1]]) & 255;
            update_routes();
          }
          break;

        case 3: // save startup configuration
          save_config("<MIDISupport$Dir>.!Config");
          break;

        case 4: // modules
          open_window_pane(1, WIN_MODULES, blk, &regs);
          break;

        case 5: // help
          _kernel_oscli("Filer_Run "RESOURCES_DIR".RouteMap");
          break;
      }
      if(b[2] == MOUSE_ADJUST)
        open_menu(0, 0, ro.cur_menu, (int)&route_map_menu);
      break;

    default:
      return 0;
  }
  return 1;
};


