/*#include <sys/types.h>*/
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <sys/time.h>
#include <sys/byteorder.h>
#include <stdio.h>
/*#include <unistd.h>*/
#include <stdlib.h>
#include <errno.h>
#include <string.h>

#include "callinfo.h"
#include "werr.h"

#define MAXPAGEBUFFERSIZE 1500  //max size of any returned page
#define LOOP_INTERVAL 1000		//Number of seconds between refreshes
#define NUM_MANUAL_STRUCTS 4    //Number of Service Providers

extern char *
http_get_url(char *url,
             char *proxy,
             int pollfunc(void *),
             void *user_data) ;

callstruct *current ;

int ss_in ;
struct in_addr ServerIp ; // IP Address of broadcasting OCLM

manualstruct manual[NUM_MANUAL_STRUCTS];

// static void
// dump_reply(char *reply)
// {
//   FILE *fp ;
//   int i=0;
//
//   fp = fopen("Mem::Sprites.$.res", "w") ;
//   if (!fp) werr(1, "fopen failed");
//   while (reply[i] && (reply[i] < 0x80))
//     fputc(reply[i++], fp) ;
//   if (reply[i] >= 0x80)
//     fputs("bit7 set char\n", fp);
//   if (reply[i] == '\0')
//     fputs("Normal termination\n", fp);
//   /*fwrite(reply, 1, strlen(reply), fp);*/
//   fclose(fp) ;
// }

/* Use http to get the IP addresses from the LAN Modem */

void lanmodem_get_ips(int pollfunc(void *))
{
  char url[128] = "", *reply, *td, *std ;
  int Ntd = 0 ;

  current[0].ip[0] = current[1].ip[0] = '\0' ;

  /* Fetch the stats page */

  sprintf(url,
    "http://%s/stat3.htm",
    inet_ntoa(ServerIp)) ;

  reply = http_get_url(
    url,
    NULL,
    pollfunc,
    NULL) ;

  if (!reply[0]) /* No response */
    return ;

  /*dump_reply(reply) ;*/

  /* Find the 11th and 12th occurrences of <td> to locate the IPs */

  /* Start at the beginning of the html */
  td = reply ;

  while (Ntd < 11)
  {
    td = strstr(td, "<td>") ;
    if (!td) return ; /* Failed */

    ++td ;
    ++Ntd ;
  }

  td = strchr(td, '>') ;
  ++td ;

  /* Should now be at start of 1st IP - find end */
  std = strstr(td, "</td>") ;

  if (!std)
  {
    werr(0, "Failed to find ip1") ;
    return ; /* Failed */
  }

  /* Terminate string here */
  *std = '\0' ;

  /* That's got the 1st IP */
  strncpy(current[0].ip, td, 63) ;

  /* Look for another <td> now */
  td = strstr(++std, "<td>") ;

  if (!td)
  {
    werr(0, "Failed to find ip2") ;
    return ; /* Failed */
  }

  td = strchr(td, '>') ;
  ++td ;

  /*td = &td[4] ;*/

  /* Find the end */
  std = strstr(td, "</td>") ;

  if (!std)
  {
    werr(0, "Failed to find ip2") ;
    return ; /* Failed */
  }

  /* Terminate string here */
  *std = '\0' ;

  /* That's got the 2nd IP */
  strncpy(current[1].ip, td, 63) ;

  return ;
}

void lanmodem_toggle_connection(
  int (*pollfunc)(void *),
  void *handle,
  int service)
{
  char url[128] = "", *reply ;

  sprintf(url,
    "http://%s/%s",
    inet_ntoa(ServerIp),
    manual[service-1].url);

  reply = http_get_url(
    url,
    NULL,
    pollfunc,
    NULL) ;

  /*werr(0, reply) ;*/
}

static char *call_direction(int direction)
{
  switch (direction)
  {
    case CALL_INCOMING:
      return "Incoming" ;

    case CALL_OUTGOING:
      return "Outgoing" ;
  }

  return "" ;
}

