
// SPDX-License-Identifier: CC-BY-NC-SA-4.0
//
// Copyright (C) 2026 Bit by Bit Signal Processing LLC (https://bxbsp.com)
//
// This work is placed under the "Creative Commons Attribution
// NonCommercial ShareAlike 4.0 International" license, known
// by the shortened acronym "CC-BY-NC-SA-4.0".
//
// This work is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// A CC-BY-NC-SA-4.0 license allows you to use this work for
// noncommercial purposes so long as attribution is made to the
// original author.  Modified versions of this work may be distributed,
// but only under the same license.  For further details, see the
// Creative Commons License "CC-BY-NC-SA-4.0".
//
// You should have received a copy of the CC-BY-NC-SA-4.0 license
// along with this work. If not, see
// <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
//

#include "web_interface.hh"
//#include "all_svgs.hh"


void set_up_inactive_page(web_socket_connection* wsc)
{
  uint32_t color = 0xFF4040FF;  // RGBA

  wsc->ws_command_font( "Helvetica", 40);

  wsc->ws_command_set_layer_visibility(7);  // 0, 1, 2 all visible

  for(int i=0; i<WS_MAX_LAYERS; i++)
    wsc->ws_command_clear_layer(i);

  wsc->ws_command_set_current_layer(0);

  wsc->ws_command_font( "Helvetica", 40);

  wsc->ws_command_text(color, DRAW_TEXT_X_CENTER|DRAW_TEXT_Y_CENTER|DRAW_TEXT_ROTATE_0, wsc->width/2, wsc->height/2, "INACTIVE");
}

