Merge "Implemented soft reset functionality to debug mode. Hard reset to follow."
diff --git a/go/src/hearts/img/uistate/uistate.go b/go/src/hearts/img/uistate/uistate.go
index 74ccb18..53f7fd3 100644
--- a/go/src/hearts/img/uistate/uistate.go
+++ b/go/src/hearts/img/uistate/uistate.go
@@ -109,6 +109,7 @@
 	AnimChans        []chan bool                    // keeps track of all 'quit' channels in animations so their goroutines can be stopped
 	SGChan           chan bool                      // pass in a bool to stop advertising the syncgroup
 	ScanChan         chan bool                      // pass in a bool to stop scanning for syncgroups
+	GameChan         chan bool                      // pass in a bool to stop receiving updates from the current game
 	DiscGroups       map[string]*DiscStruct         // contains a set of addresses and game start data for each advertised game found
 	M                sync.Mutex
 }
diff --git a/go/src/hearts/img/view/view.go b/go/src/hearts/img/view/view.go
index 9169a6b..5600864 100644
--- a/go/src/hearts/img/view/view.go
+++ b/go/src/hearts/img/view/view.go
@@ -1289,6 +1289,9 @@
 	debugPassImage := u.Texs["Clubs-2.png"]
 	debugPassPos := coords.MakeVec(u.WindowSize.X-2*buttonDim.X, u.WindowSize.Y-buttonDim.Y)
 	u.Buttons["hand"] = texture.MakeImgWithoutAlt(debugPassImage, debugPassPos, buttonDim, u)
+	debugRestartImage := u.Texs["Restart.png"]
+	debugRestartPos := coords.MakeVec(u.WindowSize.X-3*buttonDim.X, u.WindowSize.Y-buttonDim.Y)
+	u.Buttons["restart"] = texture.MakeImgWithoutAlt(debugRestartImage, debugRestartPos, buttonDim, u)
 }
 
 // Helper function that returns the largest int in a non-negative int array (not index of largest int)
diff --git a/go/src/hearts/logic/table/table.go b/go/src/hearts/logic/table/table.go
index 4eece8a..a8a8d6b 100644
--- a/go/src/hearts/logic/table/table.go
+++ b/go/src/hearts/logic/table/table.go
@@ -37,7 +37,7 @@
 		heartsBroken: false,
 		firstTrick:   true,
 		winCondition: 100,
-		dir:          direction.None,
+		dir:          direction.Right,
 	}
 }
 
@@ -395,6 +395,7 @@
 		p.ResetTricks()
 		p.ResetScore()
 	}
+	t.trick = make([]*card.Card, len(t.players))
 	t.NewRound()
 	t.dir = direction.Right
 }
diff --git a/go/src/hearts/sync/client.go b/go/src/hearts/sync/client.go
index 63d6442..c7f4194 100644
--- a/go/src/hearts/sync/client.go
+++ b/go/src/hearts/sync/client.go
@@ -109,7 +109,7 @@
 	} else {
 		fmt.Println("Syncgroup joined")
 		if u.LogSG != logName {
-			resetGame(logName, false, u)
+			ResetGame(logName, false, u)
 		}
 		return true
 	}
diff --git a/go/src/hearts/sync/server.go b/go/src/hearts/sync/server.go
index 38ed5f4..68b1147 100644
--- a/go/src/hearts/sync/server.go
+++ b/go/src/hearts/sync/server.go
@@ -169,7 +169,7 @@
 	} else {
 		fmt.Println("Syncgroup created")
 		if logSGName != u.LogSG {
-			resetGame(logSGName, true, u)
+			ResetGame(logSGName, true, u)
 		}
 		return string(value), logSGName
 	}
@@ -218,14 +218,25 @@
 	}
 }
 
-func resetGame(logName string, creator bool, u *uistate.UIState) {
+func ResetGame(logName string, creator bool, u *uistate.UIState) {
+	u.M.Lock()
+	defer u.M.Unlock()
+	go sendTrueIfExists(u.GameChan)
 	u.PlayerData = make(map[int]int)
 	u.CurPlayerIndex = -1
 	u.LogSG = logName
+	u.CurTable.NewGame()
 	if !creator {
 		tmp := strings.Split(logName, "-")
 		gameID, _ := strconv.Atoi(tmp[len(tmp)-1])
 		u.GameID = gameID
 	}
-	go UpdateGame(u)
+	u.GameChan = make(chan bool)
+	go UpdateGame(u.GameChan, u)
+}
+
+func sendTrueIfExists(ch chan bool) {
+	if ch != nil {
+		ch <- true
+	}
 }
diff --git a/go/src/hearts/sync/watch.go b/go/src/hearts/sync/watch.go
index a52b82d..877fce5 100644
--- a/go/src/hearts/sync/watch.go
+++ b/go/src/hearts/sync/watch.go
@@ -80,18 +80,43 @@
 	}
 }
 
