func NewPersistenceContext(gameConfig *config.GameConfigDef) (*PersistenceContextDef, *gkerr.GkErrDef) {
	var persistenceContext *PersistenceContextDef = new(PersistenceContextDef)
	var gkErr *gkerr.GkErrDef

	persistenceContext.gameConfig = gameConfig
	persistenceContext.connectionMutex = new(sync.Mutex)

	persistenceContext.connection, gkErr = database.NewGkDbCon(gameConfig.DatabaseUserName, gameConfig.DatabasePassword, gameConfig.DatabaseHost, gameConfig.DatabasePort, gameConfig.DatabaseDatabase)
	if gkErr != nil {
		return nil, gkErr
	}

	return persistenceContext, nil
}
func handleLoginResetPassword(loginConfig *loginConfigDef, res http.ResponseWriter, req *http.Request, token string, userName string, password string) {
	var resetPasswordData resetPasswordDataDef
	var gkErr *gkerr.GkErrDef

	resetPasswordData.Title = "resetPassword"
	resetPasswordData.LoginWebAddressPrefix = loginConfig.LoginWebAddressPrefix
	resetPasswordData.Token = token
	resetPasswordData.UserName = userName

	if !CheckToken(token, userName) {
		redirectToError("token expired", res, req)
		return
	}

	gklog.LogTrace("reset password: "******"" {
		gklog.LogTrace("password blank")
		gkErr = _resetPasswordTemplate.Build(resetPasswordData)
		if gkErr != nil {
			gklog.LogGkErr("_resetPasswordTemplate.Build", gkErr)
			redirectToError("_resetPasswordTemplate.Build", res, req)
			return
		}

		gkErr = _resetPasswordTemplate.Send(res, req)
		if gkErr != nil {
			gklog.LogGkErr("_resetPasswordTemplate.send", gkErr)
		}
		return
	}

	var gkDbCon *database.GkDbConDef

	gkDbCon, gkErr = database.NewGkDbCon(loginConfig.DatabaseUserName, loginConfig.DatabasePassword, loginConfig.DatabaseHost, loginConfig.DatabasePort, loginConfig.DatabaseDatabase)
	if gkErr != nil {
		gklog.LogGkErr("database.NewGkDbCon", gkErr)
		redirectToError("database.NewGkDbCon", res, req)
		return
	}

	defer gkDbCon.Close()

	var passwordHash, passwordSalt []byte
	var err error

	passwordSalt, err = sec.GenSalt()
	if err != nil {
		gkErr = gkerr.GenGkErr("sec.GenSalt", err, ERROR_ID_GEN_SALT)
		gklog.LogGkErr("sec.GenSalt", gkErr)
		redirectToError("sec.GenSalt", res, req)
	}

	passwordHash = sec.GenPasswordHashSlow([]byte(password), passwordSalt)

	gklog.LogTrace("change password")
	gkDbCon.ChangePassword(userName, string(passwordHash), string(passwordSalt))
	if gkErr != nil {
		gklog.LogGkErr("gkDbCon.ChangePassword", gkErr)
		redirectToError("gbDbCon.ChangePassword", res, req)
		return
	}

	gklog.LogTrace("redirect to login")
	http.Redirect(res, req, loginConfig.LoginWebAddressPrefix+_loginServer, http.StatusFound)
}
func handleLoginForgotPassword(loginConfig *loginConfigDef, res http.ResponseWriter, req *http.Request, userName string) {
	var forgotPasswordData forgotPasswordDataDef
	var gkErr *gkerr.GkErrDef

	forgotPasswordData.Title = "forgotPassword"
	forgotPasswordData.LoginWebAddressPrefix = loginConfig.LoginWebAddressPrefix
	forgotPasswordData.UserName = userName
	forgotPasswordData.ErrorList = make([]string, 0, 0)

	var gotError bool

	if userName == "" {
		forgotPasswordData.ErrorList = append(forgotPasswordData.ErrorList, "user name cannot be blank")
		forgotPasswordData.UserNameError = genErrorMarker()
		gotError = true
	}

	var dbUser *database.DbUserDef

	if !gotError {
		var gkDbCon *database.GkDbConDef

		gkDbCon, gkErr = database.NewGkDbCon(loginConfig.DatabaseUserName, loginConfig.DatabasePassword, loginConfig.DatabaseHost, loginConfig.DatabasePort, loginConfig.DatabaseDatabase)
		if gkErr != nil {
			gklog.LogGkErr("database.NewGkDbCon", gkErr)
			redirectToError("database.NewGkDbCon", res, req)
			return
		}

		defer gkDbCon.Close()

		dbUser, gkErr = gkDbCon.GetUser(
			forgotPasswordData.UserName)

		if gkErr != nil {
			if gkErr.GetErrorId() == database.ERROR_ID_NO_ROWS_FOUND {
				forgotPasswordData.ErrorList = append(forgotPasswordData.ErrorList, "no such user")
				forgotPasswordData.UserNameError = genErrorMarker()
				gotError = true
			} else {
				gklog.LogGkErr("gbDbCon.GetUser", gkErr)
				redirectToError("gbDbCon.GetUser", res, req)
				return
			}
		}
	}

	var err error

	if !gotError {
		// create temporary forgot password token

		//var token []byte
		var forgotPasswordEmailData forgotPasswordEmailDataDef

		forgotPasswordEmailData.LoginWebAddressPrefix = loginConfig.LoginWebAddressPrefix
		forgotPasswordEmailData.UserName = userName

		var token []byte

		token, err = sec.GenForgotPasswordToken()
		if err != nil {
			gkErr = gkerr.GenGkErr("GenForgotPasswordToken", err, ERROR_ID_GEN_TOKEN)
			gklog.LogGkErr("GenForgotPasswordToken", gkErr)
			redirectToError("GenForgotPasswordToken", res, req)
			return
		}

		forgotPasswordEmailData.Token = string(token)

		gkErr = _forgotPasswordEmailTemplate.Build(forgotPasswordEmailData)
		if gkErr != nil {
			gklog.LogGkErr("_forgotPasswordEmailTemplate.Build", gkErr)
			redirectToError("_forgotPasswordEmailTemplate.Build", res, req)
			return
		}

		var message []byte

		message, gkErr = _forgotPasswordEmailTemplate.GetBytes()
		if gkErr != nil {
			gklog.LogGkErr("_forgotPasswordEmailTemplate.GetBytes", gkErr)
			redirectToError("_forgotPasswordEmailTemplate.GetBytes", res, req)
			return
		}

		toArray := make([]string, 1, 1)
		toArray[0] = dbUser.Email
		var sendId string

		AddNewToken(string(token), userName)

		sendId, gkErr = gknet.SendEmail(loginConfig.EmailServer, loginConfig.ServerFromEmail, toArray, "gourdian knot forgotten password", message)

		if gkErr != nil {
			gklog.LogGkErr("gknet.SendEmail", gkErr)
		} else {
			gklog.LogTrace("forgot email sent to: " + toArray[0] + " sendId: [" + sendId + "]")
		}
	}

	if gotError {
		gkErr = _forgotPasswordTemplate.Build(forgotPasswordData)
		if gkErr != nil {
			gklog.LogGkErr("_forgotPasswordTemplate.Build", gkErr)
			redirectToError("_forgotPasswordTemplate.Build", res, req)
			return
		}

		gkErr = _forgotPasswordTemplate.Send(res, req)
		if gkErr != nil {
			gklog.LogGkErr("_forgotPasswordTemplate.send", gkErr)
		}
	} else {
		http.Redirect(res, req, _loginServer, http.StatusFound)
	}
}
func handleLoginRegister(loginConfig *loginConfigDef, res http.ResponseWriter, req *http.Request, userName string, password string, email string) {
	var registerData registerDataDef
	var gkErr *gkerr.GkErrDef
	var err error

	registerData.Title = "register"
	registerData.LoginWebAddressPrefix = loginConfig.LoginWebAddressPrefix
	registerData.UserName = userName
	registerData.Email = email
	registerData.ErrorList = make([]string, 0, 0)

	var gotError bool

	if !isNewUserNameValid(userName) {
		registerData.ErrorList = append(registerData.ErrorList, "invalid user name")
		registerData.UserNameError = genErrorMarker()
		gotError = true
	}
	if !isPasswordValid(password) {
		registerData.ErrorList = append(registerData.ErrorList, "invalid password")
		registerData.PasswordError = genErrorMarker()
		gotError = true
	}
	if !isEmailValid(email) {
		registerData.ErrorList = append(registerData.ErrorList, "invalid email")
		registerData.EmailError = genErrorMarker()
		gotError = true
	}

	if !gotError {
		var gkDbCon *database.GkDbConDef

		gkDbCon, gkErr = database.NewGkDbCon(loginConfig.DatabaseUserName, loginConfig.DatabasePassword, loginConfig.DatabaseHost, loginConfig.DatabasePort, loginConfig.DatabaseDatabase)
		if gkErr != nil {
			gklog.LogGkErr("database.NewGkDbCon", gkErr)
			redirectToError("database.NewGkDbCon", res, req)
			return
		}

		defer gkDbCon.Close()

		var passwordHash, passwordSalt []byte

		passwordSalt, err = sec.GenSalt()
		if err != nil {
			gkErr = gkerr.GenGkErr("sec.GenSalt", err, ERROR_ID_GEN_SALT)
			gklog.LogGkErr("sec.GenSalt", gkErr)
			redirectToError("sec.GenSalt", res, req)
		}

		passwordHash = sec.GenPasswordHashSlow([]byte(password), passwordSalt)

		gkErr = gkDbCon.AddNewUser(
			registerData.UserName,
			string(passwordHash),
			string(passwordSalt),
			email)

		if gkErr != nil {
			if gkErr.GetErrorId() == database.ERROR_ID_UNIQUE_VIOLATION {
				registerData.ErrorList = append(registerData.ErrorList, "user name already in use")
				registerData.UserNameError = genErrorMarker()
				gotError = true
			} else {
				gklog.LogGkErr("gbDbCon.AddNewUser", gkErr)
				redirectToError("gbDbCon.AddNewUser", res, req)
				return
			}
		}
	}

	if gotError {
		gkErr = _registerTemplate.Build(registerData)
		if gkErr != nil {
			gklog.LogGkErr("_registerTemplate.Build", gkErr)
			redirectToError("_registerTemplate.Build", res, req)
			return
		}

		gkErr = _registerTemplate.Send(res, req)
		if gkErr != nil {
			gklog.LogGkErr("_registerTemplate.send", gkErr)
		}
	} else {
		http.Redirect(res, req, _loginServer, http.StatusFound)
		//		var gameRedirect string
		//		gameRedirect = getGameRedirect(loginConfig, loginData.UserName)
		//		http.Redirect(res, req, gameRedirect, http.StatusFound)
	}
}
func handleLoginLogin(loginConfig *loginConfigDef, res http.ResponseWriter, req *http.Request, userName string, password string) {
	var loginData loginDataDef
	var gkErr *gkerr.GkErrDef
	var gotError bool

	loginData.Title = "login"
	loginData.UserName = userName
	loginData.LoginWebAddressPrefix = loginConfig.LoginWebAddressPrefix

	if loginData.UserName == "" {
		loginData.ErrorList = append(loginData.ErrorList, "invalid user name")
		loginData.UserNameError = genErrorMarker()
		gotError = true
	}

	if password == "" {
		loginData.ErrorList = append(loginData.ErrorList, "invalid password")
		loginData.PasswordError = genErrorMarker()
		gotError = true
	}

	var passwordHashFromUser []byte

	var dbUser *database.DbUserDef
	var gkDbCon *database.GkDbConDef

	if !gotError {

		gkDbCon, gkErr = database.NewGkDbCon(loginConfig.DatabaseUserName, loginConfig.DatabasePassword, loginConfig.DatabaseHost, loginConfig.DatabasePort, loginConfig.DatabaseDatabase)
		if gkErr != nil {
			gklog.LogGkErr("database.NewGkDbCon", gkErr)
			redirectToError("database.NewGkDbCon", res, req)
			return
		}

		defer gkDbCon.Close()

		dbUser, gkErr = gkDbCon.GetUser(loginData.UserName)

		if gkErr != nil {
			if gkErr.GetErrorId() == database.ERROR_ID_NO_ROWS_FOUND {
				var passwordSalt string

				password = "******"
				passwordSalt = "abc123QWE."
				// make it take the same amount of time
				// between no user and invalid password
				passwordHashFromUser = sec.GenPasswordHashSlow([]byte(password), []byte(passwordSalt))
				loginData.ErrorList = append(loginData.ErrorList, "invalid username/password")
				loginData.UserNameError = genErrorMarker()
				loginData.PasswordError = genErrorMarker()
				gotError = true
			} else {
				gklog.LogGkErr("gkDbCon.GetPasswordHashAndSalt", gkErr)
				redirectToError("gkDbCon.GetPasswordhashAndSalt", res, req)
				return
			}
		}
	}

	if !gotError {
		passwordHashFromUser = sec.GenPasswordHashSlow([]byte(password), []byte(dbUser.PasswordSalt))

		gklog.LogTrace(fmt.Sprintf("dbUser: %v fromUser: %s", dbUser, passwordHashFromUser))
		if dbUser.PasswordHash != string(passwordHashFromUser) {
			loginData.ErrorList = append(loginData.ErrorList, "invalid username/password")
			loginData.UserNameError = genErrorMarker()
			loginData.PasswordError = genErrorMarker()
			gotError = true
		}
	}

	if gotError {
		// for security, to slow down an attack that is guessing passwords,
		// sleep between 100 and 190 milliseconds
		time.Sleep(sec.GetSleepDurationPasswordInvalid())

		gkErr = _loginTemplate.Build(loginData)
		if gkErr != nil {
			gklog.LogGkErr("_loginTemplate.Build", gkErr)
			redirectToError("_loginTemplate.Build", res, req)
			return
		}

		gkErr = _loginTemplate.Send(res, req)
		if gkErr != nil {
			gklog.LogGkErr("_loginTemplate.Send", gkErr)
			return
		}
	} else {
		gkErr = gkDbCon.UpdateUserLoginDate(dbUser.UserName)
		if gkErr != nil {
			// this error is going to be logged
			// but the user is not going to be redirected to an error
			// because they are going to be redirected to the game server
			// and it is not critical that their login date be updated.
			gklog.LogGkErr("_loginTemplate.Send", gkErr)
		}
		var gameRedirect string
		gameRedirect, gkErr = getGameRedirect(loginConfig, loginData.UserName)
		if gkErr != nil {
			gklog.LogGkErr("getGameRedirect", gkErr)
			return
		}
		http.Redirect(res, req, gameRedirect, http.StatusFound)
	}
}