
// myRanges provides functions to retrieve and modify a user's Host and Moderator ranges
// These ranges define what portion of the Seekia network the user will host and/or moderate

package myRanges

// Moderator and Host Mode each have 4 types of ranges:
//	-Mate identities
//	-Host identities (For Host mode, we either host all or none)
//	-Moderator identities (For Host or Moderator mode, we either host all or none)
//	-Messages inboxes

// A user's ranges define what profiles and messages they will download
// Profiles to download are determined by the identity hash of the profile author
// Messages to download are determined by the Message's inbox

// For profiles/messages a user is hosting/moderating, they will also download all reviews and reports for the profiles/messages. 

// Identity reviews/reports to download are determined by the reviewed/reported identity hash
// Profile/Attribute reviews/reports to download are determined by the reviewed/reported profile author identity hash
// Message reviews/reports to download are determined by the reviewed/reported message's inbox

//TODO: For moderation ranges, there must be a way to stop hosting content within our range, after we have reviewed it
// We have to keep track of this dropped content, and check for it within the backgroundDownloads package

import "seekia/internal/byteRange"
import "seekia/internal/encoding"
import "seekia/internal/identity"
import "seekia/internal/messaging/inbox"
import "seekia/internal/mySettings"

import "errors"

func AdjustMyRanges(myIdentityType string)error{

	//TODO
	// This function will see how much disk space is available, and adjust the moderation and host ranges accordingly
	// This function is run by backgroundJobs on a regular schedule

	return nil
}

//Outputs:
//	-bool: Host mode enabled
//	-bool: Identity is within my host range
//	-error
func CheckIfIdentityHashIsWithinMyHostedRange(identityHash [16]byte)(bool, bool, error){

	identityType, err := identity.GetIdentityTypeFromIdentityHash(identityHash)
	if (err != nil) {
		identityHashHex := encoding.EncodeBytesToHexString(identityHash[:])
		return false, false, errors.New("CheckIfIdentityHashIsWithinMyHostedRange called with invalid identityHash: " + identityHashHex)
	}

	hostModeEnabled, hostingAnyIdentities, myIdentityRangeStart, myIdentityRangeEnd, err := GetMyIdentitiesToHostRange(identityType)
	if (err != nil) { return false, false, err }	
	if (hostModeEnabled == false){
		return false, false, nil
	}
	if (hostingAnyIdentities == false){
		return true, false, nil
	}
	if (identityType != "Mate"){
		// Hosts must host either all or none of the Host/moderator identities, so no range check is needed
		return true, true, nil
	}

	isWithinRange, err := byteRange.CheckIfIdentityHashIsWithinRange(myIdentityRangeStart, myIdentityRangeEnd, identityHash)
	if (err != nil) { return false, false, err }

	return true, isWithinRange, nil
}

