// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

library created_callback_test;
import 'package:unittest/unittest.dart';
import 'package:unittest/html_config.dart';
import 'dart:html';
import 'dart:js' as js;
import '../utils.dart';

class A extends HtmlElement {
  static final tag = 'x-a';
  factory A() => new Element.tag(tag);
  A.created() : super.created() {
    createdInvocations++;
  }

  static int createdInvocations = 0;
}

class B extends HtmlElement {
  static final tag = 'x-b';
  factory B() => new Element.tag(tag);
  B.created() : super.created();
}

class C extends HtmlElement {
  static final tag = 'x-c';
  factory C() => new Element.tag(tag);
  C.created() : super.created() {
    createdInvocations++;

    if (this.id != 'u') {
      return;
    }

    var t = div.query('#t');
    var v = div.query('#v');
    var w = div.query('#w');

    expect(query('x-b:not(:unresolved)'), this);
    expect(queryAll(':unresolved'), [v, w]);

    // As per:
    // http://www.w3.org/TR/2013/WD-custom-elements-20130514/#serializing-and-parsing
    // creation order is t, u, v, w (postorder).
    expect(t is C, isTrue);
    // Note, this is different from JavaScript where this would be false.
    expect(v is C, isTrue);
  }

  static int createdInvocations = 0;
  static var div;
}

main() {
  useHtmlConfiguration();

  // Adapted from Blink's
  // fast/dom/custom/created-callback test.

  var registered = false;
  setUp(() {
    return customElementsReady.then((_) {
      if (!registered) {
        registered = true;
        document.registerElement(B.tag, B);
        document.registerElement(C.tag, C);
        ErrorConstructorElement.register();
      }
    });
  });

  test('transfer created callback', () {
    document.registerElement(A.tag, A);
    var x = new A();
    expect(A.createdInvocations, 1);
  });

  test('unresolved and created callback timing', () {
    var div = new DivElement();
    C.div = div;
    div.setInnerHtml("""
<x-c id="t"></x-c>
<x-b id="u"></x-b>
<x-c id="v"></x-c>
<x-b id="w"></x-b>
""", treeSanitizer: NodeTreeSanitizer.trusted);

    upgradeCustomElements(div);

    expect(C.createdInvocations, 2);
    expect(div.query('#w') is B, isTrue);
  });

  test('nesting of constructors', NestedElement.test);

  test('access while upgrading gets unupgraded element',
      AccessWhileUpgradingElement.test);

  test('cannot call created constructor', () {
    expect(() {
      new B.created();
    }, throws);
  });

  test('cannot register without created', () {
    expect(() {
      document.registerElement(MissingCreatedElement.tag,
          MissingCreatedElement);
    }, throws);
  });

  test('throw on createElement does not upgrade', () {
    ErrorConstructorElement.callCount = 0;

    var e;
    expectGlobalError(() {
      e = new Element.tag(ErrorConstructorElement.tag);
    });
    expect(ErrorConstructorElement.callCount, 1);
    expect(e is HtmlElement, isTrue);
    expect(e is ErrorConstructorElement, isFalse);

    var dummy = new DivElement();
    dummy.append(e);
    e = dummy.firstChild;
    expect(ErrorConstructorElement.callCount, 1);
  });

  test('throw on innerHtml does not upgrade', () {
    ErrorConstructorElement.callCount = 0;

    var dummy = new DivElement();
    var tag = ErrorConstructorElement.tag;
    expectGlobalError(() {
      dummy.setInnerHtml('<$tag></$tag>',
          treeSanitizer: NodeTreeSanitizer.trusted);
    });

    expect(ErrorConstructorElement.callCount, 1);

    var e = dummy.firstChild;
    // Accessing should not re-run the constructor.
    expect(ErrorConstructorElement.callCount, 1);
    expect(e is HtmlElement, isTrue);
    expect(e is ErrorConstructorElement, isFalse);
  });

  test('cannot register created with params', () {
    expect(() {
      document.registerElement('x-created-with-params',
          CreatedWithParametersElement);
    }, throws);
  });

  test('created cannot be called from nested constructor',
      NestedCreatedConstructorElement.test);


  // TODO(vsm): Port additional test from upstream here:
  // http://src.chromium.org/viewvc/blink/trunk/LayoutTests/fast/dom/custom/created-callback.html?r1=156141&r2=156185
}