void set_up_active_page(web_socket_connection* wsc)
{
  uint32_t color = 0x404040FF;  // RGBA

  for(int i=0; i<WS_MAX_LAYERS; i++)
    wsc->ws_command_clear_layer(i);

  wsc->ws_command_font( "Helvetica", 20);

  wsc->ws_command_set_layer_visibility(7);  // 0, 1, 2 all visible
  
  wsc->ws_command_set_current_layer(0);

#ifdef NOTDEF
  wsc->ws_command_svg( (const char*) BxB_web_svg,  //  data
		       100,         //  offset_x
		       300,         //  offset_y
		       300,         //  draw_width
		       300);        //  draw_height
#endif
  
  //wsc->ws_command_text_size("TEST");
  //wsc->ws_command_text_size("TESTTEST");
  int a_textwidth = 0;
  int a_textheight = 0;
  int b_textwidth = 0;
  int b_textheight = 0;
  
  wsc->get_text_size("TEST", a_textwidth, a_textheight);

  printf("Got a text size for \"TEST\" of %dx%d.\n", a_textwidth, a_textheight);

  
  wsc->get_text_size("TESTTEST", b_textwidth, b_textheight);
  
  printf("In 20pt Helvetica, ext size of \"TEST\" is %dx%d, size of \"TESTTEST\" is %dx%d\n", a_textwidth, a_textheight, b_textwidth, b_textheight);
  
  wsc->ws_command_font( "Helvetica", 40);
  
  wsc->get_text_size("TEST", a_textwidth, a_textheight);
  wsc->get_text_size("TESTTEST", b_textwidth, b_textheight);
  
  printf("In 40pt Helvetica, ext size of \"TEST\" is %dx%d, size of \"TESTTEST\" is %dx%d\n", a_textwidth, a_textheight, b_textwidth, b_textheight);
  
  //wsc->ws_command_text_size("TEST");
  //wsc->ws_command_text_size("TESTTEST");
  
  // Layer 0: Static, demonstrating a layer under
  // Layer 1: Dynamic
  // Layer 2: Static, demonstrating a layer over
  // Layer 31: Scratch, for redrawing the dynamic
  
  
#ifdef NOTDEF
  wsc->ws_command_svg_from_web( "/BxB.svg",  //  url
				100,         //  offset_x
				300,         //  offset_y
				300,         //  draw_width
				300);        //  draw_height
#endif
  
  
  // To go under the graph data tests.
  wsc->ws_command_rectangle(0x00FF00FF, 500, 700, 500 + 300, 700 + 200);
  wsc->ws_command_rectangle(0x00FF00FF, 800, 300, 800 + 200, 300 + 300);
  
  /*
    wsc->ws_command_svg( "<svg width=\"500\" height=\"400\" xmlns=\"http://www.w3.org/2000/svg\"><!-- Created with Method Draw - http://github.com/duopixel/Method-Draw/ --><g><title>background</title><rect fill=\"#fff\" id=\"canvas_background\" height=\"402\" width=\"502\" y=\"-1\" x=\"-1\"/><g display=\"none\" overflow=\"visible\" y=\"0\" x=\"0\" height=\"100%\" width=\"100%\" id=\"canvasGrid\"><rect fill=\"url(#gridpattern)\" stroke-width=\"0\" y=\"0\" x=\"0\" height=\"100%\" width=\"100%\"/></g></g><g><title>Layer 1</title><path id=\"svg_1\" d=\"m118,242l64,-153l63,157c0,0 45,-71 49,-68c4,3 11,146 12,146c1,0 -173,-7 -173,-7c0,0 -61,-72 -61,-72c0,0 110,-156 46,-3z\" fill-opacity=\"0.7\" stroke-width=\"2\" stroke=\"#995757\" fill=\"#995757\"/></g></svg>",  //  svg_data
    300,      //  offset_x
    500,      //  offset_y
    100,      //  draw_width
    100);     //  draw_height
  */
  
  wsc->ws_command_svg("<svg\n"
		      "   xmlns=\"http://www.w3.org/2000/svg\"\n"
		      "   viewBox=\"0 0 50 50\">\n"
		      "  <circle cx=\"25\" cy=\"25\" r=\"22\" stroke=\"red\" fill=\"green\" stroke-width=\"5\"/>\n"
		      "</svg>\n",
		      100,      //  offset_x
		      600,      //  offset_y
		      100,      //  draw_width
		      100);     //  draw_height
  
  uint32_t colors[MAX_COLORS] = { 0xFFFFFFFF, 0xFF0000FF, 0x00FF00FF, 0x0000FFFF }; 
  wsc->ws_command_multicolored_text(colors, 0, DRAW_TEXT_X_LEFT|DRAW_TEXT_Y_BOTTOM|DRAW_TEXT_ROTATE_0, 100, 100, "Layer 0 " "\x0B" "Color 1 " "\x0C" "Color 2 " "\x0D" "Color 3");
  
  wsc->ws_command_set_current_layer(2);
  
  wsc->ws_command_text(color, DRAW_TEXT_X_LEFT|DRAW_TEXT_Y_BOTTOM|DRAW_TEXT_ROTATE_0, 100, 200, "Normal text on Layer 2 ");
  
#ifdef NOTDEF
  wsc->ws_command_svg_from_web( "/BxB.svg",  //  url
				450,         //  offset_x
				300,         //  offset_y
				300,         //  draw_width
				300);        //  draw_height
#endif
  
#ifdef NOTDEF
  wsc->ws_command_svg( (const char*)BxB_web_svg,  //  data
		       450,         //  offset_x
		       300,         //  offset_y
		       300,         //  draw_width
		       300);        //  draw_height
#endif  
  
  wsc->ws_command_svg("<svg\n"
		      "   xmlns=\"http://www.w3.org/2000/svg\"\n"
		      "   viewBox=\"0 0 50 50\">\n"
		      "  <circle cx=\"25\" cy=\"25\" r=\"22\" stroke=\"blue\" fill=\"teal\" stroke-width=\"5\"/>\n"
		      "</svg>\n",
		      170.7,      //  offset_x
		      670.7,      //  offset_y
		      100,      //  draw_width
		      100);     //  draw_height
  
  data_point data_pts[] =
    {
     { 0,0 },
     { 0.1, 0.5 },
     { 0.2, 0.3 },
     { 0.2, 0.2 },
     { -0.1, -0.1 },
     { 0.2,  0.3 }
    };
  int num_data_points = sizeof(data_pts) / sizeof(data_pts[0]);
  
  wsc->ws_command_graph_data(0x000000FF,       // color
			     num_data_points,  // num_points
			     -11,              // x_start
			     3,                // x_step
			     -12,              // x_at_left
			     20,               // x_at_right
			     -0.2,             // y_at_bottom
			     0.29,             // y_at_top
			     500,              // x_offset
			     700,              // y_offset
			     300,              // width
			     200,              // height
			     data_pts);        // y_data
  
  wsc->ws_command_graph_data(0xFF00FFFF,       // color
			     num_data_points,  // num_points
			     -11,              // x_start
			     3,                // x_step
			     -12,              // x_at_left
			     20,               // x_at_right
			     -0.2,             // y_at_bottom
			     0.29,             // y_at_top
			     800,              // x_offset
			     300,              // y_offset
			     200,              // width
			     300,              // height
			     data_pts);        // y_data
  
  
  wsc->ws_command_set_current_layer(31);
  color = 0x008080FF;  // RGBA
  
#ifdef NOTDEF
  wsc->ws_command_beep(BEEP_ID_ENTRY_ACCEPTED);
  sleep(1);
  wsc->ws_command_beep(BEEP_ID_ENTRY_ACCEPTED);
  sleep(1);
  wsc->ws_command_beep(BEEP_ID_ENTRY_ACCEPTED);
#endif

}



