#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/* OSLib headers */
#include "oslib/wimp.h"
#include "oslib/toolbox.h"
#include "oslib/displayfie.h"
#include "oslib/iconbar.h"
#include "oslib/menu.h"
#include "oslib/proginfo.h"

/* OSLib support headers */
#include "Wimptypes.h"
#include "Event.h"

/* Local headers */
#include "gdefs.h"
#include "callinfo.h"
#include "globaldef.h"
#include "werr.h"

extern callstruct *current;
extern manualstruct manual[];

int td = 0, td2 = 0 ;

os_error *e ;

extern int close(int /*s*/);

extern void lanmodem_toggle_connection(
  int pollfunc(void *),
  void *handle,
  int service) ;

extern void lanmodem_get_ips(int pollfunc(void *)) ;

extern int ss_in ;

toolbox_o window_o = event_ANY, iconbar_o = event_ANY, menu_o = event_ANY ;

int lanmodem_main (int pollfunc(void *), int updatefunc(void *),
  void *user_data) ;

int poll_wimp(void *data)
{
  wimp_event_no event_code ;
  wimp_block poll_block ;

  if (data) /* data points to a monotonic time value for idle polling */
    event_poll_idle(&event_code, &poll_block, *((os_t *) data), NULL) ;
  else
    event_poll(&event_code, &poll_block, NULL) ;

  return 0 ;
}

static char *get_help_string(int channel)
{
  char *type, *direct, buff[128] ;

  switch (current[channel].type)
  {
    case CALL_VOICE:
      type = "Voice" ;
      break ;

    case CALL_DATA:
      type = "Data" ;
      break ;

    case CALL_NONE:
      return "" ;
      break ;

    default:
      type = "???" ;
  }

  switch (current[channel].idirection)
  {
    case CALL_INCOMING:
      direct = " call from " ;
      break ;

    case CALL_OUTGOING:
      direct = " call to " ;
      break ;

    default:
      direct = "" ;
  }

  sprintf(buff,
    "%s%s%s %s",
    type,
    direct,
    current[channel].spname,
    current[channel].callup) ;

  return buff ;
}

/* Determine the iconbar sprite name */

static char *type_to_name(char help[])
{
  char name[13] ;

  name[0] = help[0] = '\0' ;

  switch (current[0].type)
  {
    case CALL_VOICE:
      strcpy(name, "a1") ;
      break ;

    case CALL_DATA:
      if ((current[1].type==NONE) && (current[0].bcount > 1))
      {
        sprintf(help, "Multilink call to %s %s",
          current[0].spname, current[0].callup);
        return "d1d2t" ; /* Channel bonding on */
      }
      else
      {
        strcpy(name, "d1") ;
      }
      break ;

    case CALL_NONE:
    default:
      strcpy(name, "") ;
  }

  switch (current[1].type)
  {
    case CALL_VOICE:
      strcat(name, "a2") ;
      break ;

    case CALL_DATA:
      if ((current[0].type==NONE) && (current[1].bcount > 1))
      {
        sprintf(help, "Multilink call to %s %s",
          current[1].spname, current[1].callup);
        return "d1d2t" ; /* Channel bonding on */
      }
      else
      {
        strcat(name, "d2") ;
      }
      break ;

    case CALL_NONE:
    default:
      strcat(name, "") ;
  }

  if (0 == strlen(name)) /* Blank */
    strcpy(name, "nxn") ;

  return name ;
}

static void set_menus(void)
{
  int i ;

    char menu_text[64] ;

    /* Are we connected to this provider? */

    /* See if there is a sbrt match in either of the
    	current call structs */

    for (i=0; i < 4; i++)
    	manual[i].sbrt=0xff;
    if (current[0].sbrt != 0xff)
    	manual[current[0].remid].sbrt=current[0].sbrt;
    if (current[1].sbrt != 0xff)
    	manual[current[1].remid].sbrt=current[1].sbrt;

    // Generate the providerstate structs
    for (i=0; i < 4; i++)
    {
	if (!manual[i].name[0])
	{
		// Take care of non-existant Service provider
		/*inMainFrame->m_trayIcon.SetProviderName(i, "");
		inMainFrame->m_trayIcon.SetProviderUrl(i, "");
		inMainFrame->m_trayIcon.SetProviderState(i, 0);*/
		continue;
	}

	/*inMainFrame->m_trayIcon.SetProviderName(i, manual[i].name);*/
	// Figure out whether to place or disconnect
	if (manual[i].sbrt == 0xff)
	{
	  sprintf(manual[i].url, "call%d.htm", i+1);
          sprintf(menu_text, "Dial %s", manual[i].name) ;
		/*state=1;*/
	}
	else
	{
	  sprintf(manual[i].url, "disc%d.htm", manual[i].sbrt+1);
          sprintf(menu_text, "Disconnect %s", manual[i].name) ;
		/*state=3;*/
	}

	/*inMainFrame->m_trayIcon.SetProviderUrl(i, inMainFrame->manualstat[i].url);
	inMainFrame->m_trayIcon.SetProviderState(i, state);	*/



    e = xmenu_set_entry_text(
      0,
      menu_o,
      2 + i,
      menu_text) ;

    if (e) wimp_report_error(e, 0, TASKNAME) ;
  }
}

