function waitUntilJobDone(test, success, timeout) {
  if (test()) {
    success();
    return;
  }

  // stop trying at some time
  if (timeout) {
    timeout -= 50;
    if (timeout <= 0) {
      return;
    }
  }
  window.setTimeout(function () {
    waitUntilJobDone(test, success, timeout);
  }, 50);
}

$(document).ready(function () {
  var pageIsLoaded = false;

  var letsmtTranslatePagePrefix = Tilde.PageTranslateWidgetClientConfiguration.TranslatePagePrefix ?? '';

  // when opening new page, don't start auto-translating because previous translation system is remembered in cookie
  document.cookie = 'letsmt-translation-system=;path=/;expires=' + new Date().toUTCString();

  var getQueryStringParameters = function () {
    var vars = [],
      hash;
    var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
    for (var i = 0; i < hashes.length; i++) {
      hash = hashes[i].split('=');
      vars.push(hash[0]);
      vars[hash[0]] = decodeURIComponent(hash[1]);
    }
    return vars;
  };

  var queryStringParameters = getQueryStringParameters();
  var url = queryStringParameters['url'];
  var termCorpusId = null;

  function discardMiddleClick(event) {
    if (event.which == 2) {
      event.preventDefault();
    }
  }

  $(document).on('click', discardMiddleClick);

  var iframe = $('#letsmt-translate-page-iframe')[0];
  if (iframe && iframe.contentWindow) {
    suppressMiddleClickOnNewlyLoadedDocument(iframe.contentWindow);
    if (iframe.contentWindow.document) {
      $(iframe.contentWindow.document).on('click', discardMiddleClick);
    }
  }

  var loadingPage = false;
  var showWait = function () {

    if (!loadingPage) {
      window.parent.postMessage({ message: 'startedLoading' }, '*');
      loadingPage = true;
    }

    var iframeWindow = $('#letsmt-translate-page-iframe')[0].contentWindow;
    if (iframeWindow && iframeWindow.document) {
      Tilde.oldDocument = iframeWindow.document;
    } else {
      Tilde.oldDocument = null;
    }

    if (Tilde.pageLoadTimeout) {
      window.clearTimeout(Tilde.pageLoadTimeout);
      Tilde.pageLoadTimeout = null;
    }

    Tilde.pageLoadTimeout = window.setTimeout(pageLoaded, 5000); // page load timeout
    //pageLoaded()
  };

  var hideWait = function () {
    if (Tilde.pageLoadTimeout) {
      window.clearTimeout(Tilde.pageLoadTimeout);
      Tilde.pageLoadTimeout = null;
    }

    window.parent.postMessage({ message: 'stoppedLoading' }, '*');

    loadingPage = false;
  };

  var navigateIframe = function (address, autoTranslate) {
    translateAfterLoad = autoTranslate === true;
    // when new url is entered forget previous translation system so that it does not autotranslate the page
    // this is unset in unload event, so that when navigating further by link click, previous system is remembered and auto translation happens
    // don't do this when the current page is about:blank, because unload event won't be fired thus system forgetting will actually
    // happen the next time someone clicks on a link
    forgetPreviousTranslationSystem = $('#letsmt-translate-page-iframe')[0].contentWindow.location.href != 'about:blank';

    showWait();
    address = $.trim(address);
    var lowerCaseAddress = address.toLowerCase();
    var protocol = 'http';
    if (lowerCaseAddress.indexOf('http://') == 0) {
      address = address.substring(7);
    } else if (lowerCaseAddress.indexOf('https://') == 0) {
      protocol = 'https';
      address = address.substring(8);
    }

    address = location.protocol + "//" + letsmtTranslatePagePrefix + protocol + "/" + address;
    $('#letsmt-translate-page-iframe').attr('name', 'letsmtTranslatePageIframe');
    window.open(address, 'letsmtTranslatePageIframe');
  };

  var normalizeUrl = function (url) {
    if (url?.substring(url.length - 1) == "/") {
      url = url.substring(0, url.length - 1);
    }
    return url;
  }

  var navigateOrTranslate = function (address, translateAfterLoad) {
    if (translateAfterLoad) {
      // if translate after load is requested
      // check if requested url is already loaded
      // if it is, do not reload page and just start the translation
      // even if wrong language is selected

      address = normalizeUrl(address);
      var loadedAddress = '';
      var iframeWindow = $('#letsmt-translate-page-iframe')[0].contentWindow;
      if (iframeWindow && iframeWindow.location && iframeWindow.location.href && iframeWindow.location.href !== 'about:blank') {
        loadedAddress = normalizeUrl(proxyUrlToRealUrl(iframeWindow.location.href)?.trim());
      }

      if (!address || loadedAddress != address) {
        // address is different, load page as usual
      } else {
        // address is already loaded, don't load, just start translation
        Tilde.PageTranslateWidget.translate(null, termCorpusId);
        return;
      }
    }

    navigateIframe(address, translateAfterLoad);
  };

  var translateAfterLoad = false;

  // when widget is loaded, override onTranslateClick
  waitUntilJobDone(
    function () {
      return typeof Tilde !== 'undefined' && Tilde.PageTranslateWidget && Tilde.PageTranslateWidget.loading === false;
    },
    function () {

      // set up communication between translation widget and parent page that hosts the widget page in an iframe
      Tilde.PageTranslateWidget.onSystemChange = function (systemId, changed, auto) {
        window.parent.postMessage({ message: 'systemChanged', systemId: systemId, changed: changed, auto: auto }, '*');
      };

      Tilde.PageTranslateWidget.onTranslationStart = function () {
        window.parent.postMessage({ message: 'translationStarted' }, '*');
      };

      Tilde.PageTranslateWidget.onTranslationStop = function () {
        window.parent.postMessage({ message: 'translationStopped' }, '*');
      };

      Tilde.PageTranslateWidget.onRestoreFinished = function () {
        window.parent.postMessage({ message: 'untranslated' }, '*');
      };

      Tilde.PageTranslateWidget.onTranslated = function () {
        window.parent.postMessage({ message: 'translated' }, '*');
      };

      Tilde.PageTranslateWidget.onError = function (errorMessage) {
        window.parent.postMessage({ message: 'error', description: errorMessage }, '*');
      };

      Tilde.PageTranslateWidget.onWarning = function (warningMessage) {
        window.parent.postMessage({ message: 'warning', description: warningMessage }, '*');
      };

      Tilde.PageTranslateWidget.onProgress = function (percent) {
        if (percent == 0 || percent == '0%') {
          window.parent.postMessage({ message: 'progress', progress: '1' }, '*');
        } else {
          window.parent.postMessage({ message: 'progress', progress: parseInt(percent) }, '*');
        }
      };

      window.addEventListener(
        'message',
        function (event) {
          if (event.data) {
            switch (event.data.message) {
              case 'changeSystem':
                Tilde.PageTranslateWidget.changeSystem(event.data.systemId);
                break;
              case 'loadUrl':
                pageIsLoaded = false;
                termCorpusId = event.data.termCorpusId;
                navigateOrTranslate(event.data.url, event.data.translateAfterLoad);
                break;
              case 'translate':
                if (loadingPage) {
                  window.parent.postMessage(
                    { message: 'warning', description: 'It is not safe to translate a page that is still loading.' },
                    '*'
                  );
                } else {
                  termCorpusId = event.data.termCorpusId;
                  Tilde.PageTranslateWidget.translate(null, termCorpusId);
                }
                break;
              case 'untranslate':
                Tilde.PageTranslateWidget.cancel();
                break;
              case 'setSystemList':
                Tilde.PageTranslateWidget.setTranslationSystemList(event.data.systemList);
                break;
              default:
                break;
            }
          }
        },
        false
      );

      window.parent.postMessage({ message: 'ready' }, '*');
    },
    30000
  );

  function proxyUrlToRealUrl(proxyUrl) {
    var proxyIndex = proxyUrl.indexOf(letsmtTranslatePagePrefix);
    if (proxyIndex > -1) {
      var protocolEndIndex = proxyUrl.indexOf('/', proxyIndex + letsmtTranslatePagePrefix.length);
      var protocol = proxyUrl.substring(proxyIndex + letsmtTranslatePagePrefix.length, protocolEndIndex);
      return protocol + '://' + proxyUrl.substring(protocolEndIndex + 1);
    }
    return null;
  }

  function suppressMiddleClickOnNewlyLoadedDocument(iframeWindow) {
    if (iframeWindow && iframeWindow.document) {
      $(iframeWindow).on('unload', function () {
        // wait until enough of the document is loaded to be able to attach mouseclick events
        window.setTimeout(function () {
          waitUntilJobDone(
            function () {
              return iframeWindow && iframeWindow.document;
            },
            function () {
              $(iframeWindow.document).on('click', discardMiddleClick);
            },
            60000
          );
        }, 50);
      });
    }
  }

  function onUnload() {
    //showWait();

    if (typeof Tilde !== 'undefined' && Tilde.PageTranslateWidget && Tilde.PageTranslateWidget.cancel) {
      Tilde.PageTranslateWidget.cancel(!forgetPreviousTranslationSystem, true);
      forgetPreviousTranslationSystem = false;
    }
  }

  var timesToTry = 25
  function pageLoaded() {
    const pageIframe = $('#letsmt-translate-page-iframe')[0]
    if (!pageIframe || pageIsLoaded) {
      return
    }
    --timesToTry

    var iframeWindow = pageIframe.contentWindow;

    if (iframeWindow && iframeWindow.location && iframeWindow.location.href != 'about:blank' && iframeWindow.document) {

      var stillTheSameDocument = false;
      try {
        stillTheSameDocument = iframeWindow.document === Tilde.oldDocument;
      } catch (err) {
        // if we don't have access/premission to old document
        // it means that document has changed
      }

      if (!stillTheSameDocument) {
        Tilde.pageLoadTimeout = null;
        timesToTry = 25;

        suppressMiddleClickOnNewlyLoadedDocument(iframeWindow);

        var url = proxyUrlToRealUrl(iframeWindow.location.href);
        if (url) {
          pageIsLoaded = true;

          window.parent.postMessage({ message: 'urlLoaded', url: url }, '*');
        }


        $(iframeWindow).on('unload', onUnload);

        $(iframeWindow.document).ready(function () {
          // page that needs translation could be loaded before translate widget finished loading,
          // so wait before trying to translate it
          waitUntilJobDone(
            function () {
              return typeof Tilde !== 'undefined' && Tilde.PageTranslateWidget && Tilde.PageTranslateWidget.loading === false;
            },
            function () {
              if (
                $(iframeWindow.document)
                  .find('html')
                  .hasClass('error')
              ) {
                // don't try to translate error pages generated by TranslateProxy
                // (common error messages are already localized)
                translateAfterLoad = false;

                window.parent.postMessage(
                  {
                    message: 'error',
                    description: $(iframeWindow.document)
                      .find('body')
                      .text(),
                    shownInUI: true
                  },
                  '*'
                );

              } else {
                var loadedPageLanguageCode = $(iframeWindow.document)
                  .find('html')
                  .attr('lang');

                var languageChanged = false;
                if (loadedPageLanguageCode) {
                  languageChanged = Tilde.PageTranslateWidget.setSourceLanguage(loadedPageLanguageCode.substring(0, 2));
                }

                if (translateAfterLoad) {
                  if (!languageChanged) {
                    // if page load was initiated by translate button, start translation as soon as page is loaded
                    Tilde.PageTranslateWidget.translate(null, termCorpusId);
                    translateAfterLoad = false;
                  }
                } else {
                  if (Tilde.PageTranslateWidget.autoTranslateIfNeeded) {
                    Tilde.PageTranslateWidget.autoTranslateIfNeeded();
                  }
                }
              }
            },
            30000
          );
        });

        hideWait();
        return
      }
    }

    if (timesToTry > 0) {
      tryAgain()
    }
  }

  function tryAgain() {
    --timesToTry
    setTimeout(() => {
      pageLoaded()
    }, 200);
  }

  $('#letsmt-translate-page-iframe').on('load', function () {
    if (Tilde.pageLoadTimeout) {
      window.clearTimeout(Tilde.pageLoadTimeout);
      Tilde.pageLoadTimeout = null;
      pageLoaded();
    }
  });
});
