Home Reference Source

lib/parks/toverland/toverland.js

import fetch from 'node-fetch';
import moment from 'moment-timezone';
import {Park} from '../park.js';

import dotenv from 'dotenv';
import {entityType, queueType, scheduleType} from '../types.js';
dotenv.config();

/**
* Toverland Park Object
* Make sure all environment variables are set in an .env file which should be in the main location.
* Not setting these variables will make the module exit early without returning data.
*
* This class is here to fetch the POI data and to attach queue times data to it.
* After the fetches this data is send to the end user and from there he could do whatever he wants to do.
*
* Most park specific parameters are set already
* @class
*/
export class Toverland extends Park {
  /**
  * Create a new Toverland Park object
  * @param {object} options
  */
  constructor(options = {}) {
    options.name ='Toverland';
    options.timezone = 'Europe/Amsterdam';

    // Setting the parks entrance as latlon
    options.latitude = 51.397673285726114;
    options.longitude = 5.981651557822892;

    // Options for our park Object
    options.supportswaittimes = true;
    options.supportsschedule = true;
    options.supportsrideschedules = true;
    options.fastPass = false;
    options.FastPassReturnTimes = false;

    // API options
    options.apiBase = process.env.TOVERLAND_APIBASE;
    options.apiKey = process.env.TOVERLAND_TOKEN;
    options.hoursUrl = process.env.TOVERLAND_HOURS;

    // Language settings
    options.languages = process.env.LANGUAGES;

    options.langoptions = `{'en', 'de', 'nl'}`;

    super(options);

    // Check for existance
    if (!this.config.apiBase) throw new Error('Missing Toverland apiBase!');
    if (!this.config.apiKey) throw new Error('Missing Toverland apiKey!');
    if (!this.config.hoursUrl) throw new Error('Missing Toverland Hours URL!');
    if (!this.config.languages) {
      this.config.languages = 'en';
    };
  }

  /**
  * Get All Ride POIS of Toverland
  * This data contains all the ride POIS in Toverland.
  * @return {string} All Toverland ride POI data
  */
  async buildRidePOI() {
    return await this.cache.wrap('rides', async () => {
      return fetch(`${this.config.apiBase}/park/ride/list`,
          {
            method: 'GET',
            headers: {
              'Authorization': this.config.apiKey,
            },
          },
      ).then((res) => res.json())
          .then((ride) => {
            const poi = {};
            const lang = this.config.languages;
            ride.forEach((pois) => {
              // What a stupid area definition.
              let area = undefined;
              if (pois.area_id === '1') {
                area = 'Land van Toos';
              } else if (pois.area_id === '2') {
                area = 'Wunderwald';
              } else if (pois.area_id === '3') {
                area = 'Ithaka';
              } else if (pois.area_id === '4') {
                area = 'De Magische Vallei';
              } else if (pois.area_id === '5') {
                area = 'Port Laguna';
              } else if (pois.area_id === '6') {
                area = 'Avalon';
              }

              const descr = pois.description[lang];
              const shortdesc = pois.short_description[lang];

              let minHeightCM = undefined;
              let minHeightComp = undefined;
              if (pois.minLength !== null) {
                minHeightCM = pois.minLength + '0 cm';
              }
              if (pois.supervision !== null) {
                minHeightComp= pois.supervision + '0 cm';
              }
              const restrictions = {
                minHeight: minHeightCM,
                minHeightAccompanied: minHeightComp,
              };
              poi[pois.id] = {
                id: `Toverland_${pois.id}`,
                name: pois.name,
                location: {
                  latitude: JSON.parse(pois.latitude),
                  longitude: JSON.parse(pois.longitude),
                  area: area,
                },
                meta: {
                  description: descr,
                  short_description: shortdesc,
                  type: entityType.ride,
                  restrictions,
                },
              };
            });
            return Promise.resolve(poi);
          });
    }, 1000 * 60 * 60 * this.config.cachepoistime); // 12 hours
  };

