<template>
<Navbar />

<div id="preferenceDropdown" class="dropdown">
  <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton1" data-bs-toggle="dropdown" aria-expanded="false">
    Map Filters
  </button>
  <div style="padding-bottom: 7px;" id="dropMenu" class="dropdown-menu" aria-labelledby="dropdownMenuButton1" v-on:click.stop="handleClick">
    <div id="prefHeader">STATIONS</div>
      <div class="container-fluid" @change="decideShowStations();">
        <div class="form-check form-switch">
          <input class="form-check-input" type="checkbox" role="switch" id="showMainlandStations" v-model="showMainlandStations"/>
          <label class="form-check-label" for="showMainlandStations">Mainline Stations</label>
        </div>
        <div class="form-check form-switch">
          <input class="form-check-input" type="checkbox" role="switch" id="showDARTStations" v-model="showDARTStations"/>
          <label class="form-check-label" for="showDARTStations">DART Stations</label>
        </div>
      </div>
      <div id="prefHeader">TRAINS</div>
      <div class="container-fluid" @change="decideShowTrains();">
        <div class="form-check form-switch">
          <input class="form-check-input" type="checkbox" role="switch" id="showMainland" v-model="showMainland"/>
          <label class="form-check-label" for="showMainland">Mainline Trains</label>
        </div>
        <div class="form-check form-switch">
          <input class="form-check-input" type="checkbox" role="switch" id="showLate" v-model="showLate"/>
          <label class="form-check-label" for="showLate">Late Trains</label>
        </div>
        <div class="form-check form-switch">
          <input class="form-check-input" type="checkbox" role="switch" id="showOnTime" v-model="showOnTime"/>
          <label class="form-check-label" for="showOnTime">On-time Trains</label>
        </div>
        <div class="form-check form-switch">
          <input class="form-check-input" type="checkbox" role="switch" id="showDART" v-model="showDART"/>
          <label class="form-check-label" for="showDART">DARTs</label>
        </div>
        <div class="form-check form-switch">
          <input class="form-check-input" type="checkbox" role="switch" id="showRunning" v-model="showRunning"/>
          <label class="form-check-label" for="showRunning">Running Trains</label>
        </div>
        <div class="form-check form-switch">
          <input class="form-check-input" type="checkbox" role="switch" id="showTerminated" v-model="showTerminated"/>
          <label class="form-check-label" for="showTerminated">Terminated Trains</label>
        </div>
        <div class="form-check form-switch">
          <input class="form-check-input" type="checkbox" role="switch" id="showNotYetRunning" v-model="showNotYetRunning"/>
          <label class="form-check-label" for="showNotYetRunning">Not-yet Running Trains</label>
        </div>
      </div>
      <button id="savePref" class="btn btn-outline-info" v-if="store.loggedIn" @click="postPreferences()">Save Preferences</button>
    </div>
</div>

<transition id="sidebar" name="slideLeft">
  <div v-if="store.displaySelectedTrain && store.selectedTrain">
    <TrainSidebar />
  </div>
  <div v-else-if="store.displaySelectedStation && store.selectedStation">
    <StationSidebar />
  </div>
</transition>

