
//The google map
let map;

//array with the markers
let markers = [];

//Array with the minimum[0] and maximum year[1]
let yearRange = [];

//initializes the map + grabs photo data from the server.
async function myMap() {
	
    var mapProp = {
		// Center the map at a specific latitude and longitude
		center: new google.maps.LatLng(44.4426434, -88.0702602), //St. Norbert
		zoom: 11, // Set the initial zoom level
		minZoom: 3,
		mapId: "1",
	};
    map = new google.maps.Map(document.getElementById("googleMap"), mapProp);
	
	const markerData = await fetchData();
	
	await displayMarkers(markerData);
	
	await updateYearRange();
	//console.log(yearRange);
	fillYearFilter();
	
	//This will crash when a user is not logged in ...
	//	... so dont put any code below this function call in this function
	await loggedUser();
}

//This function works so that I can add geocoding to photos through a hidden google map.
async function myEmptyMap() {
	const { Geocoder } = await google.maps.importLibrary("geocoding");
	
	var mapProp = {
		// Center the map at a specific latitude and longitude
		center: new google.maps.LatLng(44.4426434, -88.0702602), //St. Norbert
		zoom: 11, // Set the initial zoom level
		minZoom: 3,
		mapId: "1",
	};
    map = new google.maps.Map(document.getElementById("googleMap"), mapProp);
	
	const geocoder = new Geocoder();
	//geocode here
	const theLatBox = document.getElementById('theLat');
	//console.log(theLat);
	const theLongBox = document.getElementById('theLong');
	const theCityBox = document.getElementById('theCity');
	
	//event listener that listens for when the latitude changes
	theLatBox.addEventListener('change', (event) => {
		if(theLongBox.value != ''){
			var latVal = theLatBox.value;
			var longVal = theLongBox.value;
			const latlng = {lat: parseFloat(latVal), lng: parseFloat(longVal)};
			
			geocoder.geocode({ location: latlng }, (results, status) => {
				if(status === "OK" && results[0]) {
					var addressComponents = results[0].address_components;
					var theCity = '';
					
					for (var i = 0; i < addressComponents.length; i++){
						var types = addressComponents[i].types;
						if(types.includes("locality")) {
							theCity = addressComponents[i].long_name;
							break;
						}
					}
					theCityBox.value = theCity;
				}
			});
		}
	});
	
	//event listener that listens for when the longitude changes
	theLongBox.addEventListener('change', (event) => {
		if(theLatBox.value != ''){
			var latVal = theLatBox.value;
			var longVal = theLongBox.value;
			const latlng = {lat: parseFloat(latVal), lng: parseFloat(longVal)};
			
			geocoder.geocode({ location: latlng }, (results, status) => {
				if(status === "OK" && results[0]) {
					var addressComponents = results[0].address_components;
					var theCity = '';
					
					for (var i = 0; i < addressComponents.length; i++){
						var types = addressComponents[i].types;
						if(types.includes("locality")) {
							theCity = addressComponents[i].long_name;
							break;
						}
					}
					theCityBox.value = theCity;
				}
			});
		}
	});
	
	//event listener that listens for when the region(city) changes
	theCityBox.addEventListener('change', (event) => {
		var cityVal = theCityBox.value;
		var latVal = '';
		var longVal = '';
		
		//CURRENTLY DOES NOT RETURN THE LAT OR LONG CORRECTLY
		geocoder.geocode({address: cityVal}, (results, status) => {
			if(status === "OK" && results[0]) {
				latVal = results[0].geometry.location.lat();
				longVal = results[0].geometry.location.lng();
				
				//console.log(results);
			}
			theLatBox.value = latVal;
			theLongBox.value = longVal;
		});
	});
}