class NestedElement extends HtmlElement {
  static final tag = 'x-nested';

  final Element b = new B();

  factory NestedElement() => new Element.tag(tag);
  NestedElement.created() : super.created();

  static void register() {
    document.registerElement(tag, NestedElement);
  }

  static void test() {
    register();

    var e = new NestedElement();
    expect(e.b, isNotNull);
    expect(e.b is B, isTrue);
    expect(e is NestedElement, isTrue);
  }
}


class AccessWhileUpgradingElement extends HtmlElement {
  static final tag = 'x-access-while-upgrading';

  static Element upgradingContext;
  static Element upgradingContextChild;

  final foo = runInitializerCode();

  factory AccessWhileUpgradingElement() => new Element.tag(tag);
  AccessWhileUpgradingElement.created() : super.created();

  static runInitializerCode() {
    upgradingContextChild = upgradingContext.firstChild;

    return 666;
  }

  static void register() {
    document.registerElement(tag, AccessWhileUpgradingElement);
  }

  static void test() {
    register();

    upgradingContext = new DivElement();
    upgradingContext.setInnerHtml('<$tag></$tag>',
        treeSanitizer: new NullTreeSanitizer());
    var child = upgradingContext.firstChild;

    expect(child.foo, 666);
    expect(upgradingContextChild is HtmlElement, isFalse);
    expect(upgradingContextChild is AccessWhileUpgradingElement, isFalse,
        reason: 'Elements accessed while upgrading should not be upgraded.');
  }
}

class MissingCreatedElement extends HtmlElement {
  static final tag = 'x-missing-created';

  factory MissingCreatedElement() => new Element.tag(tag);
}

class ErrorConstructorElement extends HtmlElement {
  static final tag = 'x-throws-in-constructor';
  static int callCount = 0;

  factory ErrorConstructorElement() => new Element.tag(tag);

  ErrorConstructorElement.created() : super.created() {
    ++callCount;
    throw new Exception('Just messin with ya');
  }

  static void register() {
    document.registerElement(tag, ErrorConstructorElement);
  }
}

class NestedCreatedConstructorElement extends HtmlElement {
  static final tag = 'x-nested-created-constructor';

  // Should not be able to call this here.
  final B b = constructB();
  static B constructedB;

  factory NestedCreatedConstructorElement() => new Element.tag(tag);
  NestedCreatedConstructorElement.created() : super.created();

  static void register() {
    document.registerElement(tag, NestedCreatedConstructorElement);
  }

  // Try to run the created constructor, and record the results.
  static constructB() {
    // This should throw an exception.
    constructedB = new B.created();
    return constructedB;
  }

  static void test() {
    register();

    // Exception should have occurred on upgrade.
    var e;
    expectGlobalError(() {
      e = new Element.tag(tag);
    });
    expect(e is NestedCreatedConstructorElement, isFalse);
    expect(e is HtmlElement, isTrue);
    // Should not have been set.
    expect(constructedB, isNull);
  }
}

class CreatedWithParametersElement extends HtmlElement {
  CreatedWithParametersElement.created(ignoredParam) : super.created();
}

void expectGlobalError(Function test) {
  js.context['testExpectsGlobalError'] = true;
  try {
    test();
  } catch(e) {
    rethrow;
  } finally {
    js.context['testExpectsGlobalError'] = false;
  }
  var errors = js.context['testSuppressedGlobalErrors'];
  expect(errors['length'], 1);
  // Clear out the errors;
  js.context['testSuppressedGlobalErrors']['length'] = 0;
}
