/* global L -- eslint */

/**
 * @file This file contains the main JavaScript code for the app, including utility functions,
 *       app-specific behaviors, and integration with the Android environment.
 * @module app
 */

/**
 * Global flag indicating whether the app is running as a standalone app or within a browser.
 * @type {boolean}
 * @memberof module:app
 */
var isApp = typeof app !== 'undefined' || typeof android !== 'undefined';
window.isApp = isApp;

/**
 * Determines whether to use the interface for mobile devices depending on the application environment and device type.
 *
 * @function useAppPanes
 * @returns {boolean} Returns true if app panes should be used, false otherwise.
 */
window.useAppPanes = function () {
  // isSmartphone is important to disable panes in desktop mode
  return isApp && window.app.addPane && window.isSmartphone();
};
window.useAndroidPanes = window.useAppPanes; // compatibility

if (isApp) {
  if (typeof app === 'undefined') {
    // compatibility
    window.app = window.android;
  } else {
    window.android = window.app;
  }

  window.requestFile = function (callback) {
    // deprecated
    L.FileListLoader.loadFiles().on('load', function (e) {
      callback(e.file.name, e.reader.result);
    });
  };
}

/**
 * Returns a function, that, as long as it continues to be invoked, will not be triggered.
 * The function will be called after it stops being called for N milliseconds.
 * source: https://gist.github.com/nmsdvid/8807205#gistcomment-2641356
 *
 * @function debounce
 * @param {Function} callback - The function to debounce.
 * @param {number} time - The debounce time in milliseconds.
 * @returns {Function} Returns a debounced version of the given function.
 */
function debounce(callback, time) {
  var timeout;
  return function () {
    var context = this;
    var args = arguments;
    if (timeout) {
      clearTimeout(timeout);
    }
    timeout = setTimeout(function () {
      timeout = null;
      callback.apply(context, args);
    }, time);
  };
}

function extendLayerChooser() {
  if (window.app.setLayers) {
    // hook some additional code into the LayerControl so it's easy for the mobile app to interface with it
    window.LayerChooser.include({
      _setAppLayers: debounce(function () {
        var l = this.getLayers();
        window.app.setLayers(JSON.stringify(l.baseLayers), JSON.stringify(l.overlayLayers));
      }, 1000),

      setLabel: (function (setLabel) {
        return function () {
          this._setAppLayers();
          return setLabel.apply(this, arguments);
        };
      })(window.LayerChooser.prototype.setLabel),

      _update: function () {
        this._setAppLayers();
        return L.Control.Layers.prototype._update.apply(this, arguments);
      },
    });
  }
}

window.runOnAppBeforeBoot = function () {
  if (!isApp) {
    return;
  }

  if (window.app.showZoom) {
    window.mapOptions.zoomControl = window.app.showZoom();
  }

  extendLayerChooser();

  // add jquery listeners ******************************************************
  if (window.app.dialogOpened && window.app.dialogFocused) {
    $(document.body).on({
      // hints for iitc mobile
      dialogopen: function (e) {
        var id = $(e.target).data('id');
        window.app.dialogOpened(id, true);
      },
      dialogclose: function (e) {
        var id = $(e.target).data('id');
        window.app.dialogOpened(id, false);
      },
      dialogfocus: function (e) {
        var id = $(e.target).data('id');
        window.app.dialogFocused(id);
      },
    });
  }
  // notify app that a select spinner is enabled.
  // this disables javascript injection on app's side.
  // if app is not notified, the spinner closes on the next JS call
  if (window.app.spinnerEnabled) {
    $(document.body).on('click', 'select', function () {
      window.app.spinnerEnabled(true);
    });
  }

  // add iitc hooks ************************************************************
  if (window.app.switchToPane) {
    window.addHook('paneChanged', function (name) {
      // https://stackoverflow.com/a/59158952/2520247
      window.app.switchToPane(name);
    });
  }

  // overwrite some functions **************************************************
  if (window.app.copy) {
    window.androidCopy = function (text) {
      window.app.copy(text);
      return false;
    };
  }

  if (window.app.saveFile) {
    window.saveFile = function (data, filename, dataType) {
      window.app.saveFile(filename || '', dataType || '*/*', data);
    };
  }

  if (window.app.intentPosLink) {
    window.renderPortalUrl = function (lat, lng, title, guid) {
      // one share link option - and the app provides an interface to share the URL,
      // share as a geo: intent (navigation via google maps), etc

      var shareLink = $('<a>')
        .text('Share portal')
        .click(function () {
          window.app.intentPosLink(lat, lng, window.map.getZoom(), title, true, guid);
        });
      $('.linkdetails').append($('<aside>').append(shareLink));
    };
  }
};

window.runOnAppAfterBoot = function () {
  if (!isApp) {
    return;
  }

  if (window.app.intentPosLink) {
    $('#permalink').click(function (e) {
      e.preventDefault();
      var center = window.map.getCenter();
      window.app.intentPosLink(center.lat, center.lng, window.map.getZoom(), 'Selected map view', false);
    });
  }

  // add leaflet listeners *****************************************************
  if (window.app.setPermalink) {
    var setAppPermalink = function () {
      var p = window.selectedPortal && window.portals[window.selectedPortal];
      var href = window.makePermalink(p && p.getLatLng(), {
        fullURL: true,
        includeMapView: true,
      });
      window.app.setPermalink(href);
    };

    window.map.on('moveend', setAppPermalink);
    window.addHook('portalSelected', setAppPermalink);
  }

  // hide layer chooser if booted with the iitcm app
  if (window.app.setLayers) {
    $('.leaflet-control-layers').hide();
  }

  /* !!This block is commented out as it's unlikely that we still need this workaround
  //
  // for some reason, leaflet misses the WebView size being set at startup on IITC Mobile
  // create a short timer that checks for this issue
  setTimeout(function () { map.invalidateSize(); }, 0.2*1000);
  */

  if (window.app.bootFinished) {
    window.app.bootFinished();
  }
};