/**
 * @license
 * Copyright The Closure Library Authors.
 * SPDX-License-Identifier: Apache-2.0
 */

goog.module('goog.editor.LinkTest');
goog.setTestOnly();

const Link = goog.require('goog.editor.Link');
const NodeType = goog.require('goog.dom.NodeType');
const Range = goog.require('goog.dom.Range');
const TagName = goog.require('goog.dom.TagName');
const dom = goog.require('goog.dom');
const testSuite = goog.require('goog.testing.testSuite');


let anchor;

testSuite({
  setUp() {
    anchor = dom.createDom(TagName.A);
    document.body.appendChild(anchor);
  },

  tearDown() {
    dom.removeNode(anchor);
  },

  testCreateNew() {
    const link = new Link(anchor, true);
    assertNotNull('Should have created object', link);
    assertTrue('Should be new', link.isNew());
    assertEquals('Should have correct anchor', anchor, link.getAnchor());
    assertEquals('Should be empty', '', link.getCurrentText());
  },

  testCreateNotNew() {
    const link = new Link(anchor, false);
    assertNotNull('Should have created object', link);
    assertFalse('Should not be new', link.isNew());
    assertEquals('Should have correct anchor', anchor, link.getAnchor());
    assertEquals('Should be empty', '', link.getCurrentText());
  },

  testCreateNewLinkFromText() {
    const url = 'http://www.google.com/';
    anchor.innerHTML = url;
    const link = Link.createNewLinkFromText(anchor);
    assertNotNull('Should have created object', link);
    assertEquals('Should have url in anchor', url, anchor.href);
  },

  testCreateNewLinkFromTextLeadingTrailingWhitespace() {
    const url = 'http://www.google.com/';
    const urlWithSpaces = ` ${url} `;
    anchor.innerHTML = urlWithSpaces;
    const urlWithSpacesUpdatedByBrowser = anchor.innerHTML;
    const link = Link.createNewLinkFromText(anchor);
    assertNotNull('Should have created object', link);
    assertEquals('Should have url in anchor', url, anchor.href);
    assertEquals(
        'The text should still have spaces', urlWithSpacesUpdatedByBrowser,
        link.getCurrentText());
  },

  testCreateNewLinkFromTextWithAnchor() {
    const url = 'https://www.google.com/';
    anchor.innerHTML = url;
    const link = Link.createNewLinkFromText(anchor, '_blank');
    assertNotNull('Should have created object', link);
    assertEquals('Should have url in anchor', url, anchor.href);
    assertEquals('Should have _blank target', '_blank', anchor.target);
  },

  testInitialize() {
    const link = Link.createNewLink(anchor, 'http://www.google.com');
    assertNotNull('Should have created object', link);
    assertTrue('Should be new', link.isNew());
    assertEquals('Should have correct anchor', anchor, link.getAnchor());
    assertEquals('Should be empty', '', link.getCurrentText());
  },

  testInitializeWithTarget() {
    const link = Link.createNewLink(anchor, 'http://www.google.com', '_blank');
    assertNotNull('Should have created object', link);
    assertTrue('Should be new', link.isNew());
    assertEquals('Should have correct anchor', anchor, link.getAnchor());
    assertEquals('Should be empty', '', link.getCurrentText());
    assertEquals('Should have _blank target', '_blank', anchor.target);
  },

  testSetText() {
    const link = Link.createNewLink(anchor, 'http://www.google.com', '_blank');
    assertEquals('Should be empty', '', link.getCurrentText());
    link.setTextAndUrl('Text', 'http://docs.google.com/');
    assertEquals(
        'Should point to http://docs.google.com/', 'http://docs.google.com/',
        anchor.href);
    assertEquals('Should have correct text', 'Text', link.getCurrentText());
  },

  testSetBoldText() {
    anchor.innerHTML = '<b></b>';
    const link = Link.createNewLink(anchor, 'http://www.google.com', '_blank');
    assertEquals('Should be empty', '', link.getCurrentText());
    link.setTextAndUrl('Text', 'http://docs.google.com/');
    assertEquals(
        'Should point to http://docs.google.com/', 'http://docs.google.com/',
        anchor.href);
    assertEquals('Should have correct text', 'Text', link.getCurrentText());
    assertEquals(
        'Should still be bold', String(TagName.B), anchor.firstChild.tagName);
  },

  testLinkImgTag() {
    anchor.innerHTML = '<img src="www.google.com" alt="alt_txt">';
    const link = Link.createNewLink(anchor, 'http://www.google.com', '_blank');
    assertEquals('Test getCurrentText', 'alt_txt', link.getCurrentText());
    link.setTextAndUrl('newText', 'http://docs.google.com/');
    assertEquals('Test getCurrentText', 'newText', link.getCurrentText());
    assertEquals(
        'Should point to http://docs.google.com/', 'http://docs.google.com/',
        anchor.href);

    assertEquals(
        'Should still have img tag', String(TagName.IMG),
        anchor.firstChild.tagName);

    assertEquals(
        'Alt should equal "newText"', 'newText',
        anchor.firstChild.getAttribute('alt'));
  },

  testLinkImgTagWithNoAlt() {
    anchor.innerHTML = '<img src="www.google.com">';
    const link = Link.createNewLink(anchor, 'http://www.google.com', '_blank');
    assertEquals('Test getCurrentText', '', link.getCurrentText());
  },

  testSetMixed() {
    anchor.innerHTML = '<b>A</b>B';
    const link = Link.createNewLink(anchor, 'http://www.google.com', '_blank');
    assertEquals('Should have text: AB', 'AB', link.getCurrentText());
    link.setTextAndUrl('Text', 'http://docs.google.com/');
    assertEquals(
        'Should point to http://docs.google.com/', 'http://docs.google.com/',
        anchor.href);
    assertEquals('Should have correct text', 'Text', link.getCurrentText());
    assertEquals(
        'Should not be bold', NodeType.TEXT, anchor.firstChild.nodeType);
  },

  testPlaceCursorRightOf() {
    // IE can only do selections properly if the region is editable.
    const ed = dom.createDom(TagName.DIV);
    dom.replaceNode(ed, anchor);
    ed.contentEditable = true;
    ed.appendChild(anchor);

    // In order to test the cursor placement properly, we need to have
    // link text.  See more details in the test below.
    dom.setTextContent(anchor, 'I am text');

    const link = Link.createNewLink(anchor, 'http://www.google.com');
    link.placeCursorRightOf();

    const range = Range.createFromWindow();
    assertTrue('Range should be collapsed', range.isCollapsed());
    const startNode = range.getStartNode();

    // Check that the selection is the "right" place.
    //
    // If you query the selection, it is actually still inside the anchor,
    // but if you type, it types outside the anchor.
    //
    // Best we can do is test that it is at the end of the anchor text.
    assertEquals(
        'Selection should be in anchor text', anchor.firstChild, startNode);
    assertEquals(
        'Selection should be at the end of the text', anchor.firstChild.length,
        range.getStartOffset());

    if (ed) {
      dom.removeNode(ed);
    }
  },

  testIsLikelyUrl() {
    const good = [
      // Proper URLs
      'http://google.com',
      'http://google.com/',
      'http://192.168.1.103',
      'http://www.google.com:8083',
      'https://antoine',
      'https://foo.foo.net',
      'ftp://google.com:22/',
      'http://user@site.com',
      'ftp://user:pass@ftp.site.com',
      'http://google.com/search?q=laser%20cats',
      'aim:goim?screenname=en2es',
      'mailto:x@y.com',

      // Bad URLs a browser will accept
      'www.google.com',
      'www.amazon.co.uk',
      'amazon.co.uk',
      'foo2.foo3.com',
      'pandora.tv',
      'marketing.us',
      'del.icio.us',
      'bridge-line.com',
      'www.frigid.net:80',
      'www.google.com?q=foo',
      'www.foo.com/j%20.txt',
      'foodtv.net',
      'google.com',
      'slashdot.org',
      '192.168.1.1',
      'justin.edu?kumar&nbsp;something',
      'google.com/search?q=hot%20pockets',

      // Due to TLD explosion, these could be URLs either now or soon.
      'ww.jester',
      'juicer.fake',
      'abs.nonsense.something',
      'filename.txt',
    ];
    let i;
    for (i = 0; i < good.length; i++) {
      assertTrue(good[i] + ' should be good', Link.isLikelyUrl(good[i]));
    }

    const bad = [
      // Definitely not URLs
      'bananas',
      'http google com',
      '<img>',
      'Sad :/',
      '*garbage!.123',
      'ftp',
      'http',
      '/',
      'https',
      'this is',
      '*!&.banana!*&!',
      'www.jester is gone.com',
      'ftp .nospaces.net',
      'www_foo_net',
      'www.\'jester\'.net',
      'www:8080',
      'www . notnsense.com',
      'email@address.com',
      '.',
      'x.',

      // URL-ish but not quite
      '  http://www.google.com',
      'http://www.google.com:8081   ',
      'www.google.com foo bar',
      'google.com/search?q=not quite',
    ];

    for (i = 0; i < bad.length; i++) {
      assertFalse(bad[i] + ' should be bad', Link.isLikelyUrl(bad[i]));
    }
  },

  testIsLikelyEmailAddress() {
    const good = [
      // Valid email addresses
      'foo@foo.com',
      'foo1@foo2.foo3.com',
      'f45_1@goog13.org',
      'user@gmail.co.uk',
      'jon-smith@crazy.net',
      'roland1@capuchino.gov',
      'ernir@gshi.nl',
      'JOON@jno.COM',
      'media@meDIa.fREnology.FR',
      'john.mail4me@del.icio.us',
      'www9@wc3.madeup1.org',
      'hi@192.168.1.103',
      'hi@192.168.1.1',
    ];
    let i;
    for (i = 0; i < good.length; i++) {
      assertTrue(Link.isLikelyEmailAddress(good[i]));
    }

    const bad = [
      // Malformed/incomplete email addresses
      'user',
      '@gmail.com',
      'user@gmail',
      'user@.com',
      'user@gmail.c',
      'user@gmail.co.u',
      '@ya.com',
      '.@hi3.nl',
      'jim.com',
      'ed:@gmail.com',
      '*!&.banana!*&!',
      ':jon@gmail.com',
      '3g?@bil.com',
      'adam be@hi.net',
      'john\nsmith@test.com',
      'www.\'jester\'.net',
      '\'james\'@covald.net',
      'ftp://user@site.com/',
      'aim:goim?screenname=en2es',
      'user:pass@site.com',
      'user@site.com yay',
    ];

    for (i = 0; i < bad.length; i++) {
      assertFalse(Link.isLikelyEmailAddress(bad[i]));
    }
  },

  /** @suppress {checkTypes} suppression added to enable type checking */
  testIsMailToLink() {
    assertFalse(Link.isMailto());
    assertFalse(Link.isMailto(null));
    assertFalse(Link.isMailto(''));
    assertFalse(Link.isMailto('http://foo.com'));
    assertFalse(Link.isMailto('http://mailto:80'));

    assertTrue(Link.isMailto('mailto:'));
    assertTrue(Link.isMailto('mailto://'));
    assertTrue(Link.isMailto('mailto://foo@gmail.com'));
  },

  testGetValidLinkFromText() {
    const textLinkPairs = [
      // input text, expected link output
      'www.foo.com',
      'http://www.foo.com',
      'user@gmail.com',
      'mailto:user@gmail.com',
      'http://www.foo.com',
      'http://www.foo.com',
      'https://this.that.edu',
      'https://this.that.edu',
      'nothing to see here',
      null,
    ];
    const link = new Link(anchor, true);

    for (let i = 0; i < textLinkPairs.length; i += 2) {
      /**
       * @suppress {strictMissingProperties} suppression added to enable type
       * checking
       */
      link.currentText_ = textLinkPairs[i];
      const result = link.getValidLinkFromText();
      assertEquals(textLinkPairs[i + 1], result);
    }
  },
});