  /**
  * Get All Restaurant POIS of Toverland
  * This data contains all the Restaurant POIS in Toverland.
  * @return {string} All Toverland Restaurant POI data
  */
  async buildRestaurantPOI() {
    return await this.cache.wrap('restaurant', async () => {
      return fetch(`${this.config.apiBase}/park/foodAndDrinks/list`,
          {
            method: 'GET',
            headers: {
              'Authorization': this.config.apiKey,
            },
          },
      ).then((res) => res.json())
          .then((ride) => {
            const poi = {};
            const lang = this.config.languages;
            ride.forEach((pois) => {
              // What a stupid area definition.
              let area = undefined;
              if (pois.area_id === '1') {
                area = 'Land van Toos';
              } else if (pois.area_id === '2') {
                area = 'Wunderwald';
              } else if (pois.area_id === '3') {
                area = 'Ithaka';
              } else if (pois.area_id === '4') {
                area = 'De Magische Vallei';
              } else if (pois.area_id === '5') {
                area = 'Port Laguna';
              } else if (pois.area_id === '6') {
                area = 'Avalon';
              }

              const descr = pois.description[lang];
              const shortdesc = pois.short_description[lang];

              poi[pois.id] = {
                id: `Toverland_${pois.id}`,
                name: pois.name,
                location: {
                  latitude: JSON.parse(pois.latitude),
                  longitude: JSON.parse(pois.longitude),
                  area: area,
                },
                meta: {
                  description: descr,
                  short_description: shortdesc,
                  type: entityType.restaurant,
                },
              };
            });
            return Promise.resolve(poi);
          });
    }, 1000 * 60 * 60 * this.config.cachepoistime); // 12 hours
  };

  /**
  * Get All POIS of Toverland
  * This data contains all the POIS in Toverland.
  * @return {string} All Toverland POI data
  */
  async buildMerchandisePOI() {
    return await this.cache.wrap('merchandise', async () => {
      return fetch(`${this.config.apiBase}/park/shop/list`,
          {
            method: 'GET',
            headers: {
              'Authorization': this.config.apiKey,
            },
          },
      ).then((res) => res.json())
          .then((ride) => {
            const poi = {};
            const lang = this.config.languages;
            ride.forEach((pois) => {
              // What a stupid area definition.
              let area = undefined;
              if (pois.area_id === '1') {
                area = 'Land van Toos';
              } else if (pois.area_id === '2') {
                area = 'Wunderwald';
              } else if (pois.area_id === '3') {
                area = 'Ithaka';
              } else if (pois.area_id === '4') {
                area = 'De Magische Vallei';
              } else if (pois.area_id === '5') {
                area = 'Port Laguna';
              } else if (pois.area_id === '6') {
                area = 'Avalon';
              }

              const descr = pois.description[lang];
              const shortdesc = pois.short_description[lang];

              poi[pois.id] = {
                id: `Toverland_${pois.id}`,
                name: pois.name,
                location: {
                  latitude: JSON.parse(pois.latitude),
                  longitude: JSON.parse(pois.longitude),
                  area: area,
                },
                meta: {
                  description: descr,
                  short_description: shortdesc,
                  type: entityType.merchandise,
                },
              };
            });
            return Promise.resolve(poi);
          });
    }, 1000 * 60 * 60 * this.config.cachepoistime); // 12 hours
  };

  /**
  * Get All POIS of Toverland
  * This data contains all the POIS in Toverland.
  * @return {string} All Toverland POI data
  */
  async buildShowPOI() {
    return await this.cache.wrap('show', async () => {
      return fetch(`${this.config.apiBase}/park/show/list`,
          {
            headers: {
              'Authorization': this.config.apiKey,
            },
          },
      ).then((res) => res.json())
          .then((ride) => {
            const poi = {};
            const lang = this.config.languages;
            ride.forEach((pois) => {
              // What a stupid area definition.
              let area = undefined;
              if (pois.area_id === '1') {
                area = 'Land van Toos';
              } else if (pois.area_id === '2') {
                area = 'Wunderwald';
              } else if (pois.area_id === '3') {
                area = 'Ithaka';
              } else if (pois.area_id === '4') {
                area = 'De Magische Vallei';
              } else if (pois.area_id === '5') {
                area = 'Port Laguna';
              } else if (pois.area_id === '6') {
                area = 'Avalon';
              }

              const descr = pois.description[lang];
              const shortdesc = pois.short_description[lang];

              poi[pois.id] = {
                id: `Toverland_${pois.id}`,
                name: pois.name,
                location: {
                  latitude: JSON.parse(pois.latitude),
                  longitude: JSON.parse(pois.longitude),
                  area: area,
                },
                meta: {
                  description: descr,
                  short_description: shortdesc,
                  type: entityType.shop,
                },
              };
            });
            return Promise.resolve(poi);
          });
    }, 1000 * 60 * 60 * this.config.cachepoistime); // 12 hours
  };