//Grabs the the data from the photos.txt and parses it into a better format for data processing
async function fetchData() {
	var path = document.location.pathname.substring(0, document.location.pathname.lastIndexOf('/'));
	const metadataPath = new URL("WebApplication/Photos.txt", document.location.origin + path).href;
	
	const response = await fetch(metadataPath);
	console.log(metadataPath);
	if(!response.ok) {
		throw new Error(`HTTP error! status: ${response.status}`);
	}
	
	const text = await response.text();
	
	const data = text.split("\n");
	
	//removes the last "empty" entry
	data.pop();
	
	//store the json strings into an array
	const objects = data.map(str => JSON.parse(str));	
	
	return objects;
}

//Takes the formatted data from fetchData and turns each entry into a marker that is stored on the browser
async function displayMarkers(markerData) {
	//import libraries that will be needed
	const { AdvancedMarkerElement } = await google.maps.importLibrary("marker");
	const { CollisionBehavior } = await google.maps.importLibrary("marker");
	
	//iterate through our "data" making a marker out of each photo entry
	markerData.forEach(data => {
		const customImg = document.createElement('img');
		var pinString = data.fileName.substring(0, data.fileName.lastIndexOf('.'));
		pubPinString = pinString + "Pin.png";
		privPinString = pinString + "PPin.png";
		
		if(data.view == "public"){
			
			//What the path to the public pin
			var path = document.location.pathname.substring(0, document.location.pathname.lastIndexOf('/'));
			customImg.src = new URL(pubPinString, document.location.origin + path + "/uploads/").href;
			customImg.style.scale = "1.0";
			
			//create the marker for public pins
			const marker = new AdvancedMarkerElement({
				map: map,
				position: {lat: parseFloat(data.theLat), lng: parseFloat(data.theLong)},
				title: data.fileName,
				content: customImg,
				gmpClickable: true,
				collisionBehavior: "OPTIONAL_AND_HIDES_LOWER_PRIORITY"
			});
			
			//create the infoWindow for the Pin
			var infoWindow = new google.maps.InfoWindow({
				ariaLabel: data.fileName,
				content: '<div id= "content">' + 
						 '<img src= "uploads/' + marker.title + '" alt="Image" style="width:100%;max-width:200px;"> <br>'
						 + marker.title + '<br>' + data.theDate + '<br>' + data.theCity + '<br>' +
						 data.view + '<br>' + data.user + '</div>'
			});
			
			//Add functionality to clicking on a Pin
			marker.addEventListener('gmp-click', () => {				
				infoWindow.close();
				infoWindow.open(marker.map, marker);
			});
			
			//add the info window to the current marker
			marker.infoWindow = infoWindow;
			
			//push the marker to the marker array
			markers.push(marker);
		}
		else{
			//Whats the path to the private pin
			var path = document.location.pathname.substring(0, document.location.pathname.lastIndexOf('/'));
			customImg.src = new URL(privPinString, document.location.origin + path + "/uploads/").href;
			customImg.style.scale = "1.0";
			
			//create the marker for private pins
			const marker = new AdvancedMarkerElement({
				map: null,
				position: {lat: parseFloat(data.theLat), lng: parseFloat(data.theLong)},
				title: data.fileName,
				content: customImg,
				gmpClickable: true,
				collisionBehavior: "OPTIONAL_AND_HIDES_LOWER_PRIORITY"
			});
			
			//create the infoWindow for the Pin
			var infoWindow = new google.maps.InfoWindow({
				ariaLabel: data.fileName,
				content: '<div id= "content">' + 
						 '<img src= "uploads/' + marker.title + '" alt="Image" style="width:100%;max-width:200px;"> <br>'
						 + marker.title + '<br>' + data.theDate + '<br>' + data.theCity + '<br>' +
						 data.view + '<br>' + data.user + '</div>'
			});
			
			//Add functionality to clicking on a Pin
			marker.addEventListener('gmp-click', () => {
				infoWindow.close();
				infoWindow.open(marker.map, marker);
			});
			
			//add the info window to the current marker
			marker.infoWindow = infoWindow;
			
			//push the marker to the marker array
			markers.push(marker);
		}
		
	});
	return;
}