int update_window(void *data)
{
  char help_string[256], help1[256], help2[256], sprite[13] ;
  static char old_sprite[13] = "" ;
  static int update_window_mutex = 0 ;
  int tries = 0 ;
  os_t monot ;

  /* Don't try to update whilst waiting on IPs */
  if (update_window_mutex) return 0 ;

  e = xdisplayfield_set_value (0,
      window_o,
      CALL1_TYPE,
      current[0].calltype) ;
  if (e) wimp_report_error(e, 0, TASKNAME) ;

  e = xdisplayfield_set_value (0,
      window_o,
      CALL1_DIRECTION,
      current[0].direction) ;
  if (e) wimp_report_error(e, 0, TASKNAME) ;

  e = xdisplayfield_set_value (0,
      window_o,
      CALL1_PROVIDER,
      current[0].spname) ;
  if (e) wimp_report_error(e, 0, TASKNAME) ;

  e = xdisplayfield_set_value (0,
      window_o,
      CALL1_DURATION,
      current[0].callup) ;
  if (e) wimp_report_error(e, 0, TASKNAME) ;

  e = xdisplayfield_set_value (0,
      window_o,
      CALL2_TYPE,
      current[1].calltype) ;
  if (e) wimp_report_error(e, 0, TASKNAME) ;

  e = xdisplayfield_set_value (0,
      window_o,
      CALL2_DIRECTION,
      current[1].direction) ;
  if (e) wimp_report_error(e, 0, TASKNAME) ;

  e = xdisplayfield_set_value (0,
      window_o,
      CALL2_PROVIDER,
      current[1].spname) ;
  if (e) wimp_report_error(e, 0, TASKNAME) ;

  e = xdisplayfield_set_value (0,
      window_o,
      CALL2_DURATION,
      current[1].callup) ;
  if (e) wimp_report_error(e, 0, TASKNAME) ;

  /* Set the menus */
  set_menus() ;

  /* Clear help strings */
  help_string[0] = help1[0] = help2[0] = '\0' ;

  /* Set iconbar sprite name */

  strcpy(sprite, type_to_name(help_string)) ;

  if (0 != strcmp(old_sprite, sprite))
  {
    strcpy(old_sprite, sprite) ;

    e = xiconbar_set_sprite(0,
        iconbar_o,
        sprite) ;
    if (e)
    {
      wimp_report_error(e, 0, TASKNAME) ;
      werr(0, "Spritename: %s", type_to_name(help_string)) ;
    }

    /* We may poll the wimp here, so set the lock */
    update_window_mutex = 1 ;
    tries = 0;
    monot = os_read_monotonic_time() ;
    do
    {
      os_t after ;

      lanmodem_get_ips(poll_wimp) ;
      after = 50 + os_read_monotonic_time() ;
      ++tries ;
      poll_wimp((void *) &after) ;

      /* 20-s timeout */
      if (after - monot > 2000) break ;
    }
    while ((0 == strcmp("0.0.0.0", current[0].ip)) ||
           (0 == strcmp("0.0.0.0", current[1].ip))) ;
    /*werr(0, "%d tries in %d cs",
      tries,
      (int) (os_read_monotonic_time() - monot)) ;*/

    update_window_mutex = 0 ;

    e = xdisplayfield_set_value (0,
        window_o,
        CALL1_IP,
        current[0].ip) ;
    if (e) wimp_report_error(e, 0, TASKNAME) ;

    e = xdisplayfield_set_value (0,
        window_o,
        CALL2_IP,
        current[1].ip) ;
    if (e) wimp_report_error(e, 0, TASKNAME) ;
  }

  /* Was help_string[] not set by type_to_name()? */
  if (!help_string[0])
  {
    /* Set help strings */

    strcpy(help1, get_help_string(0)) ;
    strcpy(help2, get_help_string(1)) ;

    strcpy(help_string, help1) ;

    if (help1[0] && help2[0])
      strcat(help_string, "|M") ;

    strcat(help_string, help2) ;

    if (!help_string[0])
      strcat(help_string, "No calls currently active") ;
  }

  e = xiconbar_set_help_message(0,
      iconbar_o,
      help_string) ;
  if (e) wimp_report_error(e, 0, TASKNAME) ;

  return 0 ;
}

