goog.provide('webfont.FontWatcher');

goog.require('webfont.FontWatchRunner'); goog.require('webfont.NativeFontWatchRunner');

/**

* @typedef {Object.<string, Array.<string>>}
*/

webfont.FontTestStrings;

/**

* @constructor
* @param {webfont.DomHelper} domHelper
* @param {webfont.EventDispatcher} eventDispatcher
* @param {number=} opt_timeout
*/

webfont.FontWatcher = function(domHelper, eventDispatcher, opt_timeout) {

this.domHelper_ = domHelper;
this.eventDispatcher_ = eventDispatcher;
this.currentlyWatched_ = 0;
this.last_ = false;
this.success_ = false;
this.timeout_ = opt_timeout;

};

goog.scope(function () {

var FontWatcher = webfont.FontWatcher,
    FontWatchRunner = webfont.FontWatchRunner,
    NativeFontWatchRunner = webfont.NativeFontWatchRunner;

/**
 * @type {null|boolean}
 */
FontWatcher.SHOULD_USE_NATIVE_LOADER = null;

/**
 * @return {string}
 */
FontWatcher.getUserAgent = function () {
  return window.navigator.userAgent;
};

/**
 * @return {string}
 */
FontWatcher.getVendor = function () {
  return window.navigator.vendor;
};

/**
 * Returns true if this browser has support for
 * the CSS font loading API.
 *
 * @return {boolean}
 */
FontWatcher.shouldUseNativeLoader = function () {
  if (FontWatcher.SHOULD_USE_NATIVE_LOADER === null) {
    if (!!window.FontFace) {
      var match = /Gecko.*Firefox\/(\d+)/.exec(FontWatcher.getUserAgent());
      var safari10Match = /OS X.*Version\/10\..*Safari/.exec(FontWatcher.getUserAgent()) && /Apple/.exec(FontWatcher.getVendor());

      if (match) {
        FontWatcher.SHOULD_USE_NATIVE_LOADER = parseInt(match[1], 10) > 42;
      } else if (safari10Match) {
        FontWatcher.SHOULD_USE_NATIVE_LOADER = false;
      } else {
        FontWatcher.SHOULD_USE_NATIVE_LOADER = true;
      }
    } else {
      FontWatcher.SHOULD_USE_NATIVE_LOADER = false;
    }
  }
  return FontWatcher.SHOULD_USE_NATIVE_LOADER;
};

/**
 * Watches a set of font families.
 * @param {Array.<webfont.Font>} fonts The fonts to watch.
 * @param {webfont.FontTestStrings} fontTestStrings The font test strings for
 *     each family.
 * @param {Object.<String, boolean>} metricCompatibleFonts
 * @param {boolean} last True if this is the last set of fonts to watch.
 */
FontWatcher.prototype.watchFonts = function(fonts,
    fontTestStrings, metricCompatibleFonts, last) {
  var length = fonts.length,
      testStrings = fontTestStrings || {};

  if (length === 0 && last) {
    this.eventDispatcher_.dispatchInactive();
    return;
  }

  this.currentlyWatched_ += fonts.length;

  if (last) {
    this.last_ = last;
  }

  var i, fontWatchRunners = [];
  for (i = 0; i < fonts.length; i++) {
    var font = fonts[i],
        testString = testStrings[font.getName()];

    this.eventDispatcher_.dispatchFontLoading(font);

    var fontWatchRunner = null;

    if (FontWatcher.shouldUseNativeLoader()) {
      fontWatchRunner = new NativeFontWatchRunner(
          goog.bind(this.fontActive_, this),
          goog.bind(this.fontInactive_, this),
          this.domHelper_,
          font,
          this.timeout_,
          testString
        );
    } else {
      fontWatchRunner = new FontWatchRunner(
        goog.bind(this.fontActive_, this),
        goog.bind(this.fontInactive_, this),
        this.domHelper_,
        font,
        this.timeout_,
        metricCompatibleFonts,
        testString
      );
    }

    fontWatchRunners.push(fontWatchRunner);
  }

  for (i = 0; i < fontWatchRunners.length; i++) {
    fontWatchRunners[i].start();
  }
};

/**
 * Called by a FontWatchRunner when a font has been detected as active.
 * @param {webfont.Font} font
 * @private
 */
FontWatcher.prototype.fontActive_ = function(font) {
  this.eventDispatcher_.dispatchFontActive(font);
  this.success_ = true;
  this.decreaseCurrentlyWatched_();
};

/**
 * Called by a FontWatchRunner when a font has been detected as inactive.
 * @param {webfont.Font} font
 * @private
 */
FontWatcher.prototype.fontInactive_ = function(font) {
  this.eventDispatcher_.dispatchFontInactive(font);
  this.decreaseCurrentlyWatched_();
};

/**
 * @private
 */
FontWatcher.prototype.decreaseCurrentlyWatched_ = function() {
  if (--this.currentlyWatched_ == 0 && this.last_) {
    if (this.success_) {
      this.eventDispatcher_.dispatchActive();
    } else {
      this.eventDispatcher_.dispatchInactive();
    }
  }
};

});