<ol-map :loadTilesWhileAnimating="true" :loadTilesWhileInteracting="true" style="position:absolute; height:90.6vh; width:100%;">
    <ol-view ref="view" :center="center" :rotation="rotation" :zoom="zoom" :projection="projection" />
    <ol-tile-layer>
    <ol-source-osm />
    </ol-tile-layer>

    <div v-if="(!store.isWaitingForLoginStatus && !store.loggedIn) || (store.loggedIn && readyToDisplayMap)">
      <!-- train overlay -->
      <template v-for="coordinate, i in trainCoordinates" :position="inline-block">
        <ol-overlay v-if="showTrains[i]" :position="coordinate" :offset="[-14,-16]">
            <div class="overlay-content" @click="getSelectedTrain(i)">
                <div v-if="getTrainType(i) === 'DART'">
                    <img v-if="isTrainRunning(i) && isTrainLate(i)" src="../assets/red-train-tram-solid.png" class="trainMapIcon" alt="Late DART Icon">
                    <img v-else-if="isTrainRunning(i) && !isTrainLate(i)" src="../assets/green-train-tram-solid.png" class="trainMapIcon" alt="On-Time DART Icon">
                    <img v-else src="../assets/train-tram-solid.svg" class="trainMapIcon" alt="Not Running DART Icon">
                </div>
                <div v-else>
                    <img v-if="isTrainRunning(i) && isTrainLate(i)" src="../assets/red-train-solid.png" class="trainMapIcon" alt="Late Train Icon">
                    <img v-else-if="isTrainRunning(i) && !isTrainLate(i)" src="../assets/green-train-solid.png" class="trainMapIcon" alt="On-Time Train Icon">
                    <img v-else src="../assets/train-solid.svg" class="trainMapIcon" alt="Not Running Train Icon">
                </div>
            </div>
        </ol-overlay>
      </template>

      <!-- station overlay -->
      <template v-for="coordinate, i in stationCoordinates" :position="inline-block">
        <ol-overlay v-if="showStations[i]" :position="coordinate" :offset="[-14,-16]">
          <div class="overlay-content" @click="getSelectedStation(i)">
            <img src="../assets/station.png" class="stationMapIcon" alt="Station Icon">
          </div>
        </ol-overlay>
      </template>
    </div>
</ol-map>

<div>
  <MarqueeText v-if="publicMessages.length>0" id="publicMessageTicker" :paused="isPaused" :duration="800" :repeat="1"
    @mouseenter="isPaused = !isPaused" @mouseleave="isPaused = false">
    <span v-for="message in publicMessages"> {{ message + " • " }} </span> 
  </MarqueeText>
</div>
</template>

<script>
import { store } from '../store/store';
import { fromLonLat } from 'ol/proj.js';
import { getFunctions, httpsCallable, connectFunctionsEmulator } from "firebase/functions";
import { createToast } from 'mosha-vue-toastify';
import 'mosha-vue-toastify/dist/style.css'
import app from '../api/firebase';
import Navbar from '../components/Navbar.vue';
import MarqueeText from 'vue-marquee-text-component';
import TrainSidebar from '../components/TrainSidebar.vue';
import StationSidebar from '../components/StationSidebar.vue';

