// Copyright 2010 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

goog.provide('goog.ui.TextareaTest');
goog.setTestOnly('goog.ui.TextareaTest');

goog.require('goog.dom');
goog.require('goog.dom.classlist');
goog.require('goog.events');
goog.require('goog.style');
goog.require('goog.testing.ExpectedFailures');
goog.require('goog.testing.events.EventObserver');
goog.require('goog.testing.jsunit');
goog.require('goog.ui.Textarea');
goog.require('goog.ui.TextareaRenderer');
goog.require('goog.userAgent');
goog.require('goog.userAgent.product');

var sandbox;
var textarea;
var demoTextareaElement;
var expectedFailures;

function setUp() {
  sandbox = goog.dom.getElement('sandbox');
  textarea = new goog.ui.Textarea();
  demoTextareaElement = goog.dom.getElement('demo-textarea');
  expectedFailures = new goog.testing.ExpectedFailures();
}

function tearDown() {
  expectedFailures.handleTearDown();
  textarea.dispose();
  goog.dom.removeChildren(sandbox);
}


/**
 * @return {boolean} Whether we're on Mac Safari 3.x.
 */
function isMacSafari3() {
  return goog.userAgent.WEBKIT && goog.userAgent.MAC &&
      !goog.userAgent.isVersionOrHigher('527');
}


/**
 * @return {boolean} Whether we're on Linux Firefox 3.6.3.
 */
function isLinuxFirefox() {
  return goog.userAgent.product.FIREFOX && goog.userAgent.LINUX;
}


/**
 * @return {boolean} Whether we're on Firefox 3.0.
 */
function isFirefox3() {
  return goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('1.9.1');
}

function testConstructor() {
  assertNotNull('Textarea must not be null', textarea);
  assertEquals(
      'Renderer must default to expected value',
      goog.ui.TextareaRenderer.getInstance(), textarea.getRenderer());

  var fakeDomHelper = {'getDocument': function() { return true; }};
  var testTextarea = new goog.ui.Textarea(
      'Hello', goog.ui.TextareaRenderer.getInstance(), fakeDomHelper);
  assertEquals(
      'Content must have expected content', 'Hello', testTextarea.getContent());
  assertEquals(
      'Renderer must have expected value',
      goog.ui.TextareaRenderer.getInstance(), testTextarea.getRenderer());
  assertEquals(
      'DOM helper must have expected value', fakeDomHelper,
      testTextarea.getDomHelper());
  testTextarea.dispose();
}

function testConstructorWithDecorator() {
  var decoratedTextarea = new goog.ui.Textarea();
  decoratedTextarea.decorate(demoTextareaElement);
  assertEquals(
      'Textarea should have current content after decoration', 'Foo',
      decoratedTextarea.getContent());
  var initialHeight = decoratedTextarea.getHeight_();
  var initialOffsetHeight = decoratedTextarea.getElement().offsetHeight;
  // focus() will trigger the grow/shrink flow.
  decoratedTextarea.getElement().focus();
  assertEquals(
      'Height should not have changed without content change', initialHeight,
      decoratedTextarea.getHeight_());
  assertEquals(
      'offsetHeight should not have changed without content ' +
          'change',
      initialOffsetHeight, decoratedTextarea.getElement().offsetHeight);
  decoratedTextarea.dispose();
}

function testGetSetContent() {
  textarea.render(sandbox);
  assertEquals(
      'Textarea\'s content must default to an empty string', '',
      textarea.getContent());
  textarea.setContent(17);
  assertEquals(
      'Textarea element must have expected content', '17',
      textarea.getElement().value);
  textarea.setContent('foo');
  assertEquals(
      'Textarea element must have updated content', 'foo',
      textarea.getElement().value);
}

function testGetSetValue() {
  textarea.render(sandbox);
  assertEquals(
      'Textarea\'s content must default to an empty string', '',
      textarea.getValue());
  textarea.setValue(17);
  assertEquals(
      'Textarea element must have expected content', '17', textarea.getValue());
  textarea.setValue('17');
  assertEquals(
      'Textarea element must have expected content', '17', textarea.getValue());
}