//Outputs:
//	-bool: Host mode enabled
//	-bool: Hosting any identities of provided identityType
//	-[16]byte: Identity hash range start
//	-[16]byte: Identity hash range end
//	-error
func GetMyIdentitiesToHostRange(identityType string)(bool, bool, [16]byte, [16]byte, error){

	if (identityType != "Mate" && identityType != "Host" && identityType != "Moderator"){
		return false, false, [16]byte{}, [16]byte{}, errors.New("GetMyIdentitiesToHostRange called with invalid identityType: " + identityType)
	}

	settingExists, hostModeOnOffStatus, err := mySettings.GetSetting("HostModeOnOffStatus")
	if (err != nil) { return false, false, [16]byte{}, [16]byte{}, err }
	if (settingExists == false || hostModeOnOffStatus != "On"){
		return false, false, [16]byte{}, [16]byte{}, nil
	}
	settingExists, hostingIdentityTypeContent, err := mySettings.GetSetting("Hosting" + identityType + "Content")
	if (err != nil) { return false, false, [16]byte{}, [16]byte{}, err }
	if (settingExists == true && hostingIdentityTypeContent == "No"){
		// The default is for all identityType content to be hosted
		return true, false, [16]byte{}, [16]byte{}, nil
	}

	if (identityType != "Mate"){
		// Hosts will host either all or none of host/moderator identities
		minimumIdentityBound, maximumIdentityBound := byteRange.GetMinimumMaximumIdentityHashBounds()

		return true, true, minimumIdentityBound, maximumIdentityBound, nil
	}

	settingExists, hostedMateRangeStartString, err := mySettings.GetSetting("HostedMateContentRangeStart")
	if (err != nil) { return false, false, [16]byte{}, [16]byte{}, err }
	if (settingExists == false){
		// The default range is all identities.
		// The client will automatically reduce this range if storage limits are reached.
		minimumIdentityBound, maximumIdentityBound := byteRange.GetMinimumMaximumIdentityHashBounds()
		return true, true, minimumIdentityBound, maximumIdentityBound, nil
	}

	settingExists, hostedMateRangeEndString, err := mySettings.GetSetting("HostedMateContentRangeEnd")
	if (err != nil) { return false, false, [16]byte{}, [16]byte{}, err }
	if (settingExists == false){
		// This should not happen.
		return false, false, [16]byte{}, [16]byte{}, errors.New("HostedMateContentRangeStart exists but no end range found.")
	}

	hostedMateRangeStart, _, err := identity.ReadIdentityHashString(hostedMateRangeStartString)
	if (err != nil){
		return false, false, [16]byte{}, [16]byte{}, errors.New("HostedMateContentRangeStart is invalid: " + hostedMateRangeStartString)
	}

	hostedMateRangeEnd, _, err := identity.ReadIdentityHashString(hostedMateRangeEndString)
	if (err != nil){
		return false, false, [16]byte{}, [16]byte{}, errors.New("HostedMateContentRangeEnd is invalid: " + hostedMateRangeEndString)
	}

	return true, true, hostedMateRangeStart, hostedMateRangeEnd, nil
}


//Outputs:
//	-bool: Host mode enabled
//	-bool: Inbox is within my hosted range
//	-error
func CheckIfMessageInboxIsWithinMyHostedRange(messageInbox [10]byte)(bool, bool, error){

	hostModeEnabled, hostingAnyInboxes, myInboxRangeStart, myInboxRangeEnd, err := GetMyInboxesToHostRange()
	if (err != nil) { return false, false, err }
	if (hostModeEnabled == false){
		return false, false, nil
	}
	if (hostingAnyInboxes == false){
		return true, false, nil
	}

	isWithinRange, err := byteRange.CheckIfInboxIsWithinRange(myInboxRangeStart, myInboxRangeEnd, messageInbox)
	if (err != nil) { return false, false, err }

	return true, isWithinRange, nil
}

//Outputs:
//	-bool: Host mode enabled
//	-bool: Hosting any inboxes
//	-[10]byte: Inbox range start
//	-[10]byte: Inbox range end
//	-error
func GetMyInboxesToHostRange()(bool, bool, [10]byte, [10]byte, error){

	settingExists, hostModeOnOffStatus, err := mySettings.GetSetting("HostModeOnOffStatus")
	if (err != nil) { return false, false, [10]byte{}, [10]byte{}, err }
	if (settingExists == false || hostModeOnOffStatus != "On"){
		return false, false, [10]byte{}, [10]byte{}, nil
	}
	settingExists, hostMessagesOnOffStatus, err := mySettings.GetSetting("HostMessagesOnOffStatus")
	if (err != nil) { return false, false, [10]byte{}, [10]byte{}, err }
	if (settingExists == false || hostMessagesOnOffStatus != "On"){
		// The default is off
		return true, false, [10]byte{}, [10]byte{}, nil
	}

	settingExists, hostedInboxRangeStartString, err := mySettings.GetSetting("HostedInboxRangeStart")
	if (err != nil) { return false, false, [10]byte{}, [10]byte{}, err }
	if (settingExists == false){

		// The default range is all inboxes

		minimumInboxBound, maximumInboxBound := byteRange.GetMinimumMaximumInboxBounds()

		return true, true, minimumInboxBound, maximumInboxBound, nil
	}

	settingExists, hostedInboxRangeEndString, err := mySettings.GetSetting("HostedInboxRangeEnd")
	if (err != nil) { return false, false, [10]byte{}, [10]byte{}, err }
	if (settingExists == false){
		// This should not happen.
		return false, false, [10]byte{}, [10]byte{}, errors.New("HostedInboxRangeStart exists but no end range found.")
	}

	hostedInboxRangeStart, err := inbox.ReadInboxString(hostedInboxRangeStartString)
	if (err != nil) {
		return false, false, [10]byte{}, [10]byte{}, errors.New("HostedInboxRangeStart is invalid: " + hostedInboxRangeStartString)
	}

	hostedInboxRangeEnd, err := inbox.ReadInboxString(hostedInboxRangeEndString)
	if (err != nil) {
		return false, false, [10]byte{}, [10]byte{}, errors.New("HostedInboxRangeEnd is invalid: " + hostedInboxRangeEndString)
	}

	return true, true, hostedInboxRangeStart, hostedInboxRangeEnd, nil
}