export default {
    name: "MapPage",

    data() {
      const toast = () => {
        createToast(this.toastMessage, {
            hideProgressBar: true,
            timeout: 4000,
            toastBackgroundColor: this.toastBackground
        })
      }

      return {
          center: fromLonLat([-7.5029786, 53.4494762]),
          projection: 'EPSG:3857',
          zoom: 7,
          rotation: 0,

          showTrains: [],
          showStations: [],
          trainCoordinates: [],
          stationCoordinates: [],
          allTrains: {},
          allStations: {},
          publicMessages: [],
          isPaused: false,
          readyToDisplayMap: false,
          store,

          toastMessage: "",
          toastBackground: "",
          toast,

          showMainlandStations: true, 
          showDARTStations: true,
          showLate: true,
          showOnTime: true,
          showMainland: true,
          showDART: true, 
          showRunning: true, 
          showTerminated: true, 
          showNotYetRunning: true,
      }
    },

    components: {
      Navbar,
      MarqueeText,
      TrainSidebar,
      StationSidebar
    },
    
    created() {
        this.readyToDisplayMap = false
        let host = window.location.hostname
        if (host === '127.0.0.1' || host === 'localhost') {
            this.postTrainAndStationData();
        }  
        else {
            this.getTrainAndStationData();
        }
        // request new data every 60 seconds
        // window.setInterval(this.getTrainAndStationData, 60000);
    },

    methods: {
        showToast(message, backgroundColour) {
          this.toastMessage = message
          this.toastBackground = backgroundColour
          this.toast()
        },

        handleClick(e){
          e.stopPropagation();
        },

        getPreferences() {
          if (!store.loggedIn) return
          const functions = getFunctions(app);
          let host = window.location.hostname
          if (host === '127.0.0.1' || host == 'localhost') {
            connectFunctionsEmulator(functions, host, 5001);
          }

          const getPreferencesData = httpsCallable(functions, 'getPreferences')
          getPreferencesData().then((response) => {
            if (response.data.data) {
              this.hasPreferences = true
              this.showMainlandStations = response.data.data["showMainlandStations"]
              this.showDARTStations = response.data.data["showDARTStations"]
              this.showLate = response.data.data["showLate"]
              this.showOnTime = response.data.data["showOnTime"]
              this.showMainland = response.data.data["showMainland"]
              this.showDART = response.data.data["showDART"]
              this.showRunning = response.data.data["showRunning"]
              this.showTerminated = response.data.data["showTerminated"]
              this.showNotYetRunning = response.data.data["showNotYetRunning"]

              // update the map with the user's preferences
              this.decideShowStations()
              this.decideShowTrains()
              this.readyToDisplayMap = true
            }
          })
          .catch((error) => {
            this.readyToDisplayMap = true
            console.log(error.message)
          })
        },

        postPreferences() {
          if (!store.loggedIn) return
          let preferences = {
            "showMainlandStations": this.showMainlandStations,
            "showDARTStations": this.showDARTStations,
            "showLate": this.showLate,
            "showOnTime": this.showOnTime,
            "showMainland": this.showMainland,
            "showDART": this.showDART,
            "showRunning": this.showRunning,
            "showTerminated": this.showTerminated,
            "showNotYetRunning": this.showNotYetRunning
          }

          const functions = getFunctions(app);
            let host = window.location.hostname
            if (host === '127.0.0.1' || host == 'localhost') {
              connectFunctionsEmulator(functions, host, 5001);
          }
          
          this.showToast("Saving preferences", "green")
          const postPreferencesData = httpsCallable(functions, 'postPreferences')
          postPreferencesData(preferences).then(() => {
            this.readyToDisplayMap = true
          })
          .catch((error) => {
            this.showToast(error.message, "red")
          })
        },

        // method to determine whether or not to show each train 
        decideShowTrains() {
          for (var i=0; i<this.showTrains.length; i++) {
              let isDART = this.getTrainType(i) == "DART"; 
              if ((this.showRunning && this.allTrains[i]["TrainStatus"][0] == "R") || (this.showTerminated && this.allTrains[i]["TrainStatus"][0] == "T") || this.showNotYetRunning && this.allTrains[i]["TrainStatus"][0] == "N") {
                  if ((this.showDART && isDART) || (this.showMainland && !isDART)) {
                      this.showTrains[i] = (this.showLate && this.isTrainLate(i)) || (this.showOnTime && !this.isTrainLate(i));
                  }
                  else {
                      this.showTrains[i] = false;
                  }
              }
              else {
                  this.showTrains[i] = false;
              }
          }
        },
        
        // method to determine whether or not to show each station
        decideShowStations() {
          for (var i=0; i<this.showStations.length; i++) {
            let isDARTStation = this.getStationType(i) == "DART"; 
            this.showStations[i] = (this.showDARTStations && isDARTStation) || (this.showMainlandStations && !isDARTStation); 
          }
        },

        // method to display a selected train
        getSelectedTrain(i) {
          store.setSelectedTrain(this.allTrains[i]);
          if (store.displaySelectedStation) store.setDisplaySelectedStation(false);
          store.setDisplaySelectedTrain(true);
        },

        // method to display a selected station
        getSelectedStation(i) {
          store.setSelectedStation(this.allStations[i]);
          if (store.displaySelectedTrain) store.setDisplaySelectedTrain(false);
          store.setDisplaySelectedStation(true);
        },

        // method to determine whether or not a selected train is late 
        isTrainLate(i) {
            // check if the train is running
            if (this.allTrains[i]["TrainStatus"][0] == "R") {
                let publicMessage = this.allTrains[i]["PublicMessage"][0];
                let startTimeStr = publicMessage.indexOf("(");

                // check if the train is late
                if (publicMessage[startTimeStr+1] != "-" && publicMessage[startTimeStr+1] != "0") {
                    return true;
                }
            }
            return false;
        },

        // method to determine whether or not a selected train is running
        isTrainRunning(i) {
            if (this.allTrains[i]["TrainStatus"][0] == "R") return true; 
            else return false;
        },

        // method that returns the type of train (either "Train" or "DART")
        getTrainType(i) {
            return this.allTrains[i]["TrainType"][0];
        },

        // method that returns the type of station (either "Train" or "DART")
        getStationType(i) {
          return this.allStations[i]["StationType"][0]
        },

        // method to fetch live train and station data from the database
        getTrainAndStationData() {
            const functions = getFunctions(app);
            let host = window.location.hostname
            if (host === '127.0.0.1' || host == 'localhost') {
                connectFunctionsEmulator(functions, host, 5001);
            }
            const getTrainData = httpsCallable(functions, 'getLiveTrainData');
            let loader = this.$loading.show({
                loader: 'dots',
                container: this.$refs.container,
                canCancel: false
            });
            
            getTrainData().then((response) => {
                try {
                    if (!response.data) throw new Error("Error fetching live train data from the database")
                    var insights =  {
                      "totalNumTrains": 0,
                      "numRunningTrains": 0,
                      "numLateRunningTrains": 0,
                      "numTrains": 0,
                      "numDarts": 0,
                      "totalNumStations": 0,
                      "numTrainStations": 0,
                      "numDartStations": 0
                    };

                    var unorderedTrains = [];
                    var currentMessages = [];
                    var latest = null;
                    var earliest = null;
                    var currLatestTime = null;
                    var currEarliestTime = null;

                    // create an array of coordinates and hashmap with the key-values {index: JSON obj}
                    for (var i=0; i<response.data.length; i++) {
                        let train = response.data[i];
                        this.allTrains[i] = train;
                        this.trainCoordinates[i] = fromLonLat([train["TrainLongitude"][0], train["TrainLatitude"][0]])
                        insights["totalNumTrains"] += 1

                        // filling showTrains with the default value - true
                        this.showTrains[i] = true;
                        if (train["TrainType"][0] == "Train") insights["numTrains"] += 1;
                        else if (train["TrainType"][0] == "DART") insights["numDarts"] += 1;

                        // filter out \n in public messages
                        train["PublicMessage"][0] = train["PublicMessage"][0].replace(/\\n/g, ". ");
                        let publicMessage = train["PublicMessage"][0];
                        currentMessages.push(publicMessage);

                        // check if the train is running
                        if (train["TrainStatus"][0] == "R") {
                            insights["numRunningTrains"] += 1;
                            let startTimeStr = publicMessage.indexOf("(");
                            let timeEnd = publicMessage.indexOf(" ", startTimeStr+1);
                            let num = parseInt(publicMessage.substring(startTimeStr+1, timeEnd))
                            unorderedTrains.push({"time": num, "jsonIndex": i})

                            // check if the train is late
                            if (publicMessage[startTimeStr+1] != "-" && publicMessage[startTimeStr+1] != "0") {
                                insights["numLateRunningTrains"] += 1;
                                if (!latest) latest = train;

                                // check for a new latest train
                                if (num > currLatestTime) {
                                    latest = train;
                                    currLatestTime = num;
                                }
                            }
                            // train is early or ontime
                            else {
                                if (!earliest) earliest = train;
                                // check for a new earliest train (early trains are -x mins late)
                                if (num < currEarliestTime) {
                                    earliest = train;
                                    currEarliestTime = num;
                                }
                            }
                        }
                    }

                    insights["percentageLate"] = ((insights["numLateRunningTrains"] / insights["numRunningTrains"]) * 100).toFixed(2);
                    insights["percentageNotLate"] = (100 - insights["percentageLate"]).toFixed(2);
                    insights["latestTime"] = currLatestTime;
                    insights["earliestTime"] = currEarliestTime;
                    this.publicMessages = currentMessages;

                    // assign the results to the Vue Store
                    store.setEarliestTrain(earliest);
                    store.setLatestTrain(latest);
                    store.setRawData(response.data);
                    store.setOrderedTrains(unorderedTrains);

                    const getStationData = httpsCallable(functions, 'getStationData');
                    getStationData().then((response) => {
                      if (!response.data) throw new Error("Error fetching station from the database");

                      for (var i=0; i<response.data.length; i++) {
                        let station = response.data[i];
                        this.allStations[i] = station;
                        this.stationCoordinates[i] = fromLonLat([station["StationLongitude"][0], station["StationLatitude"][0]])
                        insights["totalNumStations"] += 1

                        // setting the station to show on the map by default - true
                        this.showStations[i] = true; 
                        if (station["StationType"][0] == "DART") insights["numDartStations"] += 1;
                        else if (station["StationType"][0] == "Train") insights["numTrainStations"] += 1;
                      }

                      store.setInsights(insights);
                      loader.hide();
                      // request the user's preferences
                      this.getPreferences()
                    })
              }
              catch (error) {
                  loader.hide()
                  this.showToast(error.message, "red")
              }
            })
            .catch((error) => {
              loader.hide()
              this.showToast("Error fetching live data", "red")
            })
        },

        // method to populate the database for local testing
        postTrainAndStationData() {
            const functions = getFunctions(app);
            let host = window.location.hostname
            if (host === '127.0.0.1' || host === 'localhost') {
                connectFunctionsEmulator(functions, host, 5001);
            }

            const postTrainData = httpsCallable(functions, 'postLiveTrainData');
            postTrainData().then(() => {
              const postStationData = httpsCallable(functions, 'postStationData');
              postStationData().then(() => {
                this.getTrainAndStationData()
              })
            })
            .catch((error) => {
              this.showToast(error.message, "red")
            })
        }
    }
}
</script>

