// Copyright 2009 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.events.FileDropHandlerTest');
goog.setTestOnly('goog.events.FileDropHandlerTest');

goog.require('goog.events');
goog.require('goog.events.BrowserEvent');
goog.require('goog.events.EventTarget');
goog.require('goog.events.EventType');
goog.require('goog.events.FileDropHandler');
goog.require('goog.testing.jsunit');
goog.require('goog.userAgent');

var textarea;
var doc;
var handler;
var dnd;
var files;

function setUp() {
  textarea = new goog.events.EventTarget();
  doc = new goog.events.EventTarget();
  textarea.ownerDocument = doc;
  handler = new goog.events.FileDropHandler(textarea);
  dnd = false;
  files = null;
  goog.events.listen(
      handler, goog.events.FileDropHandler.EventType.DROP, function(e) {
        dnd = true;
        files = e.getBrowserEvent().dataTransfer.files;
      });
}

function tearDown() {
  textarea.dispose();
  doc.dispose();
  handler.dispose();
}

function testOneFile() {
  var preventDefault = false;
  var expectedfiles = [{fileName: 'file1.jpg'}];
  var dt = {types: ['Files'], files: expectedfiles};

  // Assert that default actions are prevented on dragenter.
  textarea.dispatchEvent(new goog.events.BrowserEvent({
    preventDefault: function() { preventDefault = true; },
    type: goog.events.EventType.DRAGENTER,
    dataTransfer: dt
  }));
  assertTrue(preventDefault);
  preventDefault = false;

  // Assert that default actions are prevented on dragover.
  textarea.dispatchEvent(new goog.events.BrowserEvent({
    preventDefault: function() { preventDefault = true; },
    type: goog.events.EventType.DRAGOVER,
    dataTransfer: dt
  }));
  assertTrue(preventDefault);
  preventDefault = false;
  // Assert that the drop effect is set to 'copy'.
  assertEquals('copy', dt.dropEffect);

  // Assert that default actions are prevented on drop.
  textarea.dispatchEvent(new goog.events.BrowserEvent({
    preventDefault: function() { preventDefault = true; },
    type: goog.events.EventType.DROP,
    dataTransfer: dt
  }));
  assertTrue(preventDefault);

  // Assert that DROP has been fired.
  assertTrue(dnd);
  assertEquals(1, files.length);
  assertEquals(expectedfiles[0].fileName, files[0].fileName);
}

function testMultipleFiles() {
  var preventDefault = false;
  var expectedfiles = [{fileName: 'file1.jpg'}, {fileName: 'file2.jpg'}];
  var dt = {types: ['Files', 'text'], files: expectedfiles};

  // Assert that default actions are prevented on dragenter.
  textarea.dispatchEvent(new goog.events.BrowserEvent({
    preventDefault: function() { preventDefault = true; },
    type: goog.events.EventType.DRAGENTER,
    dataTransfer: dt
  }));
  assertTrue(preventDefault);
  preventDefault = false;

  // Assert that default actions are prevented on dragover.
  textarea.dispatchEvent(new goog.events.BrowserEvent({
    preventDefault: function() { preventDefault = true; },
    type: goog.events.EventType.DRAGOVER,
    dataTransfer: dt
  }));
  assertTrue(preventDefault);
  preventDefault = false;
  // Assert that the drop effect is set to 'copy'.
  assertEquals('copy', dt.dropEffect);

  // Assert that default actions are prevented on drop.
  textarea.dispatchEvent(new goog.events.BrowserEvent({
    preventDefault: function() { preventDefault = true; },
    type: goog.events.EventType.DROP,
    dataTransfer: dt
  }));
  assertTrue(preventDefault);

  // Assert that DROP has been fired.
  assertTrue(dnd);
  assertEquals(2, files.length);
  assertEquals(expectedfiles[0].fileName, files[0].fileName);
  assertEquals(expectedfiles[1].fileName, files[1].fileName);
}

function testNoFiles() {
  var preventDefault = false;
  var dt = {types: ['text']};

  // Assert that default actions are not prevented on dragenter.
  textarea.dispatchEvent(new goog.events.BrowserEvent({
    preventDefault: function() { preventDefault = true; },
    type: goog.events.EventType.DRAGENTER,
    dataTransfer: dt
  }));
  assertFalse(preventDefault);
  preventDefault = false;

  // Assert that default actions are not prevented on dragover.
  textarea.dispatchEvent(new goog.events.BrowserEvent({
    preventDefault: function() { preventDefault = true; },
    type: goog.events.EventType.DRAGOVER,
    dataTransfer: dt
  }));
  assertFalse(preventDefault);
  preventDefault = false;

  // Assert that default actions are not prevented on drop.
  textarea.dispatchEvent(new goog.events.BrowserEvent({
    preventDefault: function() { preventDefault = true; },
    type: goog.events.EventType.DROP,
    dataTransfer: dt
  }));
  assertFalse(preventDefault);

  // Assert that DROP has not been fired.
  assertFalse(dnd);
  assertNull(files);
}