//Runs through the marker array and determines what the oldest and newest photo year are.
async function updateYearRange(){
	var minYear = 0;
	var maxYear = 0;
	
	markers.forEach( marker => {
		//extract the year from a marker
		const strings = marker.infoWindow.content.split(">");
		const date = strings[4].split("<");
		const dateString = date[0].split(":");
		const year = parseInt(dateString[0]);
	
		//determine if its a max year or min year or neither
		if(minYear == 0 && maxYear == 0){ //base case: There is no max/min year yet
			minYear = year;
			maxYear = year;
		}
		else if (year > maxYear)
			maxYear = year;
		else if (year < minYear)
			minYear = year;
	});
	
	//push the determined min and max year to our global array
	yearRange.push(minYear);
	yearRange.push(maxYear);
}

//Takes the oldest and youngest year and fills the filter dropdown with the inbetween values
async function fillYearFilter() {
	//grab the relevant elements
	const minYearBox = document.getElementById("minYear");
	const maxYearBox = document.getElementById("maxYear");
	
	//run from the youngest year to the oldest year and append options to the filler dropdown
	for(let i = yearRange[0]; i <= yearRange[1]; i++){
		const opt1 = document.createElement("option");
		const opt2 = document.createElement("option");
		opt1.value = i;
		opt1.innerHTML = i;
		opt2.value = i;
		opt2.innerHTML = i;
		minYearBox.appendChild(opt1);
		maxYearBox.appendChild(opt2);
	}
	
	//make the filler boxes default to the youngest and oldest photo years
	minYearBox.value = yearRange[0];
	maxYearBox.value = yearRange[1];
}

//ensures that a user can't choose weird dates when filtering on the year.
async function yearBounds(){
	const minYearBox = document.getElementById('minYear');
	const maxYearBox = document.getElementById('maxYear');
	var minYear = parseInt(minYearBox.value);
	var maxYear = parseInt(maxYearBox.value);
	
	if(minYear > maxYear){
		alert("the minimum year can't be greater than the maximum year!");
		minYearBox.value = maxYear;
	}
	else if(maxYear < minYear){
		alert("the maximum year can't be less than the minimum year!");
		maxYearBox.value = minYear;
	}
}

//runs through the marker array and makes the pins that
//	 the CURRENTLY logged in user uploaded visible.
async function loggedUser(){
	markers.forEach( marker => {		
		const strings = marker.infoWindow.content.split(">");
		const targetString = strings[7].split("<");
		//console.log(strings);
		
		if(targetString[0] == username)
			marker.map = map;
	});
}

//resets our filters and also resets our filter container
async function resetFilter(){
	const prViewBox = document.getElementById('public');
	prViewBox.checked = "checked";
	const puViewBox = document.getElementById('private');
	puViewBox.checked = "";
	
	const nameBox = document.getElementById('photoName');
	nameBox.value = '';
	const userBox = document.getElementById('username');
	userBox.value = '';
	
	const minYearBox = document.getElementById('minYear');
	minYearBox.value = yearRange[0];
	const maxYearBox = document.getElementById('maxYear');
	maxYearBox.value = yearRange[1];
	
	markers.forEach( marker => {
		//reset the public markers
		const strings = marker.infoWindow.content.split(">");
		const targetString = strings[6].split("<");
		
		if(targetString[0] == 'public')
			marker.map = map;
		else
			marker.map = null;
	});
}