  /**
  * Get All Halloween POIS of Toverland
  * This data contains all the Halloween POIS in Toverland.
  * @return {string} All Toverland Halloween POI data
  */
  async buildHalloweenPOI() {
    return await this.cache.wrap('halloween', async () => {
      return fetch(`${this.config.apiBase}/park/halloween/list`,
          {
            method: 'GET',
            headers: {
              'Authorization': this.config.apiKey,
            },
          },
      ).then((res) => res.json())
          .then((ride) => {
            const poi = {};
            const lang = this.config.languages;
            ride.forEach((pois) => {
              // What a stupid area definition.
              let area = undefined;
              if (pois.area_id === '1') {
                area = 'Land van Toos';
              } else if (pois.area_id === '2') {
                area = 'Wunderwald';
              } else if (pois.area_id === '3') {
                area = 'Ithaka';
              } else if (pois.area_id === '4') {
                area = 'De Magische Vallei';
              } else if (pois.area_id === '5') {
                area = 'Port Laguna';
              } else if (pois.area_id === '6') {
                area = 'Avalon';
              }

              const descr = pois.description[lang];
              const shortdesc = pois.short_description[lang];

              poi[pois.id] = {
                id: `Toverland_${pois.id}`,
                name: pois.name,
                location: {
                  latitude: JSON.parse(pois.latitude),
                  longitude: JSON.parse(pois.longitude),
                  area: area,
                },
                meta: {
                  description: descr,
                  short_description: shortdesc,
                  type: entityType.halloween,
                },
              };
            });
            return Promise.resolve(poi);
          });
    }, 1000 * 60 * 60 * this.config.cachepoistime); // 12 hours
  };

  /**
  * Get All Halloween POIS of Toverland
  * This data contains all the Halloween POIS in Toverland.
  * @return {string} All Toverland Halloween POI data
  */
  async buildServicePOI() {
    return await this.cache.wrap('service', async () => {
      return fetch(`${this.config.apiBase}/park/services/list`,
          {
            method: 'GET',
            headers: {
              'Authorization': this.config.apiKey,
            },
          },
      ).then((res) => res.json())
          .then((ride) => {
            const poi = {};
            const lang = this.config.languages;
            ride.forEach((pois) => {
              // What a stupid area definition.
              let area = undefined;
              if (pois.area_id === '1') {
                area = 'Land van Toos';
              } else if (pois.area_id === '2') {
                area = 'Wunderwald';
              } else if (pois.area_id === '3') {
                area = 'Ithaka';
              } else if (pois.area_id === '4') {
                area = 'De Magische Vallei';
              } else if (pois.area_id === '5') {
                area = 'Port Laguna';
              } else if (pois.area_id === '6') {
                area = 'Avalon';
              }

              let descr = undefined;
              let shortdesc = undefined;
              if (pois.description !== null) {
                descr = pois.description[lang];
                shortdesc = pois.short_description[lang];
              } else {
                descr = undefined;
                shortdesc = undefined;
              }

              poi[pois.id] = {
                id: `Toverland_${pois.id}`,
                name: pois.name,
                location: {
                  latitude: JSON.parse(pois.latitude),
                  longitude: JSON.parse(pois.longitude),
                  area: area,
                },
                meta: {
                  description: descr,
                  short_description: shortdesc,
                  type: entityType.service,
                },
              };
            });
            return Promise.resolve(poi);
          });
    }, 1000 * 60 * 60 * this.config.cachepoistime); // 12 hours
  };