function testDragEnter() {
  var preventDefault = false;

  // Assert that default actions are prevented on dragenter.
  // In Chrome the dragenter event has an empty file list and the types is
  // set to 'Files'.
  textarea.dispatchEvent(new goog.events.BrowserEvent({
    preventDefault: function() { preventDefault = true; },
    type: goog.events.EventType.DRAGENTER,
    dataTransfer: {types: ['Files'], files: []}
  }));
  assertTrue(preventDefault);
  preventDefault = false;

  // Assert that default actions are prevented on dragenter.
  // In Safari 4 the dragenter event has an empty file list and the types is
  // set to 'public.file-url'.
  textarea.dispatchEvent(new goog.events.BrowserEvent({
    preventDefault: function() { preventDefault = true; },
    type: goog.events.EventType.DRAGENTER,
    dataTransfer: {types: ['public.file-url'], files: []}
  }));
  assertTrue(preventDefault);
  preventDefault = false;

  // Assert that default actions are not prevented on dragenter
  // when the drag contains no files.
  textarea.dispatchEvent(new goog.events.BrowserEvent({
    preventDefault: function() { preventDefault = true; },
    type: goog.events.EventType.DRAGENTER,
    dataTransfer: {types: ['text'], files: []}
  }));
  assertFalse(preventDefault);
}

function testPreventDropOutside() {
  var preventDefault = false;
  var dt = {types: ['Files'], files: [{fileName: 'file1.jpg'}]};

  // Assert that default actions are not prevented on dragenter on the
  // document outside the text area.
  doc.dispatchEvent(new goog.events.BrowserEvent({
    preventDefault: function() { preventDefault = true; },
    type: goog.events.EventType.DRAGENTER,
    dataTransfer: dt
  }));
  assertFalse(preventDefault);
  preventDefault = false;

  // Assert that default actions are not prevented on dragover on the
  // document outside the text area.
  doc.dispatchEvent(new goog.events.BrowserEvent({
    preventDefault: function() { preventDefault = true; },
    type: goog.events.EventType.DRAGOVER,
    dataTransfer: dt
  }));
  assertFalse(preventDefault);
  preventDefault = false;

  handler.dispose();
  // Create a new FileDropHandler that prevents drops outside the text area.
  handler = new goog.events.FileDropHandler(textarea, true);

  // Assert that default actions are now prevented on dragenter on the
  // document outside the text area.
  doc.dispatchEvent(new goog.events.BrowserEvent({
    preventDefault: function() { preventDefault = true; },
    type: goog.events.EventType.DRAGENTER,
    dataTransfer: dt
  }));
  assertTrue(preventDefault);
  preventDefault = false;

  // Assert that default actions are now prevented on dragover on the
  // document outside the text area.
  doc.dispatchEvent(new goog.events.BrowserEvent({
    preventDefault: function() { preventDefault = true; },
    type: goog.events.EventType.DRAGOVER,
    dataTransfer: dt
  }));
  assertTrue(preventDefault);
  preventDefault = false;
  // Assert also that the drop effect is set to 'none'.
  assertEquals('none', dt.dropEffect);
}

function testEffectAllowedExceptionIsCaught() {
  // This bug was only affecting IE10+.
  if (!goog.userAgent.IE || !goog.userAgent.isVersionOrHigher(10)) {
    return;
  }

  var preventDefault = false;
  var expectedfiles = [{fileName: 'file1.jpg'}];
  var dt = {types: ['Files'], files: expectedfiles};

  // We construct a mock DataTransfer object that define a setter will throw
  // SCRIPT65535 when attempt to set property effectAllowed to simulate IE Bug
  // #811625. See more: https://github.com/google/closure-library/issues/485.
  Object.defineProperty(
      dt, 'effectAllowed',
      {set: function(v) { throw new Error('SCRIPT65535'); }});

  // Assert that default actions are prevented on dragenter.
  textarea.dispatchEvent(new goog.events.BrowserEvent({
    preventDefault: function() { preventDefault = true; },
    type: goog.events.EventType.DRAGENTER,
    dataTransfer: dt
  }));
  assertTrue(preventDefault);
  preventDefault = false;

  // Assert that default actions are prevented on dragover.
  textarea.dispatchEvent(new goog.events.BrowserEvent({
    preventDefault: function() { preventDefault = true; },
    type: goog.events.EventType.DRAGOVER,
    dataTransfer: dt
  }));
  assertTrue(preventDefault);
}