int main()
{
  web_interface* wif = new web_interface(80);
  float rect_width = 20;
  uint32_t color = 0x404040FF;  // RGBA
  int shape = 0;

  int last_num_connections = 0;
  int last_next_connection_ID = 0;

  web_socket_connection* wsc_active = 0;

  for(;;)
    {
      wif->allow_deletions();
      usleep(100);
      wif->disallow_deletions();

      ListElement<web_socket_connection> * le = wif->connections.last();
      if(!le)
	continue;

      wsc_active = le->data();

      if(!wsc_active->connected)
	continue;
      
      if(last_next_connection_ID!=wif->next_connection_ID || wif->current_num_connections() != last_num_connections)
	{
	  if(last_next_connection_ID!=wif->next_connection_ID)
	    printf("\nMain program got a new web connection.\n");
	  else
	    printf("\nMain program lost a web connection.\n");
	  
	  last_num_connections = wif->current_num_connections();
	  last_next_connection_ID = wif->next_connection_ID;
	  
	  //printf("******************** Setting up active page.\n");
	  set_up_active_page(wsc_active);
	  //printf("******************** Done Setting up active page.\n");
	  
	  for(le = le->previous(); le; le = le->previous())
	    {
	      web_socket_connection* wsc = le->data();

	      set_up_inactive_page(wsc);
	    }
	  //printf("******************** Done Setting up inactive pages.\n");
	}


      //
      // Remove all packets from inactive web pages
      //
      for(ListElement<web_socket_connection> * le = wif->connections.last(); le; le = le->previous())
	{
	  web_socket_connection* wsc = le->data();
	  
	  if(wsc!=wsc_active)
	    {
	      for(;;)
		{
		  bool have_event = wsc->event_is_on_event_queue();
		  if(!have_event)
		    break;
		  wsc->event_queue_out_position = (wsc->event_queue_out_position == WS_EVENT_QUEUE_NUM_ITEMS-1) ? 0 : wsc->event_queue_out_position + 1;
		}
	    }
	}
      
      
      if(wsc_active)
	{
	  bool have_event = wsc_active->event_is_on_event_queue();
	  
	  if(have_event)
	    {
	      ws_event_packet*  packet        = (ws_event_packet*)wsc_active->event_queue[wsc_active->event_queue_out_position];
	      
	      switch(packet->type)
		{
		case WS_EVENT_BUTTON_DOWN:
		  {
		    auto event = (ws_event_button_down*)packet;

		    if(event->button==1)
		      {
			color = ( (color==0x008080FF) ? 0x00FF00FF :
				  (color==0x00FF00FF) ? 0x0000FFFF :
				  (color==0x0000FFFF) ? 0xFF0000FF :
				  /**/                  0x008080FF );
		      }
		    else if(event->button==2)
		      {
			shape++;
		      }
		    
		    //printf("Event BUTTON Down, x=%d, y=%d, button=%d\n", event->x, event->y, event->button);

		    {
		      static int beep_id = 1;

		      wsc_active->ws_command_beep(beep_id);

		      beep_id = (beep_id % 3) + 1;
		    }
		  }
		  break;
		  
		case WS_EVENT_BUTTON_UP:
		  {
		    //auto event = (ws_event_button_up*)packet;
		    
		    //printf("Event BUTTON Up, x=%d, y=%d, button=%d\n", event->x, event->y, event->button);
		  }
		  break;
		  
		case WS_EVENT_MOUSE_MOVE:
		  {
		    auto event = (ws_event_mouse_move*)packet;
		    
		    //printf("Event MOUSE MOVE, x=%d, y=%d\n", event->x, event->y);
		    
		    // Draw onto scratch
		    wsc_active->ws_command_set_current_layer(31);

		    int num_shapes = 31;
		    shape = shape % num_shapes;
		    if(shape==0)
		      wsc_active->ws_command_rectangle(color, event->x, event->y, event->x + rect_width, event->y + rect_width);
		    else if(shape==1)
		      wsc_active->ws_command_triangle(color, event->x, event->y, event->x, event->y + rect_width, event->x + rect_width*0.866, event->y + rect_width*0.5);
		    else if(shape==2)
		      wsc_active->ws_command_circle(color, event->x, event->y, rect_width/2);
		    else if(shape==3)
		      wsc_active->ws_command_line(color, rect_width/10.0, event->x, event->y, event->x + rect_width, event->y + rect_width);
		    else if(shape==4)
		      wsc_active->ws_command_text(color, DRAW_TEXT_X_LEFT|DRAW_TEXT_Y_BOTTOM|DRAW_TEXT_ROTATE_0, event->x, event->y, "TEXT X_LEFT Y_BOTTOM ROTATE_0");
		    else if(shape==5)
		      wsc_active->ws_command_text(color, DRAW_TEXT_X_CENTER|DRAW_TEXT_Y_BOTTOM|DRAW_TEXT_ROTATE_0, event->x, event->y, "TEXT X_CENTER Y_BOTTOM ROTATE_0");
		    else if(shape==6)
		      wsc_active->ws_command_text(color, DRAW_TEXT_X_RIGHT|DRAW_TEXT_Y_BOTTOM|DRAW_TEXT_ROTATE_0, event->x, event->y, "TEXT X_RIGHT Y_BOTTOM ROTATE_0");
		    else if(shape==7)
		      wsc_active->ws_command_text(color, DRAW_TEXT_X_LEFT|DRAW_TEXT_Y_CENTER|DRAW_TEXT_ROTATE_0, event->x, event->y, "TEXT X_LEFT Y_CENTER ROTATE_0");
		    else if(shape==8)
		      wsc_active->ws_command_text(color, DRAW_TEXT_X_CENTER|DRAW_TEXT_Y_CENTER|DRAW_TEXT_ROTATE_0, event->x, event->y, "TEXT X_CENTER Y_CENTER ROTATE_0");
		    else if(shape==9)
		      wsc_active->ws_command_text(color, DRAW_TEXT_X_RIGHT|DRAW_TEXT_Y_CENTER|DRAW_TEXT_ROTATE_0, event->x, event->y, "TEXT X_RIGHT Y_CENTER ROTATE_0");
		    else if(shape==10)
		      wsc_active->ws_command_text(color, DRAW_TEXT_X_LEFT|DRAW_TEXT_Y_TOP|DRAW_TEXT_ROTATE_0, event->x, event->y, "TEXT X_LEFT Y_TOP ROTATE_0");
		    else if(shape==11)
		      wsc_active->ws_command_text(color, DRAW_TEXT_X_CENTER|DRAW_TEXT_Y_TOP|DRAW_TEXT_ROTATE_0, event->x, event->y, "TEXT X_CENTER Y_TOP ROTATE_0");
		    else if(shape==12)
		      wsc_active->ws_command_text(color, DRAW_TEXT_X_RIGHT|DRAW_TEXT_Y_TOP|DRAW_TEXT_ROTATE_0, event->x, event->y, "TEXT X_RIGHT Y_TOP ROTATE_0");

		    else if(shape==13)
		      wsc_active->ws_command_text(color, DRAW_TEXT_X_LEFT|DRAW_TEXT_Y_BOTTOM|DRAW_TEXT_ROTATE_90_RIGHT, event->x, event->y, "TEXT X_LEFT Y_BOTTOM ROTATE_90_RIGHT");
		    else if(shape==14)
		      wsc_active->ws_command_text(color, DRAW_TEXT_X_CENTER|DRAW_TEXT_Y_BOTTOM|DRAW_TEXT_ROTATE_90_RIGHT, event->x, event->y, "TEXT X_CENTER Y_BOTTOM ROTATE_90_RIGHT");
		    else if(shape==15)
		      wsc_active->ws_command_text(color, DRAW_TEXT_X_RIGHT|DRAW_TEXT_Y_BOTTOM|DRAW_TEXT_ROTATE_90_RIGHT, event->x, event->y, "TEXT X_RIGHT Y_BOTTOM ROTATE_90_RIGHT");
		    else if(shape==16)
		      wsc_active->ws_command_text(color, DRAW_TEXT_X_LEFT|DRAW_TEXT_Y_CENTER|DRAW_TEXT_ROTATE_90_RIGHT, event->x, event->y, "TEXT X_LEFT Y_CENTER ROTATE_90_RIGHT");
		    else if(shape==17)
		      wsc_active->ws_command_text(color, DRAW_TEXT_X_CENTER|DRAW_TEXT_Y_CENTER|DRAW_TEXT_ROTATE_90_RIGHT, event->x, event->y, "TEXT X_CENTER Y_CENTER ROTATE_90_RIGHT");
		    else if(shape==18)
		      wsc_active->ws_command_text(color, DRAW_TEXT_X_RIGHT|DRAW_TEXT_Y_CENTER|DRAW_TEXT_ROTATE_90_RIGHT, event->x, event->y, "TEXT X_RIGHT Y_CENTER ROTATE_90_RIGHT");
		    else if(shape==19)
		      wsc_active->ws_command_text(color, DRAW_TEXT_X_LEFT|DRAW_TEXT_Y_TOP|DRAW_TEXT_ROTATE_90_RIGHT, event->x, event->y, "TEXT X_LEFT Y_TOP ROTATE_90_RIGHT");
		    else if(shape==20)
		      wsc_active->ws_command_text(color, DRAW_TEXT_X_CENTER|DRAW_TEXT_Y_TOP|DRAW_TEXT_ROTATE_90_RIGHT, event->x, event->y, "TEXT X_CENTER Y_TOP ROTATE_90_RIGHT");
		    else if(shape==21)
		      wsc_active->ws_command_text(color, DRAW_TEXT_X_RIGHT|DRAW_TEXT_Y_TOP|DRAW_TEXT_ROTATE_90_RIGHT, event->x, event->y, "TEXT X_RIGHT Y_TOP ROTATE_90_RIGHT");

		    else if(shape==22)
		      wsc_active->ws_command_text(color, DRAW_TEXT_X_LEFT|DRAW_TEXT_Y_BOTTOM|DRAW_TEXT_ROTATE_90_LEFT, event->x, event->y, "TEXT X_LEFT Y_BOTTOM ROTATE_90_LEFT");
		    else if(shape==23)
		      wsc_active->ws_command_text(color, DRAW_TEXT_X_CENTER|DRAW_TEXT_Y_BOTTOM|DRAW_TEXT_ROTATE_90_LEFT, event->x, event->y, "TEXT X_CENTER Y_BOTTOM ROTATE_90_LEFT");
		    else if(shape==24)
		      wsc_active->ws_command_text(color, DRAW_TEXT_X_RIGHT|DRAW_TEXT_Y_BOTTOM|DRAW_TEXT_ROTATE_90_LEFT, event->x, event->y, "TEXT X_RIGHT Y_BOTTOM ROTATE_90_LEFT");
		    else if(shape==25)
		      wsc_active->ws_command_text(color, DRAW_TEXT_X_LEFT|DRAW_TEXT_Y_CENTER|DRAW_TEXT_ROTATE_90_LEFT, event->x, event->y, "TEXT X_LEFT Y_CENTER ROTATE_90_LEFT");
		    else if(shape==26)
		      wsc_active->ws_command_text(color, DRAW_TEXT_X_CENTER|DRAW_TEXT_Y_CENTER|DRAW_TEXT_ROTATE_90_LEFT, event->x, event->y, "TEXT X_CENTER Y_CENTER ROTATE_90_LEFT");
		    else if(shape==27)
		      wsc_active->ws_command_text(color, DRAW_TEXT_X_RIGHT|DRAW_TEXT_Y_CENTER|DRAW_TEXT_ROTATE_90_LEFT, event->x, event->y, "TEXT X_RIGHT Y_CENTER ROTATE_90_LEFT");
		    else if(shape==28)
		      wsc_active->ws_command_text(color, DRAW_TEXT_X_LEFT|DRAW_TEXT_Y_TOP|DRAW_TEXT_ROTATE_90_LEFT, event->x, event->y, "TEXT X_LEFT Y_TOP ROTATE_90_LEFT");
		    else if(shape==29)
		      wsc_active->ws_command_text(color, DRAW_TEXT_X_CENTER|DRAW_TEXT_Y_TOP|DRAW_TEXT_ROTATE_90_LEFT, event->x, event->y, "TEXT X_CENTER Y_TOP ROTATE_90_LEFT");
		    else if(shape==30)
		      wsc_active->ws_command_text(color, DRAW_TEXT_X_RIGHT|DRAW_TEXT_Y_TOP|DRAW_TEXT_ROTATE_90_LEFT, event->x, event->y, "TEXT X_RIGHT Y_TOP ROTATE_90_LEFT");


		    wsc_active->ws_command_move_layer_to_layer(31, 1);
		  }
		  break;
		  
		case WS_EVENT_WHEEL:
		  {
		    auto event = (ws_event_wheel*)packet;

		    if(event->steps>0)
		      rect_width *= 1.05;
		    else
		      rect_width *= (1.0/1.05);
		    
		    wsc_active->ws_command_font( "Helvetica", rect_width);
		      
		    //printf("Event WHEEL, x=%d, y=%d, steps=%d\n", event->x, event->y, event->steps);
		  }		
		  break;
		  
		case WS_EVENT_RESIZE:
		  {
		    auto event = (ws_event_resize*)packet;
		    
		    printf("Event RESIZE, width=%d, height=%d\n", event->width, event->height);
		  }
		  break;
		  
		case WS_EVENT_DEBUG_TEXT:
		  {
		    auto event = (ws_event_debug_text*)packet;
		    
		    printf("Event DEBUG_TEXT, text=\"%s\"\n", event->text);
		  }		
		  break;
		  
		case WS_EVENT_TEXT_SIZE:
		  {
		    auto event = (ws_event_text_size*)packet;
		    
		    printf("Event TEXT_SIZE, width=%f, height=%f\n", event->width, event->height);
		  }
		  break;
		  
		default:
		  printf("************* Got bad packet of type %d, length %d\n", packet->type, packet->length); 
		  break;
		}
	      
	      wsc_active->event_queue_out_position = (wsc_active->event_queue_out_position == WS_EVENT_QUEUE_NUM_ITEMS-1) ? 0 : wsc_active->event_queue_out_position + 1;
	    }
	}
    }
  
  return 0;
}
