// This example is the classic snake network test.  The snake is feed a steady
// diet of pkts and the pkts work themselves thru the snake segments and exit
// the tail.  Each snake segment is a TCP socket connection to a server.  The
// server echos pkts received back to the snake, and serves each segment on a
// different port.  (See server/main.go for server).
//
//                snake     |    server
//                          |
//            head ----->---|-->--+
//             seg a        |     |
//                    +---<-|--<--+
//                    |     |
//                    +-->--|-->--+
//             seg b        |     |
//                    +---<-|--<--+
//                    |     |
//                    +-->--|-->--+
//             seg c        |     |
//                    +---<-|--<--+
//                    |     |
//                    +-->--|-->--+
//              ...         |     |
//                    +---<-|--<--+
//                    |     |
//                    +-->--|-->--+
//             seg n        |     |
//            tail -------<-|--<--+
//                          |

// The snake segments are linked by channels and each segment is run as a go
// func.  This forces segments to connect and run concurrently, which is a good
// test of the underlying driver's ability to handle concurrent connections.

//go:build ninafw || wioterminal || comboat_fw

package main

import (
	_ "embed"
	"fmt"
	"log"
	"net"
	"strings"
	"time"
)

//go:embed main.go
var code string

var (
	server string = "10.0.0.100:8080"
)

func segment(in chan []byte, out chan []byte) {
	var buf [512]byte
	for {
		c, err := net.Dial("tcp", server)
		for ; err != nil; c, err = net.Dial("tcp", server) {
			println(err.Error())
			time.Sleep(5 * time.Second)
		}
		for {
			select {
			case msg := <-in:
				_, err := c.Write(msg)
				if err != nil {
					log.Fatal(err.Error())
				}
				time.Sleep(100 * time.Millisecond)
				n, err := c.Read(buf[:])
				if err != nil {
					log.Fatal(err.Error())
				}
				out <- buf[:n]
			}
		}
	}
}

func feedit(head chan []byte) {
	for i := 0; i < 100; i++ {
		head <- []byte(fmt.Sprintf("\n---%d---\n", i))
		for _, line := range strings.Split(code, "\n") {
			if len(line) == 0 {
				line = " "
			}
			head <- []byte(line)
		}
	}
}

var head = make(chan []byte)
var a = make(chan []byte)
var b = make(chan []byte)
var c = make(chan []byte)
var d = make(chan []byte)
var e = make(chan []byte)
var f = make(chan []byte)
var tail = make(chan []byte)

func main() {

	// The snake
	go segment(head, a)
	go segment(a, b)
	go segment(b, c)
	go segment(c, d)
	go segment(d, e)
	go segment(e, f)
	go segment(f, tail)

	go feedit(head)

	for {
		select {
		case msg := <-tail:
			println(string(msg))
		}
	}
}