function testBasicTextareaBehavior() {
  var observer = new goog.testing.events.EventObserver();
  goog.events.listen(textarea, goog.ui.Textarea.EventType.RESIZE, observer);
  textarea.render(sandbox);
  var el = textarea.getElement();
  var heightBefore = textarea.getHeight_();
  assertTrue(
      'One resize event should be fired during render',
      observer.getEvents().length == 1);
  textarea.setContent(
      'Lorem ipsum dolor sit amet, consectetuer ' +
      'elit. Aenean sollicitudin ultrices urna. Proin vehicula mauris ac ' +
      'est. Ut scelerisque, risus ut facilisis dictum, est massa lacinia ' +
      'lorem, in fermentum purus ligula quis nunc.');
  var heightAfter = textarea.getHeight_();
  assertTrue(
      'With this much content, height should have grown.',
      heightAfter > heightBefore);
  assertTrue(
      'With a height change, a resize event should have fired.',
      observer.getEvents().length == 2);
  textarea.setContent('');
  heightAfter = textarea.getHeight_();
  assertTrue(
      'Textarea should shrink with no content.', heightAfter <= heightBefore);
  assertTrue(
      'With a height change, a resize event should have fired.',
      observer.getEvents().length == 3);
  goog.events.unlisten(textarea, goog.ui.Textarea.EventType.RESIZE, observer);
}

function testMinHeight() {
  textarea.render(sandbox);
  textarea.setMinHeight(50);
  assertEquals(
      'offsetHeight should be 50 initially', 50,
      textarea.getElement().offsetHeight);
  textarea.setContent(
      'Lorem ipsum dolor sit amet, consectetuer  ' +
      'elit. Aenean sollicitudin ultrices urna. Proin vehicula mauris ac ' +
      'est. Ut scelerisque, risus ut facilisis dictum, est massa lacinia ' +
      'lorem, in fermentum purus ligula quis nunc.');
  assertTrue('getHeight_() should be > 50', textarea.getHeight_() > 50);

  textarea.setContent('');
  assertEquals(
      'With no content, offsetHeight should go back to 50, ' +
          'the minHeight.',
      50, textarea.getElement().offsetHeight);

  expectedFailures.expectFailureFor(isMacSafari3());
  try {
    textarea.setMinHeight(0);
    assertTrue(
        'After setting minHeight to 0, offsetHeight should ' +
            'now be < 50, but it is ' + textarea.getElement().offsetHeight,
        textarea.getElement().offsetHeight < 50);
  } catch (e) {
    expectedFailures.handleException(e);
  }
}

function testMouseUpListener() {
  textarea.render(sandbox);
  textarea.setMinHeight(100);
  textarea.setMaxHeight(200);
  textarea.mouseUpListener_({});
  assertEquals(
      'After a mouseup which is not a resize, minHeight should ' +
          'still be 100',
      100, textarea.minHeight_);

  // We need to test how CSS drop shadows effect this too.
  goog.dom.classlist.add(textarea.getElement(), 'drop-shadowed');
  textarea.mouseUpListener_({});
  assertEquals(
      'After a mouseup which is not a resize, minHeight should ' +
          'still be 100 even with a shadow',
      100, textarea.minHeight_);
}

function testMaxHeight() {
  textarea.render(sandbox);
  textarea.setMaxHeight(50);
  assertTrue(
      'Initial offsetHeight should be less than 50',
      textarea.getElement().offsetHeight < 50);
  var newContent = 'Lorem ipsum dolor sit amet, consectetuer adipiscing ' +
      'elit. Aenean sollicitudin ultrices urna. Proin vehicula mauris ac ' +
      'est. Ut scelerisque, risus ut facilisis dictum, est massa lacinia ' +
      'lorem, in fermentum purus ligula quis nunc.';
  textarea.setContent(newContent);

  assertTrue(
      'With lots of content, getHeight_() should be > 50',
      textarea.getHeight_() > 50);
  assertEquals(
      'Even with lots of content, offsetHeight should be 50 ' +
          'with maxHeight set',
      50, textarea.getElement().offsetHeight);
  textarea.setMaxHeight(0);
  assertTrue(
      'After setting maxHeight to 0, offsetHeight should now ' +
          'be > 50',
      textarea.getElement().offsetHeight > 50);
}

function testMaxHeight_canShrink() {
  textarea.render(sandbox);
  textarea.setMaxHeight(50);
  assertTrue(
      'Initial offsetHeight should be less than 50',
      textarea.getElement().offsetHeight < 50);
  var newContent = 'Lorem ipsum dolor sit amet, consectetuer adipiscing ' +
      'elit. Aenean sollicitudin ultrices urna. Proin vehicula mauris ac ' +
      'est. Ut scelerisque, risus ut facilisis dictum, est massa lacinia ' +
      'lorem, in fermentum purus ligula quis nunc.';
  textarea.setContent(newContent);

  assertEquals(
      'Even with lots of content, offsetHeight should be 50 ' +
          'with maxHeight set',
      50, textarea.getElement().offsetHeight);
  textarea.setContent('');
  assertTrue(
      'With no content, offsetHeight should be back to < 50',
      textarea.getElement().offsetHeight < 50);
}