static char *call_type(int type)
{
  switch (type)
  {
    case CALL_NONE:
      return "None" ;

    case CALL_VOICE:
      return "Voice" ;

    case CALL_DATA:
      return "Data" ;
  }

  return "" ;
}

static void fill_in_text_entries(void)
{
  int i ;

  for (i=0; i<2; ++i)
  {
    strcpy(current[i].calltype, call_type(current[i].type)) ;
    strcpy(current[i].direction, call_direction(current[i].idirection)) ;
  }
}

static void decode_buff(char pagebuffer[], int bytesreturned)
{
  int curcount, length, option ;
  int NumChannels ;
  char data[255];
  /*unsigned long tmplong;*/
  time_t uptime ;

  //Pagebuffer now contains the packet to be parsed.
  //Bytesreturned contains the length of pagebuffer.


  curcount = 4; // Start at options offset
  while (curcount < bytesreturned)
  {
	option=pagebuffer[curcount];

	length=pagebuffer[curcount+1];
	memset(data, 0, sizeof(data));
	memcpy(data, (pagebuffer +curcount+2), length);
	curcount += (length+2);

	//Debugging
	//sprintf(buffer, "option: %d, length: %d, data=%d", option, length, data[0]);
	//AfxMessageBox(buffer);

	//Populate the structure
	switch(option)
	{
		case 1:   //Number of channels running
			NumChannels = data[0];
			break;

		case 2:   //Call Direction (Channel 1)
		{
			switch (data[0])
			{
			case 1:
				current[0].type=CALL_VOICE;
				current[0].idirection=CALL_INCOMING;
				break;
			case 2:
				current[0].type=CALL_VOICE;
				current[0].idirection=CALL_OUTGOING;
				break;
			case 3:
				current[0].type=CALL_DATA;
				current[0].idirection=CALL_INCOMING;
				break;
			case 4:
				current[0].type=CALL_DATA;
				current[0].idirection=CALL_OUTGOING;
				break;
			default:
				current[0].type=0;
				current[0].idirection=0;
			}
			break;
		}
		case 3:   //Destination Name (Channel 1)
			strncpy(current[0].spname, data, sizeof(current[0].spname));
			break;
		case 4:   //Number Called (Channel 1)
			strncpy(current[0].called, data, sizeof(current[0].called));
			break;
		case 5:   //Calling Number (Channel 1)
			strncpy(current[0].calling, data, sizeof(current[0].calling));
			break;
		case 6:   //B-Channel Count (Channel 1)
			current[0].bcount = data[0];
			break;
		case 7:   //Call duration (Channel 1)
			//Endian conversion
			uptime = (time_t) htonl (*((u_long *) &data[0]));
                        if (current[0].type != CALL_NONE)
			  strftime(current[0].callup, 31,
			    "%H:%M:%S", gmtime(&uptime)) ;
                        else
                          strcpy(current[0].callup, "") ;
			break;
		case 8:   //Remote ID
			current[0].remid=data[0];
			break;
		case 9:   //B-Channel call is on (1 or 2)
			current[0].bchan = data[0];
		case 10:  //SBRT entry for this current call
			current[0].sbrt=data[0];
			break;
		case 22:  //Call Direction (Channel 2)
		{
			switch (data[0])
			{
			case 1:
				current[1].type=CALL_VOICE;
				current[1].idirection=CALL_INCOMING;
				break;
			case 2:
				current[1].type=CALL_VOICE;
				current[1].idirection=CALL_OUTGOING;
				break;
			case 3:
				current[1].type=CALL_DATA;
				current[1].idirection=CALL_INCOMING;
				break;
			case 4:
				current[1].type=CALL_DATA;
				current[1].idirection=CALL_OUTGOING;
				break;
			default:
				current[1].type=0;
				current[1].idirection=0;
			}
			break;
		}
		case 23:   //Destination Name (Channel 2)
			strncpy(current[1].spname, data, sizeof(current[1].spname));
			break;
		case 24:   //Number Called (Channel 2)
			strncpy(current[1].called, data, sizeof(current[1].called));
			break;
		case 25:   //Calling Number (Channel 2)
			strncpy(current[1].calling, data, sizeof(current[1].calling));
			break;
		case 26:   //B-Channel Count (Channel 2)
			current[1].bcount = data[0];
			break;
		case 27:   //Call duration (Channel 2)
			//Endian conversion
			uptime = (time_t) htonl (*((u_long *) &data[0]));
                        if (current[1].type != CALL_NONE)
			  strftime(current[1].callup, 31,
			    "%H:%M:%S", gmtime(&uptime)) ;
                        else
                          strcpy(current[1].callup, "") ;
			break;
		case 28:   //Remote ID
			current[1].remid=data[0];
			break;
		case 29:   //B-Channel call is on (0 or 1)
			current[1].bchan = data[0];
		case 30:   //SBRT entry for this current call
			current[1].sbrt=data[0];
			break;

		case 40:   //Service Provider 1 name
			strncpy(manual[0].name, data, sizeof(manual[0].name));
			break;
		case 41:   //Service Provider 2 name
			strncpy(manual[1].name, data, sizeof(manual[1].name));
			break;
		case 42:   //Service Provider 3 name
			strncpy(manual[2].name, data, sizeof(manual[2].name));
			break;
		case 43:   //Service Provider 4 name
			strncpy(manual[3].name, data, sizeof(manual[3].name));
			break;
		default:
			break;
	}
  }
}