  /**
  * Build the Queue object here, cause thats cool
  * @return {string} All Ride pois with queues attached
  */
  async getQueue() {
    const rideData = await this.buildRidePOI();
    // FYI, this link actually provides the buildRidePOI data, however, I prefer doing it this way since I don't like caching queues
    return fetch(`${this.config.apiBase}/park/ride/operationInfo/list`,
        {
          method: 'GET',
          headers: {
            'Authorization': this.config.apiKey,
          },
        },
    ).then((res) => res.json())
        .then((ride) => {
          const rides = [];
          ride.forEach((poi) => {
            let state = poi.last_status.status.name.en;
            let waitTime = null;
            let active = null;
            // Ride is closed
            if (state === 'Closed') {
              waitTime = '0';
              active = false;
              state = queueType.closed;
            // Ride is open, no queue known
            } else if (state === 'Open without waiting time') {
              waitTime = '0';
              active = true;
              state = queueType.operating;
            // Ride is open at some strange unknown times, depends on where the operator is
            } else if (state === 'Variable schedule') {
              waitTime = '0';
              active = true;
              state = queueType.operating;
            // Open, but somehow the last_waiting_time disappeared. Too bad...
            } else if (state === 'Open' && !poi.last_waiting_time) {
              waitTime = '0';
              active = true;
              state = queueType.operating;
            // Finally! It is normally open!
            } else if (state === 'Open') {
              waitTime = poi.last_waiting_time.waiting_time;
              active = true;
              state = queueType.operating;
            // We'll assume ride is closed?
            } else {
              waitTime = '0';
              active = false;
              state = queueType.down;
            }

            let openTime = undefined;
            let closingTime = undefined;
            let type = undefined;
            if (Object.keys(poi.opening_times).length < 1) {
              openTime = moment('23:59', 'HH:mm').format();
              closingTime = moment('23:59', 'HH:mm').format();
              type = scheduleType.closed;
            } else {
              openTime = moment(poi.opening_times[0].start).format();
              closingTime = moment(poi.opening_times[0].end).format();
              type = scheduleType.operating;
            }

            const schedule = {
              openingTime: openTime,
              closingTime: closingTime,
              type: type,
            };

            if (rideData[poi.id]) {
              rideData[poi.id].meta.schedule = schedule; // Attach the ride schedules to the meta object.

              const rideobj = {
                id: rideData[poi.id].id,
                name: rideData[poi.id].name,
                waitTime: waitTime,
                active: active,
                status: state,
                location: rideData[poi.id].location,
                meta: rideData[poi.id].meta,
              };
              rides.push(rideobj);
            }
          });
          return Promise.resolve(rides);
        });
  }

  /**
   * Get operating hours Toverland
   * @return {string} Operating Hours for 1 week
   */
  async getOpHours() {
    const weekday = moment().format('YYYY-MM-DD');
    return fetch(`${this.config.hoursUrl}${weekday}&L=3`,
        {
          method: 'GET',
        },
    ).then((res) => res.json())
        .then((hours) => {
          const Calendar = [];
          Object.keys(hours.week).forEach((times) => {
            const date = hours.week[times].date.full;
            let open = undefined;
            let close = undefined;
            let state = undefined;
            // Park is closed
            if (hours.week[times].time_open == '00:00') {
              open = moment(`${date} 23:59`).format();
              close = moment(`${date} 23:59`).format();
              state = scheduleType.closed;
            // Park is open
            } else {
              open = moment(`${date} ${hours.week[times].time_open}`).format();
              close = moment(`${date} ${hours.week[times].time_close}`).format();
              state = scheduleType.operating;
            };
            // Create the schedule object
            const hourobj = {
              openingTime: open,
              closingTime: close,
              date: date,
              type: state,
            };
            Calendar.push(hourobj);
          });
          return Promise.resolve(Calendar);
        });
  }
}

export default Toverland;