$(function () {
  // handles shinyapps.io
  var workerId = $('base').attr('href');
  // ensure that this code does not locally
  if (typeof workerId != "undefined") {
    var pathname = window.location.pathname;
    var newpath = pathname + workerId;
    window.history.replaceState( {} , 'newpath', newpath);
  }

  // From this we can recover the workerId and the sessionId. sessionId
  // is the same recovered on the server side with session$token.
  $(document).on('shiny:sessioninitialized', function(event) {
    Shiny.setInputValue('shinyInfo', Shiny.shinyapp.config);
  });

  // Returns the last input changed (name, value, type, ...)
  $(document).on('shiny:inputchanged', function(event) {
    Shiny.setInputValue('lastInputChanged', {name: event.name, value: event.value, type: event.binding.name.split('.')[1]});
  });

  // Framework7.device is extremely useful to set up custom design
  $(document).on('shiny:connected', function(event) {
    Shiny.setInputValue('deviceInfo', Framework7.device);
  });

  // handle toolbar padding for mobiles in standalone mode
  // only if there is an appbar
  if (Framework7.device.standalone) {
    $('html, body').css({'height':'100vh', 'width':'100vw'});
    if ($('.appbar').length > 0) {
      $('.toolbar').css('margin-bottom', '20px');
    }
  }

  // fix standalone tabs height issue
  $('.tabs-standalone').css('height', 'auto');

  // handle background for dark mode
  // need to remove the custom gainsboro color background
  var dark_mode = $('html').hasClass('theme-dark');
  if (dark_mode) {
    $('.page-content').css('background-color', '');
    $('.page-content.tab, .tab').css('background-color', '');
    $('.demo-facebook-card .card-footer').css('background-color', '#1c1c1d');
    $('.sheet-modal, .swipe-handler').css('background-color', '#1b1b1d');
    $('.popup').css('background-color', '#1b1b1d');
    $('.fab-label').css('background-color', 'var(--f7-fab-label-text-color)');
    $('.fab-label').css('color', 'var(--f7-fab-text-color)');

    // fix black accordion text in dark mode
    $('.accordion-item .item-content .item-inner').css('color', 'white');
    $('.accordion-item .accordion-item-content').css('color', 'white');

    // below the sidebar id #f7-sidebar-view ensures that we do not
    // screw up the classic f7Panel style in dark mode
    // The sidebar background has to be slightly lighter than the main background
    var sidebarPanel = $('#f7-sidebar-view').find('.page-content');
    $(sidebarPanel).css('background-color', '#1e1e1e');
    // we also need to darken sidebar items in the sidebar menu
    // the default color does not contrast enough with the
    // new sidebar background
    var sidebarItems = $('#f7-sidebar-view').find('li');
    $(sidebarItems).css('background-color', '#171717');
  } else {
    $('div.messages').css('background-color', 'gainsboro');
    // fix photo browser links issue
    $('a').on('click', function() {
      setTimeout(function() {
        // we recover the body class that contains the page
        // color we set up in f7Init
        var linkColors = $('body').attr('class');
        $('.navbar-photo-browser .navbar-inner .title').css('color', 'black');
        $('.navbar-photo-browser .navbar-inner .right .popup-close').css('color', linkColors);
        $('.photo-browser-page .toolbar .toolbar-inner a').css('color', linkColors);
      }, 100);
    });
  }


      // allow for subnavbar. If a subnavbar if provided in the navbar
      // add a custom class to the page so that the subnavbar is rendered
  var subnavbar = $('.subnavbar');
  if (subnavbar.length == 1) {
   $('.page').addClass('page-with-subnavbar');
  }


  // set up notifications
  // for now, it only works for 1 notification at a time
  Shiny.addCustomMessageHandler("notif", function(message) {

    // properly treat Booleans get from R
    // R returns strings containing 'true' or 'false'
    var closeButton = (message.closeButton == 'true');
    var closeOnClick = (message.closeOnClick == 'true');
    var swipeToClose = (message.swipeToClose == 'true');

    // create the HTML icon
    var icon;
    if (message.icon !== undefined) {
      icon = '<i class="' +
      message.icon.attribs.class +'">' +
      message.icon.children[0] + '</i>';
    } else {
      icon = undefined;
    }

    var notif = app.notification.create({
      icon: icon,
      title: message.title,
      titleRightText: message.titleRightText,
      subtitle: message.subtitle,
      text: message.text,
      closeTimeout: parseInt(message.closeTimeout),
      closeOnClick: closeOnClick,
      swipeToClose: swipeToClose,
      closeButton: closeButton
    });
    // Open Notifications
    notif.open();
  });

  // set up popovers
  popoverIds = [];
  getAllPopoverIds = function() {
    //In data-popover attribute we specify CSS selector of popover we need to open
    $('[data-popover]').each(function() {
      popoverIds.push($(this).attr("data-popover"));
    });
  };

  // call the function ...
  getAllPopoverIds();

  popoverIds.forEach(function(index) {
    Shiny.addCustomMessageHandler(index, function(message) {
      var popover = app.popover.create({
        targetEl: '[data-popover = "' + index + '"]',
        content: '<div class="popover">'+
                 '<div class="popover-inner">'+
                 '<div class="block">'+
                  message.content +
                '</div>'+
                '</div>'+
                '</div>',
        // Events
        on: {
          open: function (popover) {
            console.log('Popover open');
          },
          opened: function (popover) {
            console.log('Popover opened');
          },
        }
      });
      $('[data-popover = "' + index + '"]').on('click', function() {
        popover.open();
      });
    });
  });


  // handle toasts
  Shiny.addCustomMessageHandler("toast", function(message) {

    // properly treat Booleans get from R
    // R returns strings containing 'true' or 'false'
    var closeButton = (message.closeButton == 'true');

    var toast = app.toast.create({
      icon: message.icon,
      text: message.text,
      position: message.position,
      closeButton: closeButton,
      closeTimeout: parseInt(message.closeTimeout),
      closeButtonText: message.closeButtonText,
      closeButtonColor: message.closeButtonColor
    });
    // Open Notifications
    toast.open();
  });



  // handle dialog
  Shiny.addCustomMessageHandler("dialog", function(message) {

    var type = message.type;
    switch (type) {
      case 'alert':
        var dialog = app.dialog.alert(message.text, message.title);
        break;
      case 'confirm':
        var confirm = app.dialog.confirm(
          text = message.text,
          title = message.title,
          callbackOk = function() {
            Shiny.setInputValue(message.id, true);
          },
          callbackCancel = function() {
            Shiny.setInputValue(message.id, false);
          }
        ).open(Shiny.setInputValue(message.id, null));
        //confirm.closed(Shiny.setInputValue(message.id, null));
        break;
      case 'prompt':
        var prompt = app.dialog.prompt(
          text = message.text,
          title = message.title,
          callbackOk = function(value) {
            Shiny.setInputValue(message.id, value);
          },
          callbackCancel = function() {
            Shiny.setInputValue(message.id, null);
          }
        ).open(Shiny.setInputValue(message.id, null));
        break;
      case 'login':
        console.log(login);
        var login = app.dialog.login(
          text = message.text,
          title = message.title,
          callbackOk = function (username, password) {
            Shiny.setInputValue(message.id, {user: username, password: password});
          },
          callbackCancel = function() {
            Shiny.setInputValue(message.id, null);
          }
        ).open(Shiny.setInputValue(message.id, null));
        break;
      default:
        console.log('');
    }
  });

  // handle taphold events
  Shiny.addCustomMessageHandler('tapHold', function(message) {
    var selector = String(message.target);
    $(selector).on('taphold', function() {
      eval(message.callback);
    });
  });

  // handle f7InsertTab and f7RemoveTab ...
  // recover all tabSet ids in an array
  // The idea is that we will add each respective
  // id to the Shiny.addCustomMessageHandler function
  // which first argument is the type and should be the id
  // of the targeted tabSet
  var tabIds = [];
  getAllTabSetIds = function() {
    $('.tabs.ios-edges').each(function() {
      tabIds.push(this.id);
    });
  };

  // call the function ...
  getAllTabSetIds();

  // f7InsertTab js
  tabIds.forEach(function(index) {
    var id = "insert_" + index;
    Shiny.addCustomMessageHandler(id, function(message) {
      var tabId = $("#" + message.ns + "-" + message.target);

      // for swipeable tabs
      var newTab;
      if ($(tabId).hasClass('swiper-slide')) {
        // prepare the new slide
        newTab = $(message.value).addClass('swiper-slide');
        // remove page content class for standalone tabs
        if ($('.tabLinks').children(1).hasClass('segmented')) {
          $(newTab).removeClass('page-content');
        }
        // add active if necessary
        if (message.select === "true") {
          $(newTab).addClass('swiper-slide-active');
        }
        if (dark_mode) $(newTab).css('background-color', '');
      } else {
        // remove white background for tab in dark mode
        newTab = $(message.value);
        if (dark_mode) $(newTab).css('background-color', '');
      }

      if (message.position === "after") {
        // insert after the targeted tag in the tab-panel div
        $(newTab).insertAfter($(tabId));
        // we also need to insert an item in the navigation
        $(message.link).insertAfter($('.tabLinks [href ="#' + message.ns + "-" + message.target + '"]'));
      } else if (message.position === "before") {
        // insert before the targeted tag in the tab-panel div
        $(newTab).insertBefore($(tabId));
        // we also need to insert an item in the navigation
        $(message.link).insertBefore($('.tabLinks [href ="#' + message.ns + "-" + message.target + '"]'));
      }

      // we need to transform a in button in case
      // the container has segmented class (for standalone tabs).
      // This is ignored for toolbar tabs
      if ($('.tabLinks').children(1).hasClass('segmented')) {
        var newLink;
        var oldLink = $('.tabLinks [href ="#' + message.id + '"]');
        newLink = $(oldLink)
          .replaceWith('<button class="button tab-link" href="#' + message.id + '">' + $(oldLink).html() + '</button>');
      }

      // update the swiper if needed
      if ($(tabId).hasClass('swiper-slide')) {
        // access the swiper container
        var swiper = document.querySelector('.swiper-container').swiper;
        swiper.update();
      }

      // if the newly inserted tab is active, disable other tabs
      if (message.select === "true") {
        // trigger a click on corresponding the new tab button.
        app.tab.show('#' + message.id, true);
      }
    });
  });

  // f7RemoveTab js
  tabIds.forEach(function(index) {
    var id = "remove_" + index;
    Shiny.addCustomMessageHandler(id, function(message) {
      // show the next tab first
      var tabToRemove = $('#' + message.ns + "-" + message.target);

      // important: prevent tab from translating which would lead to a
      // white screen
      $(".tabs.ios-edges").css('transform', '');

      // remove the tab link: if condition to handle the case
      // of standalone tabs vs toolbar tabs
      if (!$('.tabLinks').children(1).hasClass('segmented')) {
        $('.toolbar-inner a[href="#' + message.ns + "-" + message.target +'"]').remove();
      } else {
        var linkToRemove = $('.tabLinks button[href="#' + message.ns + "-" + message.target +'"]');
        var otherLinks = $('.tabLinks button').not('[href="#' + message.ns + "-" + message.target +'"]');
        if ($(linkToRemove).next().length === 0) {
          if (!$(otherLinks).hasClass('tab-link-active')) {
            $(linkToRemove).prev().addClass('tab-link-active');
          }
        } else {
          if (!$(otherLinks).hasClass('tab-link-active')) {
            $(linkToRemove).next().addClass('tab-link-active');
          }
        }
        $(linkToRemove).remove();
      }

      // remove the tab body content
      $('#' + message.ns + "-" + message.target).remove();

      // update the swiper if needed
      if ($(tabToRemove).hasClass('swiper-slide')) {
        // access the swiper container
        var swiper = document.querySelector('.swiper-container').swiper;
        swiper.update();
      }

      // show the next element. Need to be after the swiper update.
      var nextTabId = $(tabToRemove).next().attr('id');
      app.tab.show('#' + nextTabId);

      // we programmatically remove the old tabbar indicator and rebuild it.
      // The with of the tabbar indicator depends on the number of tab items it contains
      if (!$('.tabLinks').children(1).hasClass('segmented')) {
        $('.tab-link-highlight').remove();
        segment_width = 100 / $('.toolbar-inner > a').length;
        $('.toolbar-inner').append('<span class="tab-link-highlight" style="width: ' + segment_width + '%;"></span>');
      }
    });
  });


  // update f7Progress
  progressIds = [];
  getAllProgressIds = function() {
    $('.progressbar').each(function() {
      progressIds.push($(this).attr('id'));
    });
  };

  // call the function ...
  getAllProgressIds();

  progressIds.forEach(function(index) {
    Shiny.addCustomMessageHandler(index, function(message) {
      app.progressbar.set('#' + index, message);
    });
  });

  // show navbar
  Shiny.addCustomMessageHandler('show_navbar', function(message) {
    var animate;
    if (message.animate == "true") animate = true; else animate = false;
    app.navbar.show('.navbar', animate = message.animate);
  });

  // hide navbar
  Shiny.addCustomMessageHandler('hide_navbar', function(message) {
    var animate; var hideStatusbar;
    if (message.animate == "true") animate = true; else animate = false;
    if (message.hideStatusbar == "true") hideStatusbar = true; else hideStatusbar = false;
    app.navbar.hide(
      '.navbar',
      animate = animate,
      hideStatusbar = hideStatusbar
    );
  });


  // handle action sheet
  Shiny.addCustomMessageHandler('action-sheet', function(message) {
    var grid;
    var buttonsId = message.id + '_button';
    if (message.grid == "true") grid = true; else grid = false;

    // define function that set an inputvalue those name depends on an index
    // parameter
    function setButtonInput(index) { Shiny.setInputValue(buttonsId, index) }

    // add those functions to the message.button array
    function setOnClick(element, index) {
      Object.defineProperty(element, 'onClick', {
        value: function() {setButtonInput(index + 1);},
        writable: false
      });
    }

    message.buttons.forEach(setOnClick);

    // create the sheet
    var actionSheet = app.actions.create({
      //el: message.id,
      grid: grid,
      buttons: message.buttons,
      // below we set up events to set/update input values for Shiny
      on: {
        opened: function () {
          Shiny.setInputValue(message.id, true);
        },
        closed: function () {
          Shiny.setInputValue(message.id, false);
          // input$button is null when the action is closed
          Shiny.setInputValue(buttonsId, null);
        }
      }
    });
    // open the sheet
    actionSheet.open();
  });


  // pull to refresh
  // add the preoloader tag dynamically
  // We use the App root data feature
  if (app.data.pullToRefresh) {
    const ptrLoader = $(
      '<div class="ptr-preloader">' +
      '<div class="preloader"></div>' +
      '<div class="ptr-arrow"></div>' +
      '</div>'
    );

    // add useful classes to the page content
    $('.page-content')
      .addClass('ptr-content')
      .prepend(ptrLoader)
      .attr('data-ptr-distance', '55')
      .attr('data-ptr-mousewheel', 'true');

    // we need to create the ptr manually since it
    // is added after the page initialization
    app.ptr.create('.ptr-content');
	  var ptr = app.ptr.get('.ptr-content');
	  // Add 'refresh' listener on it
	  ptr.on('refresh', function(e) {
	    // Emulate 2s loading
	    Shiny.setInputValue('ptr', true);
	    setTimeout(function () {
	      app.ptr.done();
	    }, 2000);
	  });

    // reset input. This will prevent observeEvent from
    // always being fired since they ignore NULL by default.
    // Therefore, instead of setting ptr to FALSE, we set it
    // to null
    ptr.on('done', function(e) {
      Shiny.setInputValue('ptr', null);
    });
  }

  // validate inputs (see f7ValidateInput)
  Shiny.addCustomMessageHandler('validate-input', function(message) {
    $('#' + message.target)
      .attr('required','')
      .attr('validate', '')
      .attr('pattern', message.pattern)
      .attr('data-error-message', message.error);

    $('#' + message.target).closest('.item-content.item-input').addClass('item-input-with-info');
    var infoTag;
    if (message.info !== undefined) {
      infoTag = '<div class = "item-input-info">' + message.info + '</div>';
    }
    $('#' + message.target).parent().append(infoTag);
  });


  // preloader
  Shiny.addCustomMessageHandler('show-preloader', function(message) {
    if (typeof message.el !== 'undefined') {
      app.preloader.showIn(message.el, message.color);
    } else {
      app.preloader.show(message.color);
    }
  });

   Shiny.addCustomMessageHandler('hide-preloader', function(message) {
    if (typeof message.el !== 'undefined') {
      app.preloader.hideIn(message.el);
    } else {
      app.preloader.hide();
    }
  });
});
