//CountLastMonthBoxes reads the clan member list and then updates the boxes for everyone.
func CountLastMonthBoxes(members ClanMemberList) {
	monthAgo := time.Now().AddDate(0, 0, -30).Format("2006-01-02 00:00:00")
	var BoxCount int
	var SinceDateString string
	database, tx := MakeDBConnection()

	//As people come and go we need to mark the people who have left as inactive.
	//Mark all as inactive and then as we get values for each person in the clan
	//we'll mark them active again.

	mytools.Debug(fmt.Sprint("Comparing box count from up to 30 days ago against current box count for ", len(members.Members), " clan members."))
	_, err := database.Exec("UPDATE members SET active = FALSE")
	mytools.CheckError("Update all to false:", err)

	for i := 0; i < len(members.Members); i++ {
		err = database.QueryRow("SELECT MAX(total)-MIN(total), MIN(date) AS boxes FROM historical WHERE userid=? AND date > ?",
			members.Members[i].Account_id, monthAgo).Scan(&BoxCount, &SinceDateString)
		mytools.CheckError("Query Row", err)
		//convert retrieved date to time object
		SinceDate, err := time.Parse("2006-01-02", SinceDateString)
		mytools.CheckError("Parse date from database: ", err)
		mytools.Debug(fmt.Sprint(members.Members[i].Account_name, " made ", BoxCount, " boxes since ", SinceDateString, " which is ", int(time.Now().Sub(SinceDate).Hours()/24), " days."))

		_, err = database.Exec("REPLACE INTO members (userid,name,lastmonthboxcount,lastmonthdays,lastupdate, active) VALUES (?,?,?,?,?,?)",
			members.Members[i].Account_id, members.Members[i].Account_name, BoxCount, int(time.Now().Sub(SinceDate).Hours()/24), SinceDate, true)
		mytools.CheckError("Update Stats", err)
	}
	err = tx.Commit()
	mytools.CheckError("tx.Commit()", err)
	database.Close()
}
//GetStrongBattleTimes queries WG's APi server and unmarshals the response
func GetStrongBattleTimes() (Battles SHBattleList) {

	clanID := "1000005061"
	url := "https://api.worldoftanks.com/wot/stronghold/plannedbattles/?application_id=b4ac9bb7c9cbb189201c95a778827c24&clan_id=" + clanID

	//	fmt.Println(url)
	var WGResponse WGJSONSHResponse

	resp, err := http.Get(url)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)

	err = json.Unmarshal([]byte(body), &WGResponse)
	if err != nil {
		mytools.Debug("Unmarshaling SHBattles - No battles")
	}
	Battles = WGResponse.Data

	//mytools.Debug("calling init() on SH data")
	for i := 0; i < len(Battles.Battles); i++ {
		Battles.Battles[i].Init()
		//	mytools.Debug(fmt.Sprintf("a %+v", Battles.Battles[i].BattleCreationDate))
		//	mytools.Debug(fmt.Sprintf("a %+v", Battles.Battles[i].BattlePlannedDate))
	}
	/*	mytools.Debug("calling looking at the dates after init")
		for _, sb := range Battles.Battles {
			mytools.Debug(fmt.Sprintf("b %+v", sb.BattleCreationDate))
			mytools.Debug(fmt.Sprintf("b %+v", sb.BattlePlannedDate))
		}
	*/
	return
}
//ShowMeAllTheBoxes handler page displays the historical data
func ShowMeAllTheBoxes(rw http.ResponseWriter, r *http.Request) {
	lastMonth := time.Now().AddDate(0, 0, -30).Format("2006-01-02 00:00:00")
	database, tx := boxcheckerbackend.MakeDBConnection()
	var UserID, LastWeek, AllTime, i int
	var Date string

	mytools.Debug("Retrieving Historical Rows")
	rows, err := database.Query("SELECT * FROM historical WHERE date >= ? ORDER BY userid", lastMonth)
	mytools.CheckError("Query Members Table", err)

	fmt.Fprintln(rw, "This is the raw data for all the box calculations, only the last 30 days is shown.")
	fmt.Fprintln(rw, "UserId		Date		\"This week\"	\"All Time\"")
	i = 1

	for rows.Next() {
		err := rows.Scan(&UserID, &Date, &LastWeek, &AllTime)
		mytools.CheckError("scan row results", err)
		fmt.Fprintln(rw, fmt.Sprint(UserID, "	", Date, "	", LastWeek, "	", AllTime))
		i++
	}
	err = rows.Err()
	mytools.CheckError("after last row", err)
	rows.Close()
	err = tx.Commit()
	mytools.CheckError("tx.Commit()", err)
	database.Close()
}
//DisplayBattles is for debugging and testing, not executed as part of 'prod' functionality
func DisplayBattles(Battles SHBattleList) {
	mytools.Debug(fmt.Sprint("Getting ready to display ", len(Battles.Battles), " battles"))
	for _, battle := range Battles.Battles {
		battle.BattleCreationDate = time.Unix(battle.BattleCreationDateInt, int64(0))
		battle.BattlePlannedDate = time.Unix(battle.BattlePlannedDateInt, int64(0))
		fmt.Printf("%+v", battle)
		fmt.Println("")
	}
}
//GetBoxes users the member list and updates their boxes
func GetBoxes(members ClanMemberList) {
	today := time.Now().Format("2006-01-02 00:00:00")
	var boxes, boxchecks int

	database, tx := MakeDBConnection()

	mytools.Debug("Retrieving boxes...")

	for i := 0; i < len(members.Members); i++ {
		thisweek, total := getStrongholdStats(members.Members[i].Account_id)
		boxchecks = 0
		//Start data validation checking
	DirtyGoto: // there's likely a better way to do this but, this is easier.
		//WG API is not really reliable and will return 0s for box counts which makes a mess of the data.
		//After we get the data we need to see if the user has a non-zero box count and if so then
		//send a re-request for the data.  Fail after a few tries.
		if total == 0 { //run a query to see if the member had more than 0 previously
			_ = database.QueryRow("SELECT MAX(total) FROM historical WHERE userid=?", members.Members[i].Account_id).Scan(&boxes)
			if boxes != 0 { //now we have a problem ask WG API for the data again.
				mytools.Debug(fmt.Sprintln("Houston we have a Problem. ", members.Members[i].Account_name, " had ", boxes, " before, but WG just told me he had 0. Rechecking"))
				thisweek, total = getStrongholdStats(members.Members[i].Account_id) //query wg api for fresh box count
				boxchecks++
				if boxchecks > 2 { //tried 3 times, give up
					mytools.Debug(fmt.Sprintln("After 3 tries I'm giving up on getting fresh boxes for ", members.Members[i].Account_name))
					continue //continue the i loop
				}
				goto DirtyGoto // re-check the result of the wg api query
			}
		}
		_, err := database.Exec("INSERT INTO historical (userid,thisweek,total,date) SELECT ?, ?, ?, ? FROM dual WHERE NOT EXISTS (SELECT userid, date FROM historical WHERE userid=? AND date=?)",
			members.Members[i].Account_id, thisweek, total, today, members.Members[i].Account_id, today)
		mytools.CheckError("database.Exec()", err)
	}
	//	mytools.Debug("\nDone collecting boxes.")
	err := tx.Commit()
	mytools.CheckError("tx.Commit()", err)
	database.Close()
}
//LastRun returns the number of days since the last run, not sure if this is used
func LastRun() (DaysSinceLastRun int) {
	var LastDateString string
	Today := time.Now()

	database, _ := MakeDBConnection()
	err := database.QueryRow("SELECT MAX(date) FROM historical").Scan(&LastDateString)
	mytools.CheckError("Finding Highest Date ", err)
	LastDate, err := time.Parse("2006-01-02", LastDateString)
	mytools.CheckError("Parsing Date", err)
	mytools.Debug(fmt.Sprint("Comparing dates ", Today, LastDate))

	DaysSinceLastRun = int(Today.Sub(LastDate).Hours() / 24)
	database.Close()
	return
}
func main() {
	mytools.Debug(fmt.Sprint("Main() Started at ", time.Now().Local().Format("2006-01-02 15:04:05")))
	go Scheduler()
	http.HandleFunc("/", HandleRoot)
	http.HandleFunc("/showmetheboxes", ShowMeTheBoxes)
	http.HandleFunc("/upcomingbattles", UpcomingBattles)
	http.HandleFunc("/showmetheboxesnew", ShowMeTheBoxesNew)
	//http.HandleFunc("/showmetheboxesexperiment", ShowMeTheBoxesNew)
	http.HandleFunc("/showmetheboxesold", ShowMeTheBoxesOld)
	http.HandleFunc("/showmealltheboxes", ShowMeAllTheBoxes)
	http.HandleFunc("/UpdateTheBoxes", UpdateTheBoxes)
	//http.HandleFunc("/fillthegap", GapFiller)
	//	http.HandleFunc("/Die", Die)
	http.HandleFunc("/test", TemplateTest)
	http.Handle("/mods/", http.FileServer(http.Dir("./mods")))
	http.ListenAndServe(":8080", nil)
	//http.ListenAndServe(":81", nil)
}
//GetPlayerData returns a Player struct when given a PlayerID int
func GetPlayerData(PlayerID int) (PlayerData Player) {
	var WGResponse WGJSONPlayerResponse
	PlayerIDString := strconv.Itoa(PlayerID)
	url := "http://api.worldoftanks.com/wot/account/info/?application_id=b4ac9bb7c9cbb189201c95a778827c24&fields=-statistics%2C%20-private&account_id=" + PlayerIDString // + strconv.Itoa(PlayerID)
	resp, err := http.Get(url)
	if err != nil {
		panic(err)
	}
	//defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	err = json.Unmarshal([]byte(body), &WGResponse)
	if err != nil {
		mytools.Debug("Unmarshaling Player - Error")
	}
	PlayerData = WGResponse.Data[PlayerIDString]

	PlayerData.Init()
	return
}
// Scheduler automates the updating of boxes.  Runs forever and sleeps a minute at a Time
// and when the date changes trigger the update process.
func Scheduler() {

	today := time.Now().Local().Format("2006-01-02 00:00:00")
	hours, minutes, _ := time.Now().Clock()
	for {
		if today != time.Now().Local().Format("2006-01-02 00:00:00") {
			mytools.Debug("Performing Update")
			mytools.Log("Scheduler", fmt.Sprint("Performing update at", hours))
			members := boxcheckerbackend.GetClanMembers()
			boxcheckerbackend.GetBoxes(members)
			boxcheckerbackend.CountLastMonthBoxes(members)
			today = time.Now().Local().Format("2006-01-02 00:00:00")
		}

		if minutes == 0 {
			//mytools.Debug(fmt.Sprint("Hourly Scheduler Heartbeat at ", hours))
			go mytools.Log("Scheduler", fmt.Sprint("Hourly Scheduler Heartbeat at ", hours))
		}
		time.Sleep(time.Minute)
	}
}
//GetCWBattleTimes queries WG api and unmarshals the response
func GetCWBattleTimes() (Battles CWBattleList) {
	clanID := "1000005061"
	url := "https://api.worldoftanks.com/wot/globalmap/clanbattles/?application_id=b4ac9bb7c9cbb189201c95a778827c24&clan_id=" + clanID

	var WGResponse WGJSONCWResponse

	resp, err := http.Get(url)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)

	err = json.Unmarshal([]byte(body), &WGResponse)
	if err != nil {
		mytools.Debug("Unmarshaling CWBattles - No battles")
	}
	Battles = WGResponse.Data

	for i := 0; i < len(Battles.Battles); i++ {
		Battles.Battles[i].Init()
	}
	return
}