<style scoped>
.overlay-content {
  width: 1%;
}

.trainMapIcon {
  width: 28px;
  height: 32px;
}

.trainMapIcon:hover {
  width:30px;
  height:34px;
  cursor: pointer;
}

.stationMapIcon {
  width: 14px;
  height: 17px;
}

.stationMapIcon:hover {
  width: 16px;
  height: 19px;
  cursor: pointer;
}

#dropdownMenuButton1 {
  box-shadow: 0 0 5px 2px #6e757dbe;
}

#dropMenu {
  /*In case we want to edit dropdown menu*/
  font-size: 14.6px;
}

#preferenceDropdown {
  position: absolute;
  z-index: 3;
  right: 1%;
  top: 11%;
}

#prefHeader {
  font-size: 18px;
  font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
  text-align: center;
  position: relative;
}

#sidebar {
  position: absolute;
  height: 80%;
  width: 20%;
  left: 2%;
  top: 14%;
  z-index: 2;
  text-align: center;
  animation: gradient 15s ease infinite;
  background: linear-gradient(45deg, #ffffff, #fef3f3, #ffffff, #f2f2f2);
  background-size: 100%, 100%;
  box-shadow: 0 0 4px 2px #cccccc;
  overflow: hidden;
  font-family:'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif
}

#savePref {
  left:2%;
  top: 2px;
  width: 95%;
  position: relative;
}
.slideLeft-enter-active, .slideLeft-leave-active {
  transition: opacity .5s;
  transition: all 0.8s;

}
.slideLeft-enter-from, .slideLeft-leave-to {
  opacity: 0;
  transform: translateX(-100px);
}

@keyframes gradient {
  0% {
    background-position: 0% 50%;
  }
  50% {
    background-position: 100% 50%;
  }
    100% {
  background-position: 0% 50%;
  }
}

#publicMessageTicker {
  z-index: 3;
  position: absolute;
  bottom:0px;
  width:100%;
  background-color: rgb(255, 255, 125);
  color: black;
  font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
  text-align: bottom;
  font-size: 16px;
}
</style>