/*
 * EdGEL: The University of Edinburgh Experience Language.
 * Cookie Consent Settings JS File.
 */
/*
 * Polyfills.
 */
if (!Object.entries) {
  Object.entries = function (obj) {
    'use strict';

    var ownProps = Object.keys(obj);
    var i = ownProps.length;
    var resArray = new Array(i); // preallocate the Array
    while (i--)
      resArray[i] = [ownProps[i], obj[ownProps[i]]];

    return resArray;
  };
}

if (!Element.prototype.matches) {
  Element.prototype.matches = Element.prototype.msMatchesSelector ||
    Element.prototype.webkitMatchesSelector;
}

var EdGel = EdGel || {};

(function (global) {
  'use strict';

  global.EdGel.cookieSettings = global.EdGel.cookieSettings || (function () {
    var loaded = false;
    var version = 3;
    var permissions = {
      necessary: {
        mandatory: true,
        isDefault: true
      },
      advertising: {
        mandatory: false,
        isDefault: true
      }
    };
    var selectableOptions = {
        all: {
          permissions: ['advertising','necessary'],
          label: 'I\'m OK with personalised ads',
          cssClass: 'cookie-radio-secondary',
          selected: false
        },
        necessaryOnly: {
          permissions: ['necessary'],
          label: 'I do not want to see personalised ads',
          cssClass: 'cookie-radio-secondary',
          selected: false
        }
      };
    var _values = {};
    var subscribers = [];
    var bootstrapped = false;

    function getValues() {
      var values = {}

      for (var permission in permissions) {
        if (_values.hasOwnProperty(permission)) {
          values[permission] = _values[permission]
        }
        else {
          values[permission] = false
        }
      }

      return values
    }

    function reset() {
      loaded = false
      _values = {}
    }

    function load(cDomain) {
      reset();

      var stored = readPrefs(cDomain);

      _values = stored;
      loaded = true;

      // If we are missing any mandatory values, we
      // don't have a valid load.
      for (var permission in permissions) {
        if (permissions[permission].mandatory && !stored.hasOwnProperty(permission)) {
          loaded = false;
        }
      }
    }

    function readPrefs(cDomain) {
      var decodedCookie = decodeURIComponent(document.cookie)
      var allCookies = decodedCookie.split(';')
      var json = ''
      var cookieName = '_uoeCookiePrefsV' + version

      for (var i = 0; i < allCookies.length; i++) {
        var curr = allCookies[i].trim()

        if (curr.indexOf(cookieName + '=') == 0) {
          json = curr.substring((cookieName).length + 1, curr.length)
        }
      }

      var parsed = {}
      if (json != '') {
        var requiresUpdate = false
        try {
          // If we have raw JSON string encode this since the value can cause
          // problems with other systems: I180531-0649
          if (json.indexOf('{') == 0) {
            requiresUpdate = true
          }
          else {
            json = global.atob(json)
          }
          parsed = JSON.parse(json)
        }
        catch (e) {
          parsed = {}
        }
        if (requiresUpdate) {
          writeCookie(cDomain, parsed)
        }
      }

      return parsed
    }

    function savePrefs(cDomain, defaults) {
      var i

      // the first time we save the cookie settings for this version, we wipe all previous cookie settings.
      if (!loaded) {
        var d = new Date();
        d.setTime(d.getTime() - (60 * 60 * 1000)); // set expired date 1 hour ago
        var expires = 'expires=' + d.toUTCString();

        document.cookie = '_uoeCookiePrefs=;' + expires + ';domain=' + cDomain + ';path=/';
        for (i = 0; i < version; i++) {
          document.cookie = '_uoeCookiePrefsV' + version + '=;' + expires + ';domain=' + cDomain + ';path=/';
        }
      }

      for (var permission in permissions) {
        _values[permission] = permissions[permission].mandatory
      }

      if (defaults) {
        for (permission in permissions) {
          _values[permission] = _values[permission] || permissions[permission].isDefault
        }
      }
      else {
        // Iterate over all radios in #cookiePrefs.
        var cookiePrefs = document.getElementById('cookiePrefs')

        if (cookiePrefs !== null) {
          var inputs = cookiePrefs.getElementsByTagName('INPUT')
          for (i = 0; i < inputs.length; i++) {
            if (inputs[i].matches('[data-cookie-choice]') && inputs[i].checked) {
              var perms = inputs[i].value.split(',')
              for (var j = 0; j < perms.length; j++) {
                _values[perms[j]] = true
              }
            }
          }
        }
      }
      loaded = true;
      writeCookie(cDomain, _values)
    }

    function writeCookie(cDomain, cValue) {
      var timeOutDays = 365
      var d = new Date()
      d.setTime(d.getTime() + (timeOutDays * 24 * 60 * 60 * 1000))
      var expires = 'expires=' + d.toUTCString()
      var cookieName = '_uoeCookiePrefsV' + version

      cValue = JSON.stringify(cValue)
      cValue = global.btoa(cValue)

      document.cookie = cookieName + '=' + cValue + ';' + expires + ';domain=' + cDomain + ';path=/'

      // Confirm that the write worked.
      var decodedCookie = decodeURIComponent(document.cookie)
      var allCookies = decodedCookie.split(';')
      var json = ''

      for (var c = 0; c < allCookies.length; c++) {
        var curr = allCookies[c].trim()

        if (curr.indexOf(cookieName + '=') == 0) {
          json = curr.substring((cookieName).length + 1, curr.length)
        }
      }

      if (json != cValue) { // doing straight comparison of btoa values.
        setError('Cookie setting write failed. Check the cookie domain (' + cDomain + ').')
        loaded = false
      }

      // Notify subscribers that a change has happened.
      for (var i = 0; i < subscribers.length; i++) {
        subscribers[i]()
      }
    }

    function editPrefs(cDomain, cookiePrefsFormView) {
      var cookiePrefsOptionsView = []
      var i
      var oneOptionSelected = false

      for (var option in selectableOptions) {
        selectableOptions[option].selected = false
        selectableOptions[option].merged = selectableOptions[option].permissions.sort().join()
      }

      load(cDomain)

      if (loaded) {
        var active = Object.entries(getValues())
          .filter(function (a) { return a[1]})
          .map(function (a) { return a[0]})
          .sort()
          .join()
        for (option in selectableOptions) {
          if (selectableOptions[option].merged === active) {
            selectableOptions[option].selected = true
            oneOptionSelected = true
          }
        }
      }

      for (option in selectableOptions) {
        cookiePrefsOptionsView.push(selectableOptions[option])
      }

      cookiePrefsFormView.settings = cookiePrefsOptionsView
      cookiePrefsFormView.oneOptionSelected = oneOptionSelected

      var cookieJar = document.getElementById('cookie-jar')
      var cookieLid = document.getElementById('cookie-lid')
      if (cookieJar !== null) { // Open the jar
        cookieJar.innerHTML = nunjucks.render('uoe-cookies-preferences.njk', cookiePrefsFormView)
        // when hidden, the maxHeight is set to 0px
        if (cookieJar.style.display !== '') {
          cookieJar.style.display = ''
          setTimeout(function () {
            cookieJar.style.maxHeight = '500px'
            cookieJar.style.padding = '' // takes the CSS value
          }, 10)
        }
      }
      var htmlTags = document.getElementsByTagName('HTML')
      for (i = 0; i < htmlTags.length; i++) {
        htmlTags[i].scrollTop = 0
      }
      var bodyTags = document.getElementsByTagName('BODY')
      for (i = 0; i < bodyTags.length; i++) {
        bodyTags[i].scrollTop = 0
      }
      if (cookieLid !== null) { // close the lid
        // when shown, the maxHeight & maxWidth are set to blank to allow responsive
        // set them to current size, then shrink to zero
        if (cookieLid.style.display === '') {
          cookieLid.style.maxWidth = cookieLid.offsetWidth + 'px' // from blank so no transition.
          cookieLid.style.maxHeight = cookieLid.offsetHeight + 'px' // from blank so no transition.
          cookieLid.style.padding = '' // takes the CSS value
          setTimeout(function () {
            cookieLid.style.maxWidth = '0px'
            cookieLid.style.maxHeight = '0px'
            cookieLid.style.padding = '0px'
          }, 10)
        }
      }
    }

    var errors = []

    function setError(error) {
      errors.push(error)
      // Use of console.error requires the devel:true jshint setting
      console.error(error)
    }

    return {
      allowed: function (permission) {
        var prefs = getValues()
        return prefs[permission]
      },

      allowedList: function () {
        var prefs = getValues()
        var allowed = []

        for (var pref in prefs) {
          if (prefs[pref]) {
            allowed.push(pref)
          }
        }

        return allowed.sort().join()
      },

      bannerRequired: function () {
        return !(this.hasSavedSettings())
      },

      hasSavedSettings: function () {
        return loaded
      },

      cookieDomain: '.ed.ac.uk',

      cookieInfoView: {
        link: 'https://www.ed.ac.uk/about/website/privacy',
        heading: 'Cookies on the University of Edinburgh website',
        text: [
          'We use cookies for security purposes, remembering your preferences ' +
          'and to analyse site traffic to understand our users\' behaviour. ' +
          'This includes anonymised Google Analytics data.',
          'We\'d also like to show you personalised ads (such as reminders of ' +
          'our Open Days) when you are on other websites and/or social media ' +
          'platforms. We will do this by sharing information with our selected ' +
          'advertising partners. We won\'t share your data with anyone else.'
        ]
      },

      cookiePrefsFormView: {
        heading: 'Change my cookie settings for the University of Edinburgh website',
        explanation: [
          {
            heading: 'We use cookies',
            text: 'Cookies are a common feature used on almost all websites. We use cookies for different reasons, ' +
              'including measuring your visits to our sites and remembering your preferences.',
            link: {
              label: 'Learn more about necessary cookies',
              url: 'https://www.ed.ac.uk/about/website/privacy/necessary-cookies'
            }
          },
          {
            heading: 'Set your personalised ads preferences',
            text: 'We work with advertising partners to show you ads for events and services you might be interested ' +
              'in, such as open days. You can choose whether the ads you see are personalised by selecting one of ' +
              'the options below.',
            link: {
              label: 'Learn more about advertising cookies',
              url: 'https://www.ed.ac.uk/about/website/privacy/advertising-cookies'
            }
          },
          {
            text: 'You can always revisit these settings by clicking on the link at the bottom of all web pages.'
          }
        ]
      },

      bootstrap: function () {
        if (!bootstrapped) {
          load(this.cookieDomain)

          // Attach callbacks to banner buttons. Also allows access to object methods etc within events
          var _this = this;

          document.addEventListener('click', function (e) {
              if (!e.target) {
                return false
              }
              if (e.target.matches('button[data-cookie-save]')) { // has no clickable subelements
                savePrefs(_this.cookieDomain, false)
                // Re-open the banner; it should close to the lid
                _this.openBanner(true)
                return false
              }
              if (e.target.matches('button[data-cookie-save-default]')) { // has no clickable subelements
                savePrefs(_this.cookieDomain, true)
                // Re-open the banner; it should close to the lid
                _this.openBanner(true)
                return false
              }
              if (e.target.matches('button[data-cookie-change]')) { // has no clickable subelements
                editPrefs(_this.cookieDomain, _this.cookiePrefsFormView)
                return false
              }
              if (e.target.matches('div.cookie-check')) {
                // clicked on surround div, so click on the radio button
                var children = e.target.getElementsByTagName('INPUT');
                for (var i = 0; i < children.length; i++) {
                  children[i].click()
                }
                return false
              }
            });
          document.addEventListener('change', function (e) {
            if (e.target.matches('input[data-cookie-choice]')) {
              var cookieSaveButton = document.getElementById('edgel-cookie-btn-save-settings')
              cookieSaveButton.disabled = ''
              return true
            }
          });

          bootstrapped = true
        }
      },

      openBanner: function (animate) {
        var cookieJar = document.getElementById('cookie-jar')
        var cookieLid = document.getElementById('cookie-lid')

        // Reload preferences from _uoeCookiePrefsV* cookie, if present.
        load(this.cookieDomain)

        if (errors.length > 0) {
          cookieJar.innerHTML = 'ERROR WITH GEL COOKIE SETTINGS :</br>' + errors.join('<br/>')
          cookieJar.style.display = ''
          cookieJar.style.maxHeight = ''
          cookieJar.style.padding = ''
          cookieLid.style.display = 'none' // immediately hides
        }
        else if (this.bannerRequired()) {
          cookieJar.innerHTML = nunjucks.render('uoe-cookies-banner.njk', this.cookieInfoView);
          if (animate) {
            if (cookieJar.style.display !== '') { // when hidden, the maxHeight is set to 0px
              cookieJar.style.display = ''
              setTimeout(function () {
                cookieJar.style.maxHeight = '500px'
                cookieJar.style.padding = ''
              }, 10)
            }
            if (cookieLid.style.display === '') { // when shown, the maxHeight & maxWidth are set to blank to allow responsive
              cookieLid.style.maxWidth =  cookieLid.offsetWidth + 'px'; // from blank so no transition.
              cookieLid.style.maxHeight = cookieLid.offsetHeight + 'px'; // from blank so no transition.
              setTimeout(function () {
                cookieLid.style.maxWidth = '0px'
                cookieLid.style.maxHeight = '0px'
                cookieLid.style.padding = '0px'
              }, 10)
            }
            else {
              cookieLid.style.maxWidth = '0px'
              cookieLid.style.maxHeight = '0px'
              cookieLid.style.padding = '0px'
            }
          }
          else {
            cookieJar.style.display = ''
            cookieJar.style.maxHeight = '' // to blank so will not transition
            cookieJar.style.padding = ''
            cookieLid.style.display = 'none' // immediately hides
            cookieLid.style.maxWidth = '0px'
            cookieLid.style.maxHeight = '0px'
            cookieLid.style.padding = '0px'
          }
        }
        else {
          // Show the floating button that allows access to change settings.
          cookieLid.innerHTML = nunjucks.render('uoe-cookies-lid.njk', this.cookieInfoView)
          if (animate) {
            if (cookieJar.style.display === '') { // when shown, the maxHeight & maxWidth are set to blank to allow responsive
              cookieJar.style.maxHeight = cookieJar.offsetHeight + 'px'; // from blank so no transition.
              setTimeout(function () {
                cookieJar.style.maxHeight = '0px'
                cookieJar.style.padding = '0px'
              }, 10)
            }
            if (cookieLid.style.display !== '') { // when hidden, the maxHeight is set to 0px
              cookieLid.style.display = ''
              setTimeout(function () {
                cookieLid.style.maxWidth = '200px'
                cookieLid.style.maxHeight = '60px'
                cookieLid.style.padding = ''
              }, 10)
            }
          }
          else {
            cookieJar.style.display = 'none' // immediately hides
            cookieJar.style.maxHeight = '0px'
            cookieJar.style.padding = '0px'
            // Lid will be rendered full size immediately.
            cookieLid.style.display = ''
            cookieLid.style.maxWidth = '' // to blank so will not transition
            cookieLid.style.maxHeight = ''
            cookieLid.style.padding = ''
          }
        }
      },

      // Add a subscriber function to be called whenever settings are changed
      // or successfully loaded.
      subscribe: function (fn) {
        subscribers.push(fn);

        // Do an initial call to the subscriber function so it can initialise.
        fn()
      },

      // Deprecated : Allow extra departmental permissions to be added to the banner.
      addPermission: function () {
        // this requires the devel:true jshint setting
        console.warn('DEPRECATED: Cookie addPermission can no longer be used to add extra departmental permissions')
      },

      setCookiesSettings: function (domain, mainHeading, prefsHeading, necessaryUrl, advertUrl) {
        var checkDomain = domain
        var splitScheme
        var splitUrl

        if (checkDomain.charAt(0) == '.') {
          checkDomain = checkDomain.substring(1)
        }

        this.cookieDomain = domain
        this.cookieInfoView.heading = mainHeading
        this.cookiePrefsFormView.heading = prefsHeading

        // check domains in URLs: assume scheme provided, and no user/password.
        if (typeof necessaryUrl == 'string') {
          splitScheme = necessaryUrl.split('//')
          if (splitScheme.length == 2) {
            splitUrl = splitScheme[1].split('/')
            if (splitUrl[0] != checkDomain &&
                (splitUrl[0].length < domain.length ||
                  splitUrl[0].substring(splitUrl[0].length - domain.length) != domain)) {
              setError('Mismatch between Cookie necessary link hostname (' + splitUrl[0] + ') and domain (' + checkDomain + ').')
            }
          } else {
            setError('Could not extract domain from Cookie necessary link - scheme may be missing: ' + necessaryUrl)
          }
          this.cookiePrefsFormView.explanation[0].link.url = necessaryUrl
        } else {
          setError('Cookie necessary link must be a string')
        }
        if (typeof advertUrl == 'string') {
          splitScheme = advertUrl.split('//')
          if (splitScheme.length == 2) {
            splitUrl = splitScheme[1].split('/')
            if (splitUrl[0] != checkDomain &&
                (splitUrl[0].length < domain.length ||
                  splitUrl[0].substring(splitUrl[0].length - domain.length) != domain)) {
              setError('Mismatch between Cookie advertising link hostname (' + splitUrl[0] + ') and domain (' + checkDomain + ').')
            }
          } else {
            setError('Could not extract domain from Cookie advertising link - scheme may be missing: ' + advertUrl)
          }
          this.cookiePrefsFormView.explanation[1].link.url = advertUrl
        } else {
          setError('Cookie advertising link must be a string')
        }
      }
    }
  })();

  // Preload cookie settings ready for subscribers.
  global.EdGel.cookieSettings.bootstrap()

  document.addEventListener('DOMContentLoaded', function () {

    function finishLidTransition(event) {
      // there may be other transitions... Lid transitions in height and width
      if (event.propertyName === 'max-width') {
        var cookieLid = document.getElementById('cookie-lid')
        if (cookieLid.style.maxWidth === '0px') {
          // just finished closing the lid
          cookieLid.style.display = 'none'
        } else {
          // just finished opening the lid
          // remove the max* to allow responsive, to blank so no transition
          cookieLid.style.maxWidth = ''
          cookieLid.style.maxHeight = ''
          // the padding was set to blank to take on CSS value, so no need to set here
        }
      }
    }

    function finishJarTransition(event) {
      // there may be other transitions... Jar only transitions in height
      if (event.propertyName === 'max-height') {
        var cookieJar = document.getElementById('cookie-jar')
        if (cookieJar.style.maxHeight === '0px') {
          // just finished closing the Jar
          cookieJar.style.display = 'none'
        } else {
          // just finished opening the Jar
          // remove the max* to allow responsive, to blank so no transition
          cookieJar.style.maxHeight = ''
          // the padding was set to blank to take on CSS value, so no need to set here
        }
      }
    }

    /* From Modernizr */
    function whichTransitionEvent(el) {

      var transitions = {
        transition      : 'transitionend',
        OTransition     : 'oTransitionEnd',
        MozTransition   : 'transitionend',
        WebkitTransition: 'webkitTransitionEnd'
      }

      for (var t in transitions){
        if (el.style[t] !== undefined){
          return transitions[t];
        }
      }
    }

    var body = document.getElementsByTagName('BODY')
    var cookieJar = document.createElement('div')
    var cookieLid = document.createElement('div')
    var transitionEvent = whichTransitionEvent(cookieJar)

    cookieJar.setAttribute('id', 'cookie-jar')
    cookieJar.setAttribute('class', 'cookie-jar')
    cookieJar.addEventListener(transitionEvent, finishJarTransition)

    cookieLid.setAttribute('id', 'cookie-lid')
    cookieLid.setAttribute('class', 'cookie-lid')
    cookieLid.addEventListener(transitionEvent, finishLidTransition)

    for (var i = 0; i < body.length; i++) {
      // Add a div for the main banner for cookie settings. Defaults to closed.
      cookieJar.style.display = 'none'
      cookieJar.style.transition = 'max-height 400ms linear 0s, padding 400ms'
      cookieJar.style.overflow = 'hidden'
      cookieJar.style.padding = '0px'
      cookieJar.style.maxHeight = '0px'
      body[i].insertBefore(cookieJar, body[i].firstChild)
      // Add a div for the small panel to allow changing cookie options. Defaults to closed.
      cookieLid.style.display = 'none'
      cookieLid.style.transition = 'max-width 400ms, max-height 400ms, padding 400ms'
      cookieLid.style.overflow = 'hidden'
      cookieLid.style.padding = '0px'
      cookieLid.style.maxWidth = '0px'
      cookieLid.style.maxHeight = '0px'
      body[i].insertBefore(cookieLid, null)
    }

    EdGel.cookieSettings.openBanner(false)
  });

})(this);