-func UpdateGame(u *uistate.UIState) {
-	stream, err := WatchData(LogName, fmt.Sprintf("%d", u.GameID), u)
-	fmt.Println("STARTING WATCH FOR GAME", u.GameID)
+func UpdateGame(quit chan bool, u *uistate.UIState) {
+	file, err := os.OpenFile("/sdcard/test.txt", os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
 	if err != nil {
-		fmt.Println("WatchData error:", err)
-	}
-	file, err2 := os.OpenFile("/sdcard/test.txt", os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
-	if err2 != nil {
-		fmt.Println("err2:", err2)
+		fmt.Println("err:", err)
 	}
 	fmt.Fprintf(file, fmt.Sprintf("\n***NEW GAME: %d\n", u.GameID))
 	defer file.Close()
+	scanner := ScanData(LogName, fmt.Sprintf("%d", u.GameID), u)
+	m := make(map[string][]byte)
+	keys := make([]string, 0)
+	for scanner.Advance() {
+		k := scanner.Key()
+		var v []byte
+		if err := scanner.Value(&v); err != nil {
+			fmt.Println("Value error:", err)
+		}
+		id := strings.Split(k, "/")[0]
+		if id == fmt.Sprintf("%d", u.GameID) {
+			m[k] = v
+			keys = append(keys, k)
+		}
+	}
+	sort.Sort(scanSorter(keys))
+	for _, key := range keys {
+		select {
+		case <-quit:
+			return
+		default:
+			value := m[key]
+			handleGameUpdate(file, key, value, u)
+		}
+	}
+	stream, err2 := WatchData(LogName, fmt.Sprintf("%d", u.GameID), u)
+	fmt.Println("STARTING WATCH FOR GAME", u.GameID)
+	if err2 != nil {
+		fmt.Println("WatchData error:", err2)
+	}
 	updateBlock := make([]nosql.WatchChange, 0)
 	for {
 		if updateExists := stream.Advance(); updateExists {
@@ -99,63 +124,67 @@
 			updateBlock = append(updateBlock, c)
 			if !c.Continued {
 				sort.Sort(updateSorter(updateBlock))
-				handleGameUpdate(file, updateBlock, u)
+				for _, c := range updateBlock {
+					select {
+					case <-quit:
+						return
+					default:
+						if c.ChangeType == nosql.PutChange {
+							key := c.Row
+							var value []byte
+							if err := c.Value(&value); err != nil {
+								fmt.Println("Value error:", err)
+							}
+							handleGameUpdate(file, key, value, u)
+						} else {
+							fmt.Println("Unexpected ChangeType: ", c.ChangeType)
+						}
+					}
+				}
 				updateBlock = make([]nosql.WatchChange, 0)
 			}
 		}
 	}
 }
 
-func handleGameUpdate(file *os.File, changes []nosql.WatchChange, u *uistate.UIState) {
-	for _, c := range changes {
-		if c.ChangeType == nosql.PutChange {
-			key := c.Row
-			curTime := time.Now().UnixNano() / 1000000
-			var value []byte
-			if err := c.Value(&value); err != nil {
-				fmt.Println("Value error:", err)
-			}
-			valueStr := string(value)
-			fmt.Fprintf(file, fmt.Sprintf("key: %s\n", key))
-			fmt.Fprintf(file, fmt.Sprintf("value: %s\n", valueStr))
-			fmt.Fprintf(file, fmt.Sprintf("time: %v\n", curTime))
-			tmp := strings.Split(key, "/")
-			if len(tmp) == 3 {
-				keyTime, _ := strconv.ParseInt(strings.Split(tmp[2], "-")[0], 10, 64)
-				fmt.Fprintf(file, fmt.Sprintf("diff: %d milliseconds\n\n", curTime-keyTime))
-			} else {
-				fmt.Fprintf(file, "\n")
-			}
-			fmt.Println(key, valueStr)
-			keyType := strings.Split(key, "/")[1]
-			switch keyType {
-			case "log":
-				updateType := strings.Split(valueStr, "|")[0]
-				switch updateType {
-				case Deal:
-					onDeal(valueStr, u)
-				case Pass:
-					onPass(valueStr, u)
-				case Take:
-					onTake(valueStr, u)
-				case Play:
-					onPlay(valueStr, u)
-				case TakeTrick:
-					onTakeTrick(valueStr, u)
-				case Ready:
-					onReady(valueStr, u)
-				}
-			case "players":
-				switch strings.Split(key, "/")[3] {
-				case "player_number":
-					onPlayerNum(key, valueStr, u)
-				case "settings_sg":
-					onSettings(key, valueStr, u)
-				}
-
-			}
-		} else {
-			fmt.Println("Unexpected ChangeType: ", c.ChangeType)
+func handleGameUpdate(file *os.File, key string, value []byte, u *uistate.UIState) {
+	curTime := time.Now().UnixNano() / 1000000
+	valueStr := string(value)
+	fmt.Fprintf(file, fmt.Sprintf("key: %s\n", key))
+	fmt.Fprintf(file, fmt.Sprintf("value: %s\n", valueStr))
+	fmt.Fprintf(file, fmt.Sprintf("time: %v\n", curTime))
+	tmp := strings.Split(key, "/")
+	if len(tmp) == 3 {
+		keyTime, _ := strconv.ParseInt(strings.Split(tmp[2], "-")[0], 10, 64)
+		fmt.Fprintf(file, fmt.Sprintf("diff: %d milliseconds\n\n", curTime-keyTime))
+	} else {
+		fmt.Fprintf(file, "\n")
+	}
+	fmt.Println(key, valueStr)
+	keyType := strings.Split(key, "/")[1]
+	switch keyType {
+	case "log":
+		updateType := strings.Split(valueStr, "|")[0]
+		switch updateType {
+		case Deal:
+			onDeal(valueStr, u)
+		case Pass:
+			onPass(valueStr, u)
+		case Take:
+			onTake(valueStr, u)
+		case Play:
+			onPlay(valueStr, u)
+		case TakeTrick:
+			onTakeTrick(valueStr, u)
+		case Ready:
+			onReady(valueStr, u)
+		}
+	case "players":
+		switch strings.Split(key, "/")[3] {
+		case "player_number":
+			onPlayerNum(key, valueStr, u)
+		case "settings_sg":
+			onSettings(key, valueStr, u)
 		}
 	}
 }
@@ -474,6 +503,24 @@
 	return iKey < jKey
 }
 
+type scanSorter []string
+
+func (ss scanSorter) Len() int {
+	return len(ss)
+}
+
+// Swaps the positions of two changes in the array
+func (ss scanSorter) Swap(i, j int) {
+	ss[i], ss[j] = ss[j], ss[i]
+}
+
+// Compares two changes-- one card is less than another if it has an earlier timestamp
+func (ss scanSorter) Less(i, j int) bool {
+	iKey := ss[i]
+	jKey := ss[j]
+	return iKey < jKey
+}
+
 func PlayCard(ch chan bool, playerId int, u *uistate.UIState) string {
 	c := u.DropTargets[0].GetCardHere()
 	if c == nil {
diff --git a/go/src/hearts/touchhandler/touchhandler.go b/go/src/hearts/touchhandler/touchhandler.go
index 32db10b..a76f12d 100644
--- a/go/src/hearts/touchhandler/touchhandler.go
+++ b/go/src/hearts/touchhandler/touchhandler.go
@@ -290,6 +290,8 @@
 			view.LoadTableView(u)
 		} else if b == u.Buttons["hand"] {
 			view.LoadPassOrTakeOrPlay(u)
+		} else if b == u.Buttons["restart"] {
+			sync.ResetGame(u.LogSG, u.IsOwner, u)
 		} else if b == u.Buttons["pass"] {
 			pressButton(b, u)
 		}
@@ -376,6 +378,8 @@
 			view.LoadTableView(u)
 		} else if b == u.Buttons["hand"] {
 			view.LoadPassOrTakeOrPlay(u)
+		} else if b == u.Buttons["restart"] {
+			sync.ResetGame(u.LogSG, u.IsOwner, u)
 		} else if b == u.Buttons["take"] {
 			pressButton(b, u)
 		}
@@ -440,6 +444,8 @@
 			view.LoadTableView(u)
 		} else if b == u.Buttons["hand"] {
 			view.LoadPassOrTakeOrPlay(u)
+		} else if b == u.Buttons["restart"] {
+			sync.ResetGame(u.LogSG, u.IsOwner, u)
 		} else if b == u.Buttons["takeTrick"] {
 			pressButton(b, u)
 		}
@@ -550,6 +556,8 @@
 			view.LoadTableView(u)
 		} else if b == u.Buttons["hand"] {
 			view.LoadPassOrTakeOrPlay(u)
+		} else if b == u.Buttons["restart"] {
+			sync.ResetGame(u.LogSG, u.IsOwner, u)
 		}
 	}
 }
@@ -721,7 +729,7 @@
 func unpressButtons(u *uistate.UIState) []*staticimg.StaticImg {
 	pressed := make([]*staticimg.StaticImg, 0)
 	for _, b := range u.Buttons {
-		if b.GetDisplayingImage() == false {
+		if b != nil && b.GetDisplayingImage() == false {
 			u.Eng.SetSubTex(b.GetNode(), b.GetImage())
 			b.SetDisplayingImage(true)
 			pressed = append(pressed, b)
@@ -811,5 +819,7 @@
 		view.LoadTableView(u)
 	} else if b == u.Buttons["hand"] {
 		view.LoadPassOrTakeOrPlay(u)
+	} else if b == u.Buttons["restart"] {
+		sync.ResetGame(u.LogSG, u.IsOwner, u)
 	}
 }