//Outputs:
//	-bool: Moderator mode enabled
//	-bool: Identity is within my moderation range
//	-error
func CheckIfIdentityHashIsWithinMyModerationRange(identityHash [16]byte)(bool, bool, error){

	identityType, err := identity.GetIdentityTypeFromIdentityHash(identityHash)
	if (err != nil) {
		identityHashHex := encoding.EncodeBytesToHexString(identityHash[:])
		return false, false, errors.New("CheckIfIdentityHashIsWithinMyModerationRange called with invalid identityHash: " + identityHashHex)
	}

	moderatorModeEnabled, moderatingAny, myIdentityRangeStart, myIdentityRangeEnd, err := GetMyIdentitiesToModerateRange(identityType)
	if (err != nil) { return false, false, err }
	if (moderatorModeEnabled == false){
		return false, false, nil
	}
	if (moderatingAny == false){
		return true, false, nil
	}

	isWithinRange, err := byteRange.CheckIfIdentityHashIsWithinRange(myIdentityRangeStart, myIdentityRangeEnd, identityHash)
	if (err != nil) { return false, false, err }

	return true, isWithinRange, nil
}

//Outputs:
//	-bool: Moderator mode enabled
//	-bool: Moderating any identities of requested identityType
//	-[16]byte: Identity hash Range start
//	-[16]byte: Identity hash Range end
//	-error
func GetMyIdentitiesToModerateRange(identityType string)(bool, bool, [16]byte, [16]byte, error){

	if (identityType != "Mate" && identityType != "Host" && identityType != "Moderator"){
		return false, false, [16]byte{}, [16]byte{}, errors.New("GetMyIdentitiesToModerateRange called with invalid identityType: " + identityType)
	}

	settingExists, moderatorModeOnOffStatus, err := mySettings.GetSetting("ModeratorModeOnOffStatus")
	if (err != nil) { return false, false, [16]byte{}, [16]byte{}, err }
	if (settingExists == false || moderatorModeOnOffStatus != "On"){
		return false, false, [16]byte{}, [16]byte{}, nil
	}
	settingExists, moderatingContentStatus, err := mySettings.GetSetting("Moderate" + identityType + "ContentOnOffStatus")
	if (err != nil) { return false, false, [16]byte{}, [16]byte{}, err }
	if (settingExists == true && moderatingContentStatus == "Off"){
		// This setting is on by default
		return true, false, [16]byte{}, [16]byte{}, nil
	}

	if (identityType == "Moderator"){
		// The default is all identities
		minimumIdentityBound, maximumIdentityBound := byteRange.GetMinimumMaximumIdentityHashBounds()

		return true, true, minimumIdentityBound, maximumIdentityBound, nil
	}

	settingExists, moderatedContentRangeStartString, err := mySettings.GetSetting("Moderated" + identityType + "ContentRangeStart")
	if (err != nil) { return false, false, [16]byte{}, [16]byte{}, err }
	if (settingExists == false){
		// The default is all identities
		minimumIdentityBound, maximumIdentityBound := byteRange.GetMinimumMaximumIdentityHashBounds()

		return true, true, minimumIdentityBound, maximumIdentityBound, nil
	}

	settingExists, moderatedContentRangeEndString, err := mySettings.GetSetting("Moderated" + identityType + "ContentRangeEnd")
	if (err != nil) { return false, false, [16]byte{}, [16]byte{}, err }
	if (settingExists == false){
		// This should not happen.
		return false, false, [16]byte{}, [16]byte{}, errors.New("Moderated" + identityType + "ContentRangeStart exists, but no end range found.")
	}

	moderatedContentRangeStart, _, err := identity.ReadIdentityHashString(moderatedContentRangeStartString)
	if (err != nil){
		return false, false, [16]byte{}, [16]byte{}, errors.New("Moderated" + identityType + "ContentRangeStart is invalid: " + moderatedContentRangeStartString)
	}

	moderatedContentRangeEnd, _, err := identity.ReadIdentityHashString(moderatedContentRangeEndString)
	if (err != nil){
		return false, false, [16]byte{}, [16]byte{}, errors.New("Moderated" + identityType + "ContentRangeEnd is invalid: " + moderatedContentRangeEndString)
	}

	return true, true, moderatedContentRangeStart, moderatedContentRangeEnd, nil
}