static bool connect_event(bits event_code,
      toolbox_action *action, toolbox_block *id_block,
      void *handle)
{
  int service ;

  service = (int) handle ;

  /*werr(0, "connect_event %d", service) ;*/

  lanmodem_toggle_connection(poll_wimp, NULL, service) ;

  return(1);
}

void lanmodemm_exit(void)
{
  /* Exit function */

  if (ss_in) close(ss_in) ;
}

static bool quit_event(bits event_code,
      toolbox_action *action, toolbox_block *id_block,
      void *handle)
{
  /* Close the socket */

  close(ss_in) ;
  ss_in = 0 ;
  exit(0) ;
  return(1);
}

static bool quit_message(wimp_message  *message,void *handle)
{
  message = message;
  handle = handle;

  /* Close the socket */

  close(ss_in) ;
  ss_in = 0 ;
  exit(0) ;
  return(1);
}

static int window_created(toolbox_o w)
{
  window_o = w ;

  return 0 ;
}

static int iconbar_created(toolbox_o w)
{
  iconbar_o = w ;

  return 0 ;
}

static int attach_our_other_handlers(bits event_code,
      toolbox_action *action, toolbox_block *id_block,
      void *handle)
{
  char name[64] ;
  int used ;

  e = xtoolbox_get_template_name (0,
      id_block->this_obj,
      name,
      64,
      &used);

  if (e)
  {
    wimp_report_error(e, 0, TASKNAME) ;
    return 1 ;
  }

  if (strcmp(name, "ProgInfo") == 0)
  {
    e = xproginfo_set_version(0,
      id_block->this_obj,
      VERSION) ;

    if (e)
    {
      wimp_report_error(e, 0, TASKNAME) ;
      return 1 ;
    }

    return 1 ;
  }

  if (strcmp(name, "Window") == 0)
  {
    window_created(id_block->this_obj) ;
    return 1 ;
  }

  if (strcmp(name, "Iconbar") == 0)
  {
    iconbar_created(id_block->this_obj) ;
    return 1 ;
  }

  if (strcmp(name, "Menu") == 0)
  {
    menu_o = id_block->this_obj ;
    return 1 ;
  }

  return 1 ;
}

int main(int argc, char *argv[])
{
  int messages[] = {0} ;
  int action_nos[] = {0} ;
  messagetrans_control_block cb ;
  toolbox_block block ;
  int version_out ;
  osspriteop_area *area ;
  wimp_t task ;
  wimp_event_no event_code ;
  wimp_block poll_block ;

  /* Register exit function - to close socket */
  atexit(lanmodemm_exit) ;

  current = (callstruct *) calloc(sizeof(callstruct) ,2) ;

  task = toolbox_initialise(
                          0,
                          310,
                          (wimp_message_list*) messages,
                          (toolbox_action_list*) action_nos,
                          "<LanMoC$Dir>",
                          &cb,
                          &block,
                          &version_out,
                          &area
                         ) ;


  event_initialise(&block) ;

    event_set_mask(0); /*
        	      	Wimp_Poll_NullMask
                      | Wimp_Poll_KeyPressedMask
                      | Wimp_Poll_LoseCaretMask
                      | Wimp_Poll_GainCaretMask
                      | Wimp_Poll_PollWordNonZeroMask
                      | Wimp_Poll_PollWord
                      | Wimp_Poll_PollWordHighPriority
                            );*/

  if (!event_register_message_handler(message_QUIT, quit_message, NULL))
    werr(1, "event_register_message_handler failed") ;

  if (!event_register_toolbox_handler(
        event_ANY,
        action_OBJECT_AUTO_CREATED,
        attach_our_other_handlers,
        NULL
  )) werr(1, "event_register_toolbox_handler failed") ;

  if (!event_register_toolbox_handler(
        event_ANY,
        1,
        quit_event,
        NULL
  )) werr(1, "event_register_toolbox_handler failed") ;

  if (!event_register_toolbox_handler(
        event_ANY,
        0x11,
        connect_event,
        (void *) 1
  )) werr(1, "event_register_toolbox_handler failed") ;

  if (!event_register_toolbox_handler(
        event_ANY,
        0x12,
        connect_event,
        (void *) 2
  )) werr(1, "event_register_toolbox_handler failed") ;

  if (!event_register_toolbox_handler(
        event_ANY,
        0x13,
        connect_event,
        (void *) 3
  )) werr(1, "event_register_toolbox_handler failed") ;

  if (!event_register_toolbox_handler(
        event_ANY,
        0x14,
        connect_event,
        (void *) 4
  )) werr(1, "event_register_toolbox_handler failed") ;

  while ( (window_o == event_ANY) &&
          (iconbar_o == event_ANY) &&
          (menu_o == event_ANY))
  {
    event_poll(&event_code, &poll_block, NULL) ;
  }

  lanmodem_main(poll_wimp, update_window, NULL) ;

  exit(0) ;
}