function testSetPlaceholder() {
  textarea.setPlaceholder('Some default text here.');
  textarea.setPlaceholder('new default text...');
  textarea.render(sandbox);
  if (textarea.supportsNativePlaceholder_()) {
    assertEquals('new default text...', textarea.getElement().placeholder);
  }
  assertEquals('', textarea.getValue());
  textarea.setValue('some value');
  assertEquals('some value', textarea.getValue());
  // ensure setting a new placeholder doesn't replace the value.
  textarea.setPlaceholder('some new placeholder');
  assertEquals('some value', textarea.getValue());
}

function testSetPlaceholderForInitialContent() {
  var testTextarea = new goog.ui.Textarea('initial content');
  testTextarea.render(sandbox);
  assertEquals('initial content', testTextarea.getValue());
  testTextarea.setPlaceholder('new default text...');
  assertEquals('initial content', testTextarea.getValue());
  testTextarea.setValue('new content');
  assertEquals('new content', testTextarea.getValue());
  testTextarea.setValue('');
  assertEquals('', testTextarea.getValue());
  if (!testTextarea.supportsNativePlaceholder_()) {
    // Pretend we leave the textarea. When that happens, the
    // placeholder text should appear.
    assertEquals('', testTextarea.getElement().value);
    testTextarea.blur_();
    assertEquals('new default text...', testTextarea.getElement().value);
  }
}

function testMinAndMaxHeight() {
  textarea.render(sandbox);
  textarea.setMinHeight(50);
  textarea.setMaxHeight(150);
  assertEquals(
      'offsetHeight should be 50 initially', 50,
      textarea.getElement().offsetHeight);

  textarea.setContent(
      'Lorem ipsum dolor sit amet, consectetuer  ' +
      'elit. Aenean sollicitudin ultrices urna. Proin vehicula mauris ac ' +
      'est. Ut scelerisque, risus ut facilisis dictum, est massa lacinia ' +
      'lorem, in fermentum purus ligula quis nunc.');

  var height = textarea.getHeight_();
  // For some reason Mac Safari 3 has 136 and Linux FF has 146 here.
  expectedFailures.expectFailureFor(isMacSafari3() || isLinuxFirefox());
  try {
    assertTrue(
        'With lots of content, getHeight_() should be > 150 ' +
            '(it is ' + height + ')',
        height > 150);
    assertEquals(
        'Even with lots of content, offsetHeight should be 150 ' +
            'with maxHeight set',
        150, textarea.getElement().offsetHeight);

    textarea.setMaxHeight(0);
    assertTrue(
        'After setting maxHeight to 0, offsetHeight should now ' +
            'be > 150 (it is ' + textarea.getElement().offsetHeight + ')',
        textarea.getElement().offsetHeight > 150);

    textarea.setContent('');
    textarea.setMinHeight(0);
    assertTrue(
        'After setting minHeight to 0, with no contents, ' +
            'offsetHeight should now be < 50',
        textarea.getElement().offsetHeight < 50);
  } catch (e) {
    expectedFailures.handleException(e);
  }
}

function testSetValueWhenInvisible() {
  textarea.render(sandbox);
  var content = 'Lorem ipsum dolor sit amet, consectetuer  ' +
      'elit. Aenean sollicitudin ultrices urna. Proin vehicula mauris ac ' +
      'est. Ut scelerisque, risus ut facilisis dictum, est massa lacinia ' +
      'lorem, in fermentum purus ligula quis nunc.';
  textarea.setValue(content);
  var height = textarea.getHeight_();
  var elementHeight = goog.style.getStyle(textarea.getElement(), 'height');
  assertEquals(height + 'px', elementHeight);

  // Hide the element, height_ should be invalidate when setValue().
  goog.style.setElementShown(textarea.getElement(), false);
  textarea.setValue(content);

  // Show the element again.
  goog.style.setElementShown(textarea.getElement(), true);
  textarea.setValue(content);
  height = textarea.getHeight_();
  elementHeight = goog.style.getStyle(textarea.getElement(), 'height');
  assertEquals(height + 'px', elementHeight);
}

function testSetAriaLabel() {
  assertNull(
      'Textarea must not have aria label by default', textarea.getAriaLabel());
  textarea.setAriaLabel('My textarea');
  textarea.render(sandbox);
  var element = textarea.getElementStrict();
  assertNotNull('Element must not be null', element);
  assertEquals(
      'Item element must have expected aria-label', 'My textarea',
      element.getAttribute('aria-label'));
  textarea.setAriaLabel('My new textarea');
  assertEquals(
      'Item element must have updated aria-label', 'My new textarea',
      element.getAttribute('aria-label'));
}