int lanmodem_main (int (*pollfunc)(void *), int (*updatefunc)(void *),
  void *user_data)
{
  struct sockaddr_in addr_in ;
  int addrlen, i ;
  char buf[MAXPAGEBUFFERSIZE];
  int retval, fromaddrlen ;

  /* Create inet socket */

  ss_in = socket(AF_INET, SOCK_DGRAM, 0);
  if (ss_in == -1) {
    werr(1, "Error opening inet stream socket");
  }

  i = 1 ;
  if (-1 == setsockopt(ss_in,  SOL_SOCKET, SO_REUSEADDR, (char *)&i, sizeof(i)))
  {
    werr(1, "Error: setsockopt SO_REUSEADDR") ;
  }

  addr_in.sin_family = AF_INET ;
  addr_in.sin_port   = htons(2071) ;
  addr_in.sin_addr.s_addr = INADDR_ANY;
  addrlen = sizeof (addr_in) ;
  if (bind (ss_in, (struct sockaddr *) &addr_in, addrlen) == -1) {
    werr(1, "Error binding inet stream socket");
  }

  do
  {
    fd_set rfds;
    struct timeval tv;
    int ts ;

    ts = ss_in+1 ;

    FD_ZERO(&rfds);
    FD_SET(ss_in, &rfds);
    tv.tv_sec = 0;
    tv.tv_usec = 10000;

    memset(buf, 0, sizeof buf);

    retval = select(ts, &rfds, NULL, NULL, &tv);
    if (retval) {
      /* Somebody is talking to us! */

      if (FD_ISSET(ss_in, &rfds))
      {
        memset(buf, 0, sizeof buf);

        fromaddrlen = sizeof(struct sockaddr_in) ;

        retval = recvfrom(ss_in, buf, 1024, 0, (struct sockaddr *)&addr_in,
          &fromaddrlen);

        if ((retval > 0) && (retval < 1024))
        {
          decode_buff(buf, retval) ;
          fill_in_text_entries() ;
          /*print_calls();*/

          ServerIp = addr_in.sin_addr ;

          /*werr(0, "http://%s/mainpage.htm", inet_ntoa(ServerIp));*/

          /* Callback function */
          if (-1 == updatefunc(user_data)) exit(1) ;
        }

        if (retval == -1)
        {
          werr(0, "Error reading inet stream message");
        }
      }
    }
    else
    {
      /* Do something else! */
      if (pollfunc)
        if (-1 == pollfunc(user_data)) exit(0) ;
    }

  } while (1);

  return 0 ;
}