//Outputs:
//	-bool: Moderator mode enabled
//	-bool: Inbox is within my moderation range
//	-error
func CheckIfMessageInboxIsWithinMyModerationRange(messageInbox [10]byte)(bool, bool, error){
	
	moderatorModeEnabled, moderatingAny, myInboxRangeStart, myInboxRangeEnd, err := GetMyInboxesToModerateRange()
	if (err != nil) { return false, false, err }
	if (moderatorModeEnabled == false){
		return false, false, nil
	}
	if (moderatingAny == false){
		return true, false, nil
	}

	isWithinRange, err := byteRange.CheckIfInboxIsWithinRange(myInboxRangeStart, myInboxRangeEnd, messageInbox)
	if (err != nil) { return false, false, err }

	return true, isWithinRange, nil
}


//Outputs:
//	-bool: Moderator mode enabled
//	-bool: Moderating any messages
//	-[10]byte: Inbox Range start
//	-[10]byte: Inbox Range end
//	-error
func GetMyInboxesToModerateRange()(bool, bool, [10]byte, [10]byte, error){

	settingExists, moderatorModeOnOffStatus, err := mySettings.GetSetting("ModeratorModeOnOffStatus")
	if (err != nil) { return false, false, [10]byte{}, [10]byte{}, err }
	if (settingExists == false || moderatorModeOnOffStatus != "On"){
		return false, false, [10]byte{}, [10]byte{}, nil
	}
	exists, moderatingMessages, err := mySettings.GetSetting("ModerateMessagesOnOffStatus")
	if (err != nil) { return false, false, [10]byte{}, [10]byte{}, err }
	if (exists == false || moderatingMessages != "On"){
		// The default is off
		return true, false, [10]byte{}, [10]byte{}, nil
	}

	exists, moderatedInboxRangeStartString, err := mySettings.GetSetting("ModeratedInboxRangeStart")
	if (err != nil) { return false, false, [10]byte{}, [10]byte{}, err }
	if (exists == false){

		// The default is to moderate all messages
		// This will be automatically reduced if size exceeds available disk space

		minimumInboxBound, maximumInboxBound := byteRange.GetMinimumMaximumInboxBounds()

		return true, true, minimumInboxBound, maximumInboxBound, nil
	}

	exists, moderatedInboxRangeEndString, err := mySettings.GetSetting("ModeratedInboxRangeEnd")
	if (err != nil) { return false, false, [10]byte{}, [10]byte{}, err }
	if (exists == false){
		return false, false, [10]byte{}, [10]byte{}, errors.New("ModeratedInboxRangeStart exists but no end range found.")
	}

	moderatedInboxRangeStart, err := inbox.ReadInboxString(moderatedInboxRangeStartString)
	if (err != nil) {
		return false, false, [10]byte{}, [10]byte{}, errors.New("ModeratedInboxRangeStart is invalid: " + moderatedInboxRangeStartString)
	}

	moderatedInboxRangeEnd, err := inbox.ReadInboxString(moderatedInboxRangeEndString)
	if (err != nil) {
		return false, false, [10]byte{}, [10]byte{}, errors.New("ModeratedInboxRangeEnd is invalid: " + moderatedInboxRangeEndString)
	}

	return true, true, moderatedInboxRangeStart, moderatedInboxRangeEnd, nil
}




