func TestConnectionProcessor(t *testing.T) {
	Convey("Connection Processor", t, func() {
		physics := processor.DefaultPhysics()
		physics.TurnCommandModifier = 1.0
		physics.AccelerationCommandModifier = 1.0
		conn_processor := processor.ConnectCommandProcessor{Physics: &physics}

		c := cmd.NewConnect("abc123")
		c2 := cmd.NewConnect("abc")
		c.UserId = "abc123"
		c2.UserId = "abc"

		connect := cmd.GameCommand(&c)
		connect2 := cmd.GameCommand(&c2)

		game_state := physics.NewGameState()

		So(len(game_state.Vehicles), ShouldEqual, 0)

		conn_processor.Run(&game_state, connect)
		So(len(game_state.Vehicles), ShouldEqual, 1)

		conn_processor.Run(&game_state, connect)
		So(len(game_state.Vehicles), ShouldEqual, 1)

		conn_processor.Run(&game_state, connect2)
		So(len(game_state.Vehicles), ShouldEqual, 2)
	})
}
func TestCommandConsumption(t *testing.T) {
	physics := processor.DefaultPhysics()
	current_state := physics.NewGameState()
	response_channel := make(chan state.StateResponse, 100)

	physics.TurnCommandModifier = 1.0
	physics.AccelerationCommandModifier = 1.0
	factory := processor.NewFactory(&physics)

	manager := NewManager(current_state, response_channel, &factory)

	Convey("Pause", t, func() {
		manager.Pause()
		So(manager.IsPaused(), ShouldEqual, true)
	})

	Convey("AddCommand", t, func() {
		So(len(manager.commandsToProcess), ShouldEqual, 0)
		connect := cmd.NewConnect("tester")
		gamecommand := cmd.GameCommand(&connect)
		manager.AddCommand(gamecommand)
		So(len(manager.commandsToProcess), ShouldEqual, 1)
	})

	Convey("Removed On tick", t, func() {
		So(len(manager.commandsToProcess), ShouldEqual, 1)
		manager.tick()
		So(len(manager.commandsToProcess), ShouldEqual, 0)
	})

}
func TestProcessorFactory(t *testing.T) {
	Convey("ProcessorFactory", t, func() {
		physics := processor.DefaultPhysics()
		physics.TurnCommandModifier = 1.0
		physics.AccelerationCommandModifier = 1.0
		factory := processor.NewFactory(&physics)

		t := cmd.NewTurn(1)
		t_comm := cmd.GameCommand(&t)
		turn_cp := factory.GetCommandProcessor(&t_comm)
		So(turn_cp, ShouldHaveSameTypeAs, &processor.TurnCommandProcessor{Physics: &physics})

		a := cmd.NewAcceleration(1)
		a_comm := cmd.GameCommand(&a)
		acceleration_cp := factory.GetCommandProcessor(&a_comm)
		So(acceleration_cp, ShouldHaveSameTypeAs, &processor.AccelerationCommandProcessor{Physics: &physics})

		c := cmd.NewConnect("test")
		c_comm := cmd.GameCommand(&c)
		connect_cp := factory.GetCommandProcessor(&c_comm)
		So(connect_cp, ShouldHaveSameTypeAs, &processor.ConnectCommandProcessor{Physics: &physics})

		f := cmd.NewFire()
		f_comm := cmd.GameCommand(&f)
		fire_cp := factory.GetCommandProcessor(&f_comm)
		So(fire_cp, ShouldHaveSameTypeAs, &processor.FireCommandProcessor{Physics: &physics})

		b := cmd.BaseCommand{}
		b_comm := cmd.GameCommand(&b)
		base_cp := factory.GetCommandProcessor(&b_comm)
		So(base_cp, ShouldEqual, nil)
	})
}
func TestRoute(t *testing.T) {
	ack_channel := make(chan state.Ack, 100)
	state_channel := make(chan state.StateResponse, 100)

	physics := processor.DefaultPhysics()
	factory := processor.CommandProcessorFactory{Physics: &physics}

	gameManager := NewManager(physics.NewGameState(), state_channel, &factory)

	router := CommandRouter{Acks: ack_channel, GameManager: &gameManager}
	address, err := net.ResolveUDPAddr("udp", "127.0.0.1:8080")

	Convey("Route", t, func() {
		So(err, ShouldEqual, nil)
		turn := cmd.NewConnect("test")
		cmd := cmd.GameCommand(&turn)

		So(len(gameManager.commandsToProcess), ShouldEqual, 0)

		router.RouteCommand(&cmd, address)
		resp := <-ack_channel

		So(resp.Address, ShouldEqual, address)
		So(len(gameManager.commandsToProcess), ShouldEqual, 1)
	})
}
func TestConnection(t *testing.T) {

	ack_channel := make(chan state.Ack, 100)
	state_channel := make(chan state.StateResponse, 5)
	physics := processor.DefaultPhysics()
	factory := processor.NewFactory(&physics)
	manager := game.NewManager(physics.NewGameState(), state_channel, &factory)
	router := game.CommandRouter{GameManager: &manager, Acks: ack_channel}
	go manager.Start()

	reciever := network.UdpReceiver{
		Router:     router,
		Acks:       ack_channel,
		Responses:  state_channel,
		PortNumber: ":10002"}

	reciever.Run()
	conn, err := net.DialTimeout("udp", "127.0.0.1:10002", 1*time.Second)
	Convey("Test connect", t, func() {
		So(err, ShouldEqual, nil)
		So(conn, ShouldNotEqual, nil)
	})

	Convey("Test Connect command", t, func() {
		a := cmd.NewConnect("Dan")
		a.UniqueId = "abc123"
		message, err := json.Marshal(a)

		So(err, ShouldEqual, nil)

		i, error := conn.Write(message)

		So(i, ShouldBeGreaterThan, 0)
		So(error, ShouldEqual, nil)
	})

	Convey("Test State Responder", t, func() {
		reciever.Responses <- state.StateResponse{State: physics.NewGameState()}
		response := make([]byte, 2048)
		// read response
		conn.SetDeadline(time.Now().Add(2 * time.Second))
		n, err := bufio.NewReader(conn).Read(response)
		So(err, ShouldEqual, nil)
		So(string(response[:n]), ShouldEqual, "abc123")

		conn.SetDeadline(time.Now().Add(2 * time.Second))
		n, err = bufio.NewReader(conn).Read(response)
		So(err, ShouldEqual, nil)

		encoder := encoder.JsonEncoderDecoder{}

		_, encode_error := encoder.Decode(response[:n])
		So(encode_error, ShouldEqual, nil)

	})

}
func TestConnect(t *testing.T) {
	Convey("Connect Command", t, func() {
		connect := cmd.NewConnect("myname")
		So(connect.UniqueId, ShouldEqual, "")
		So(connect.Subtype, ShouldEqual, cmd.Connect)
		So(connect.Type, ShouldEqual, cmd.Post)
		So(connect.Value, ShouldEqual, "myname")
		So(connect.Type, ShouldEqual, connect.Command().Type)
		So(connect.Subtype, ShouldEqual, connect.Command().Subtype)
		So(connect.UniqueId, ShouldEqual, connect.Command().UniqueId)
	})
}
func main() {
	var waiter sync.WaitGroup
	waiter.Add(1)
	//get connection to host and sets a timeout for connection when completed
	conn, err := net.DialTimeout("udp", host, 1*time.Second)

	// start goroutine  to listen for messages
	go responsePrinter(conn)

	for i := 0; i < 12; i++ {

		if err != nil {
			log.Print(err)
		} else {
			var message []byte

			// creates unique identifier to be returned for the packet ack
			uuid := uuid.NewUUID().String()
			if i == 0 {
				a := cmd.NewConnect("Dan")
				a.UniqueId = uuid
				message, err = json.Marshal(a)
			} else {
				// randomly select between commands
				randType := rand.Intn(2)
				if randType == 0 {
					a := cmd.NewTurn(.5)
					a.UniqueId = uuid
					message, err = json.Marshal(a)
				}
				if randType == 1 {
					a := cmd.NewAcceleration(.5)
					a.UniqueId = uuid
					message, err = json.Marshal(a)
				}
			}

			//send the message
			conn.Write(message)

			time.Sleep(1 * time.Millisecond)
		}
	}
	waiter.Wait()

	//clean up connection
	conn.Close()

}
func TestDecodeConnect(t *testing.T) {
	Convey("Connect Decode", t, func() {
		formatter := encoder.JsonEncoderDecoder{Tag: "DecodeTest"}

		data := cmd.NewConnect("myname")
		data.UniqueId = "ABC123"
		buffer, error := json.Marshal(data)

		command, err := formatter.Decode(buffer)

		turn := command.(*cmd.ConnectCommand)

		So(error, ShouldEqual, nil)
		So(turn.Command().Type, ShouldEqual, cmd.Post)
		So(turn.Command().Subtype, ShouldEqual, cmd.Connect)
		So(err, ShouldEqual, nil)
		So(turn.Value, ShouldEqual, "myname")
		So(turn.Command().UniqueId, ShouldEqual, "ABC123")
	})
}
func TestFireProcessor(t *testing.T) {
	Convey("Fire Processor", t, func() {
		physics := processor.DefaultPhysics()
		physics.TurnCommandModifier = 1.0
		physics.AccelerationCommandModifier = 1.0
		fireProcessor := processor.FireCommandProcessor{Physics: &physics}
		connectProcessor := processor.ConnectCommandProcessor{Physics: &physics}

		fireCommand := cmd.NewFire()
		fireCommand.UserId = "abc"

		connectCommand := cmd.NewConnect("abc")
		connectCommand.UserId = "abc"

		fire := cmd.GameCommand(&fireCommand)
		connect := cmd.GameCommand(&connectCommand)

		game_state := physics.NewGameState()
		So(len(game_state.Bullets), ShouldEqual, 0)
		So(len(game_state.Vehicles), ShouldEqual, 0)

		connectProcessor.Run(&game_state, connect)
		So(len(game_state.Vehicles), ShouldEqual, 1)

		fireProcessor.Run(&game_state, fire)
		So(len(game_state.Bullets), ShouldEqual, 1)

		badFireCommand := cmd.NewFire()
		badFireCommand.UserId = "nobody"
		badFire := cmd.GameCommand(&badFireCommand)

		fireProcessor.Run(&game_state, badFire)
		So(len(game_state.Bullets), ShouldEqual, 1)

	})
}