/**
 * Copyright (c) Tiny Technologies, Inc. All rights reserved.
 * Licensed under the LGPL or a commercial license.
 * For LGPL see License.txt in the project root for license information.
 * For commercial licenses see https://www.tiny.cloud/
 */

import { URL } from '@ephox/sand';
import { navigator, window, matchMedia, document } from '@ephox/dom-globals';

/**
 * This class contains various environment constants like browser versions etc.
 * Normally you don't want to sniff specific browser versions but sometimes you have
 * to when it's impossible to feature detect. So use this with care.
 *
 * @class tinymce.Env
 * @static
 */

const nav = navigator, userAgent = nav.userAgent;
let opera, webkit, ie, ie11, ie12, gecko, mac, iDevice, android, fileApi, phone, tablet, windowsPhone;

const matchMediaQuery = function (query) {
  return 'matchMedia' in window ? matchMedia(query).matches : false;
};

opera = false;
android = /Android/.test(userAgent);
webkit = /WebKit/.test(userAgent);
ie = !webkit && !opera && (/MSIE/gi).test(userAgent) && (/Explorer/gi).test(nav.appName);
ie = ie && /MSIE (\w+)\./.exec(userAgent)[1];
ie11 = userAgent.indexOf('Trident/') !== -1 && (userAgent.indexOf('rv:') !== -1 || nav.appName.indexOf('Netscape') !== -1) ? 11 : false;
ie12 = (userAgent.indexOf('Edge/') !== -1 && !ie && !ie11) ? 12 : false;
ie = ie || ie11 || ie12;
gecko = !webkit && !ie11 && /Gecko/.test(userAgent);
mac = userAgent.indexOf('Mac') !== -1;
iDevice = /(iPad|iPhone)/.test(userAgent);
fileApi = 'FormData' in window && 'FileReader' in window && 'URL' in window && !!URL.createObjectURL;
phone = matchMediaQuery('only screen and (max-device-width: 480px)') && (android || iDevice);
tablet = matchMediaQuery('only screen and (min-width: 800px)') && (android || iDevice);
windowsPhone = userAgent.indexOf('Windows Phone') !== -1;

if (ie12) {
  webkit = false;
}

// Is a iPad/iPhone and not on iOS5 sniff the WebKit version since older iOS WebKit versions
// says it has contentEditable support but there is no visible caret.
const contentEditable = !iDevice || fileApi || parseInt(userAgent.match(/AppleWebKit\/(\d*)/)[1], 10) >= 534;

export default {
  /**
   * Constant that is true if the browser is Opera.
   *
   * @property opera
   * @type Boolean
   * @final
   */
  opera,

  /**
   * Constant that is true if the browser is WebKit (Safari/Chrome).
   *
   * @property webKit
   * @type Boolean
   * @final
   */
  webkit,

  /**
   * Constant that is more than zero if the browser is IE.
   *
   * @property ie
   * @type Boolean
   * @final
   */
  ie,

  /**
   * Constant that is true if the browser is Gecko.
   *
   * @property gecko
   * @type Boolean
   * @final
   */
  gecko,

  /**
   * Constant that is true if the os is Mac OS.
   *
   * @property mac
   * @type Boolean
   * @final
   */
  mac,

  /**
   * Constant that is true if the os is iOS.
   *
   * @property iOS
   * @type Boolean
   * @final
   */
  iOS: iDevice,

  /**
   * Constant that is true if the os is android.
   *
   * @property android
   * @type Boolean
   * @final
   */
  android,

  /**
   * Constant that is true if the browser supports editing.
   *
   * @property contentEditable
   * @type Boolean
   * @final
   */
  contentEditable,

  /**
   * Transparent image data url.
   *
   * @property transparentSrc
   * @type Boolean
   * @final
   */
  transparentSrc: 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',

  /**
   * Returns true/false if the browser can or can't place the caret after a inline block like an image.
   *
   * @property noCaretAfter
   * @type Boolean
   * @final
   */
  caretAfter: ie !== 8,

  /**
   * Constant that is true if the browser supports native DOM Ranges. IE 9+.
   *
   * @property range
   * @type Boolean
   */
  range: window.getSelection && 'Range' in window,

  /**
   * Returns the IE document mode for non IE browsers this will fake IE 10.
   *
   * @property documentMode
   * @type Number
   */
  documentMode: ie && !ie12 ? ((<any> document).documentMode || 7) : 10,

  /**
   * Constant that is true if the browser has a modern file api.
   *
   * @property fileApi
   * @type Boolean
   */
  fileApi,

  /**
   * Constant that is true if the browser supports contentEditable=false regions.
   *
   * @property ceFalse
   * @type Boolean
   */
  ceFalse: (ie === false || ie > 8),

  cacheSuffix: null,
  container: null,
  overrideViewPort: null,
  experimentalShadowDom: false,

  /**
   * Constant if CSP mode is possible or not. Meaning we can't use script urls for the iframe.
   */
  canHaveCSP: (ie === false || ie > 11),

  desktop: !phone && !tablet,
  windowsPhone
};