/*
        Make.c
*/

#include "stdlib.h"
#include "config.h"
#include "poly.h"
#include "serial.h"
#include "string.h"
#define MY_IP 192,168,2,200
#define GATEWAY 192,168,2,1 

#define MSG_MAX 2048
#define IP_ADDRESS( a, b, c, d ) \
  ( ( (int)d << 24 ) + ( (int)c << 16 ) + ( (int)b << 8 ) + (int)a )

void BlinkTask( void* parameters );
void SerialTask( void* parameters );
void NetworkCheck( void );

void Make( )
{

  // Do this right quick after booting up - otherwise we won't be recognised
  Usb_SetActive( 1 );

  //Debug_SetUdp(1);
  Debug_SetActive( 1 );

  // Active the Poly Function Task
  // Poly_SetActive( true );

  // Fire up the OSC system
  Osc_SetActive( true );
  // Add all the subsystems (make sure OSC_SUBSYSTEM_COUNT is large enough to accomodate them all)
  Osc_RegisterSubsystem( 0, AppLedOsc_GetName(), AppLedOsc_ReceiveMessage, NULL );
  Osc_RegisterSubsystem( 1, DipSwitchOsc_GetName(), DipSwitchOsc_ReceiveMessage, NULL );
  Osc_RegisterSubsystem( 2, ServoOsc_GetName(), ServoOsc_ReceiveMessage, NULL );
  Osc_RegisterSubsystem( 3, AnalogInOsc_GetName(), AnalogInOsc_ReceiveMessage, NULL );
  Osc_RegisterSubsystem( 4, DigitalOutOsc_GetName(), DigitalOutOsc_ReceiveMessage, NULL );
  Osc_RegisterSubsystem( 5, DigitalInOsc_GetName(), DigitalInOsc_ReceiveMessage, NULL );
  Osc_RegisterSubsystem( 6, MotorOsc_GetName(), MotorOsc_ReceiveMessage, NULL );
  Osc_RegisterSubsystem( 7, PwmOutOsc_GetName(), PwmOutOsc_ReceiveMessage, NULL );
  Osc_RegisterSubsystem( 8, LedOsc_GetName(), LedOsc_ReceiveMessage, NULL );
  Osc_RegisterSubsystem( 9, DebugOsc_GetName(), DebugOsc_ReceiveMessage, NULL );
  Osc_RegisterSubsystem( 10, SystemOsc_GetName(), SystemOsc_ReceiveMessage, NULL );
  Osc_RegisterSubsystem( 11, NetworkOsc_GetName(), NetworkOsc_ReceiveMessage, NULL );
  Osc_RegisterSubsystem( 12, SerialOsc_GetName(), SerialOsc_ReceiveMessage, NULL );
  Osc_RegisterSubsystem( 13, IoOsc_GetName(), IoOsc_ReceiveMessage, NULL );
  Osc_RegisterSubsystem( 14, StepperOsc_GetName(), StepperOsc_ReceiveMessage, NULL );

  // Permit DIP switches to change the base IP settings
  NetworkCheck();

  // Starts the network up.  Will not return until a network is found...
  Network_SetActive( true );

  TaskCreate( BlinkTask, "Blink", 400, 0, 1 );
  TaskCreate( SerialTask, "Ser", 300, 0, 1 );

}

void SerialTask( void* p )
{
  (void)p;
  char* request = \
    "GET /auto/rss_full/RI/Kingston.xml?units=both HTTP/1.0\r\n\r\n";
  char *loading_msg = "Refreshing RSS Feed...";
  void* sock;
  int msg_index;
  char msg[MSG_MAX];

  Debug(0, "Setting up Serial interface\n");
  Serial_SetActive(1);
  Serial_SetBaud(9600);
  Serial_SetHardwareHandshake(0);
  Serial_SetBits(8);
  Serial_SetStopBits(1);
  Serial_SetParity(0);
  Sleep(1000);
  Debug(0, "Starting Serial loop\n");

  while (true) {
    char s[33];
    char *marker = "ion>";
    int m = 0;
    int in_closing_tag = 0;
    int count;
    msg_index = 0;

    Serial_SetChar(254); // attn
    Serial_SetChar(1);   // cls
    Serial_Write((uchar*) loading_msg, strlen(loading_msg), 2000);
    Debug(0, "Connecting...\n");

    sock = Socket(IP_ADDRESS(104,174,243,64), 80); // rss.wunderground.com
    SocketWrite(sock, request, strlen(request));
    Debug(0, "Wrote to socket.\n");
    while ((count = SocketRead(sock, s, 32)) != 0) {
      Debug(0, "Read another chunk.\n");
      // Find and display the forecast
      int i;   
      for (i = 0; i < count; i++) {
        if (m == 4) { // match (<descript)ion>
          Debug(0, "m==4\n");
          if (s[i] == '<') { // start of the closing </description> tag
            Debug(0, "Left Description.\n");
            in_closing_tag = 1; 
            m = 0;
          } else {  // we're in the body of the description
            if (msg_index >= MSG_MAX) {
              Debug(0, "Out of space in the message buffer.");
	        } else if (s[i] >= ' ' && s[i] <= 127) { // skip high/low characters
              msg[msg_index++] = s[i];
            } else if (s[i] == '\n') {               // turn \n's into spaces
              msg[msg_index++] = ' ';
            }        
          }
        } else if (s[i] == marker[m] && m < 4) { 
          Debug(0, "s[i] == marker[m] && m < 4\n");
          m++;
          if (m == 4) {
            if (in_closing_tag) {
              m = 0;
              in_closing_tag = 0;
            } else {
              Debug(0, "Entered Description.\n");
              if (msg_index+1 >= MSG_MAX) {
                Debug(0, "Out of space in the message buffer.");
	          } else {
                msg[msg_index++] =   1; // cls            
	          }
            }
          }
        } else {
          Debug(0, "else");
          m = 0;
        }
      }
    }  
    Debug(0, "Closing socket.\n");
    SocketClose(sock);
    
    // Display the weather several times
    int j;
    for (j = 0; j < 10; j++) { 
      int chars_written = 0;
      int i;
      for (i = 0; i < msg_index; i++) {

        if (msg[i] == 1) {
          Sleep(2500); // pause before sending special character
          Serial_SetChar(254); // attn
          Serial_SetChar(1);   // cls
	      chars_written = 0;

	    } else if (msg[i] == ' ') { 
          if (chars_written == 0) { 
            //skip leading space
	      } else {
            Serial_SetChar(msg[i]);
	        chars_written++;
	      } 
	    } else if (msg[i] > ' ' && msg[i] <= 127) {
          Serial_SetChar(msg[i]);
          chars_written++;
          Sleep(125);
        }

        if (chars_written == 32) {
           Sleep(750);
           Serial_SetChar(254); // attn
           Serial_SetChar(1);   // cls
           chars_written = 0;
        }

      }
    }
    Sleep(2500);
  }
}

void BlinkTask( void* p )
{
 (void)p;
  Led_SetState( 1 );
  Sleep( 1000 );

  while ( true )
  {
    Led_SetState( 0 );
    Sleep( 900 );
    Led_SetState( 1 );
    Sleep( 10 );
  }
}

// Make sure the network settings are OK
void NetworkCheck()
{
  Network_SetAddress( MY_IP );
  Network_SetMask( 255, 255, 255, 0 );
  Network_SetGateway( GATEWAY );
  Network_SetValid( 1 );
}