//checks and applies each of the relevant filters to our markers
async function filter() {
	//grab our data from our filter fields
	//photoName
	var photoName = document.getElementById('photoName').value;
	
	//username
	var userName = document.getElementById('username').value;
	
	//Year
	var minYear = parseInt(document.getElementById('minYear').value);
	var maxYear = parseInt(document.getElementById('maxYear').value);
	//console.log(minYear);
	//console.log(maxYear);
	
	//view type
	var Public = document.getElementById('public').checked;
	var Private = document.getElementById('private').checked;
	
	//initialize flags
	var nameFlag = false;
	var usernameFlag = false;
	var yearFlag = false;
	var privViewFlag = false;
	var pubViewFlag = false;
	var keep = true;
	
	//check which filters need to be checked
	if(photoName != '')
		nameFlag = true;
	if(userName != '')
		usernameFlag = true;
	if(minYear != yearRange[0] || maxYear != yearRange[1])
		yearFlag = true;
	if(Private == true) 
		privViewFlag = true;
	if(Public == true)
		pubViewFlag = true;
	
	//iterate through our array and apply the filters
	markers.forEach(marker => {
		//begin prepping the available data for filtering checks
		const strings = marker.infoWindow.content.split(">");
		
		//initialize our flag for the marker		
		keep = true;
		
		//filter for a specific photos name
		if(nameFlag == true){
			if(!marker.title.includes(photoName))
				keep = false;
		}
		
		//filter for a specific user
		const targetUser = strings[7].split("<");
		if(usernameFlag == true){
			if(targetUser[0] != userName)
				keep = false;
		}
	
		//filter for a year range
		if(yearFlag == true) {
			const date = strings[4].split("<");
			const dateInt = parseInt(date[0].split(":"));
			
			if(dateInt < minYear || dateInt > maxYear)
				keep = false;
		}
		
		//filter for a specific photo view (public or private)
		const targetView = strings[6].split("<");
		if(targetView[0] == 'public' && pubViewFlag == false)
			keep = false;

		if (targetView[0] == 'private' && privViewFlag == false)
			keep = false;
		else if(targetView[0] == 'private' && privViewFlag == true){
			if(targetUser[0] != username)
				keep = false;
		}
		
		//what to do with the marker?
		if(keep == true)
			marker.map = map;
		else
			marker.map = null;
		
	});
}

//If filter button is clicked, opens filter also closes the filter
async function overlay(){
	//calculate the offset for the filter box
	var nav = document.getElementById('topnav');
	var offset = String(nav.offsetHeight) + 'px';
	
    var filterContainer = document.getElementById('filterContainer');
    var isCollapsed = filterContainer.style.top === offset;

    filterContainer.style.top = isCollapsed ? '-640px' : offset;
}

//function that randomly pans to markers and displays their info windows.
async function kioskMode(){	
	//close out filter overlay
	overlay();
	
	//grab the coordinates of our elements
	var nav = document.getElementById('topnav');
	var adjustedPos = Math.round((nav.offsetHeight/1.5) * 100)/100;
	var offset = String(adjustedPos) + 'px';
	
	var kioskContainer = document.getElementById('kioskContainer');
	var isShown = kioskContainer.style.top === offset;
	
	kioskContainer.style.top = isShown ? '-640px' : offset;

	//set up the kiosking
	map.setZoom(10);
	
	var nextMarker = markers[Math.floor(Math.random() * markers.length)];
	nextMarker.map = map;
	var infoWindow = nextMarker.infoWindow;
	infoWindow.open(map, nextMarker);
	
	//kiosk loop
	const KioskLoop = setInterval(function() {
		//close the info window of the now previous marker
		infoWindow.close();
		
		var bounds = new google.maps.LatLngBounds();
		map.fitBounds(bounds);
		
		//grab a new random marker
		nextMarker = markers[Math.floor(Math.random() * markers.length)];
		nextMarker.map = map;

		infoWindow = nextMarker.infoWindow;
		infoWindow.open(map, nextMarker);
	
		map.panTo(new google.maps.LatLng(nextMarker.position));
	}, 6000);
	
	//event listener that listens for when the user wants to stop kiosking
	kioskContainer.addEventListener('click', (event) => {
		clearInterval(KioskLoop);
		infoWindow.close();
		
		nav = document.getElementById('topnav');
		adjustedPos = Math.round((nav.offsetHeight/1.5) * 100)/100;
		offset = String(adjustedPos) + 'px';
		
		isShown = kioskContainer.style.top === offset;
		kioskContainer.style.top = isShown ? '-640px' : offset;
	});
}