/*
 * Copyright (C) 2013 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "core/animation/EffectInput.h"

#include "bindings/core/v8/Dictionary.h"
#include "bindings/core/v8/DictionaryHelperForBindings.h"
#include "bindings/core/v8/DictionarySequenceOrDictionary.h"
#include "core/animation/AnimationInputHelpers.h"
#include "core/animation/CompositorAnimations.h"
#include "core/animation/KeyframeEffectModel.h"
#include "core/animation/StringKeyframe.h"
#include "core/css/CSSStyleSheet.h"
#include "core/dom/Document.h"
#include "core/dom/Element.h"
#include "core/dom/ExceptionCode.h"
#include "core/dom/NodeComputedStyle.h"
#include "core/frame/FrameConsole.h"
#include "core/frame/LocalFrame.h"
#include "core/inspector/ConsoleMessage.h"
#include "wtf/ASCIICType.h"
#include "wtf/HashSet.h"
#include "wtf/NonCopyingSort.h"

namespace blink {

namespace {

bool compareKeyframes(const RefPtr<StringKeyframe>& a,
                      const RefPtr<StringKeyframe>& b) {
  return a->offset() < b->offset();
}

// Validates the value of |offset| and throws an exception if out of range.
bool checkOffset(double offset,
                 double lastOffset,
                 ExceptionState& exceptionState) {
  // Keyframes with offsets outside the range [0.0, 1.0] are an error.
  if (std::isnan(offset)) {
    exceptionState.throwTypeError("Non numeric offset provided");
    return false;
  }

  if (offset < 0 || offset > 1) {
    exceptionState.throwTypeError("Offsets provided outside the range [0, 1]");
    return false;
  }

  if (offset < lastOffset) {
    exceptionState.throwTypeError(
        "Keyframes with specified offsets are not sorted");
    return false;
  }

  return true;
}

void setKeyframeValue(Element& element,
                      StringKeyframe& keyframe,
                      const String& property,
                      const String& value,
                      ExecutionContext* executionContext) {
  StyleSheetContents* styleSheetContents =
      element.document().elementSheet().contents();
  CSSPropertyID cssProperty =
      AnimationInputHelpers::keyframeAttributeToCSSProperty(property,
                                                            element.document());
  if (cssProperty != CSSPropertyInvalid) {
    MutableStylePropertySet::SetResult setResult =
        cssProperty == CSSPropertyVariable
            ? keyframe.setCSSPropertyValue(
                  AtomicString(property), element.document().propertyRegistry(),
                  value, styleSheetContents)
            : keyframe.setCSSPropertyValue(cssProperty, value,
                                           styleSheetContents);
    if (!setResult.didParse && executionContext) {
      Document& document = toDocument(*executionContext);
      if (document.frame()) {
        document.frame()->console().addMessage(ConsoleMessage::create(
            JSMessageSource, WarningMessageLevel,
            "Invalid keyframe value for property " + property + ": " + value));
      }
    }
    return;
  }
  cssProperty = AnimationInputHelpers::keyframeAttributeToPresentationAttribute(
      property, element);
  if (cssProperty != CSSPropertyInvalid) {
    keyframe.setPresentationAttributeValue(cssProperty, value,
                                           styleSheetContents);
    return;
  }
  const QualifiedName* svgAttribute =
      AnimationInputHelpers::keyframeAttributeToSVGAttribute(property, element);
  if (svgAttribute)
    keyframe.setSVGAttributeValue(*svgAttribute, value);
}

EffectModel* createEffectModelFromKeyframes(
    Element& element,
    const StringKeyframeVector& keyframes,
    ExceptionState& exceptionState) {
  StringKeyframeEffectModel* keyframeEffectModel =
      StringKeyframeEffectModel::create(keyframes,
                                        LinearTimingFunction::shared());
  if (!RuntimeEnabledFeatures::cssAdditiveAnimationsEnabled()) {
    for (const auto& keyframeGroup :
         keyframeEffectModel->getPropertySpecificKeyframeGroups()) {
      PropertyHandle property = keyframeGroup.key;
      if (!property.isCSSProperty())
        continue;

      for (const auto& keyframe : keyframeGroup.value->keyframes()) {
        if (keyframe->isNeutral()) {
          exceptionState.throwDOMException(
              NotSupportedError, "Partial keyframes are not supported.");
          return nullptr;
        }
        if (keyframe->composite() != EffectModel::CompositeReplace) {
          exceptionState.throwDOMException(
              NotSupportedError, "Additive animations are not supported.");
          return nullptr;
        }
      }
    }
  }

  DCHECK(!exceptionState.hadException());
  return keyframeEffectModel;
}

bool exhaustDictionaryIterator(DictionaryIterator& iterator,
                               ExecutionContext* executionContext,
                               ExceptionState& exceptionState,
                               Vector<Dictionary>& result) {
  while (iterator.next(executionContext, exceptionState)) {
    Dictionary dictionary;
    if (!iterator.valueAsDictionary(dictionary, exceptionState)) {
      exceptionState.throwTypeError("Keyframes must be objects.");
      return false;
    }
    result.push_back(dictionary);
  }
  return !exceptionState.hadException();
}

}  // namespace

// Spec: http://w3c.github.io/web-animations/#processing-a-keyframes-argument
EffectModel* EffectInput::convert(
    Element* element,
    const DictionarySequenceOrDictionary& effectInput,
    ExecutionContext* executionContext,
    ExceptionState& exceptionState) {
  if (effectInput.isNull() || !element)
    return nullptr;

  if (effectInput.isDictionarySequence()) {
    return convertArrayForm(*element, effectInput.getAsDictionarySequence(),
                            executionContext, exceptionState);
  }

  const Dictionary& dictionary = effectInput.getAsDictionary();
  DictionaryIterator iterator = dictionary.getIterator(executionContext);
  if (!iterator.isNull()) {
    // TODO(alancutter): Convert keyframes during iteration rather than after to
    // match spec.
    Vector<Dictionary> keyframeDictionaries;
    if (exhaustDictionaryIterator(iterator, executionContext, exceptionState,
                                  keyframeDictionaries)) {
      return convertArrayForm(*element, keyframeDictionaries, executionContext,
                              exceptionState);
    }
    return nullptr;
  }

  return convertObjectForm(*element, dictionary, executionContext,
                           exceptionState);
}

EffectModel* EffectInput::convertArrayForm(
    Element& element,
    const Vector<Dictionary>& keyframeDictionaries,
    ExecutionContext* executionContext,
    ExceptionState& exceptionState) {
  StringKeyframeVector keyframes;
  double lastOffset = 0;

  for (const Dictionary& keyframeDictionary : keyframeDictionaries) {
    RefPtr<StringKeyframe> keyframe = StringKeyframe::create();

    Nullable<double> offset;
    if (DictionaryHelper::get(keyframeDictionary, "offset", offset) &&
        !offset.isNull()) {
      if (!checkOffset(offset.get(), lastOffset, exceptionState))
        return nullptr;

      lastOffset = offset.get();
      keyframe->setOffset(offset.get());
    }

    String compositeString;
    DictionaryHelper::get(keyframeDictionary, "composite", compositeString);
    if (compositeString == "add")
      keyframe->setComposite(EffectModel::CompositeAdd);
    // TODO(alancutter): Support "accumulate" keyframe composition.

    String timingFunctionString;
    if (DictionaryHelper::get(keyframeDictionary, "easing",
                              timingFunctionString)) {
      RefPtr<TimingFunction> timingFunction =
          AnimationInputHelpers::parseTimingFunction(
              timingFunctionString, &element.document(), exceptionState);
      if (!timingFunction)
        return nullptr;
      keyframe->setEasing(timingFunction);
    }

    const Vector<String>& keyframeProperties =
        keyframeDictionary.getPropertyNames(exceptionState);
    if (exceptionState.hadException())
      return nullptr;
    for (const auto& property : keyframeProperties) {
      if (property == "offset" || property == "composite" ||
          property == "easing") {
        continue;
      }

      Vector<String> values;
      if (DictionaryHelper::get(keyframeDictionary, property, values)) {
        exceptionState.throwTypeError(
            "Lists of values not permitted in array-form list of keyframes");
        return nullptr;
      }

      String value;
      DictionaryHelper::get(keyframeDictionary, property, value);

      setKeyframeValue(element, *keyframe.get(), property, value,
                       executionContext);
    }
    keyframes.push_back(keyframe);
  }

  DCHECK(!exceptionState.hadException());

  return createEffectModelFromKeyframes(element, keyframes, exceptionState);
}

static bool getPropertyIndexedKeyframeValues(
    const Dictionary& keyframeDictionary,
    const String& property,
    ExecutionContext* executionContext,
    ExceptionState& exceptionState,
    Vector<String>& result) {
  DCHECK(result.isEmpty());

  // Array of strings.
  if (DictionaryHelper::get(keyframeDictionary, property, result))
    return true;

  Dictionary valuesDictionary;
  if (!keyframeDictionary.get(property, valuesDictionary) ||
      valuesDictionary.isUndefinedOrNull()) {
    // Non-object.
    String value;
    DictionaryHelper::get(keyframeDictionary, property, value);
    result.push_back(value);
    return true;
  }

  DictionaryIterator iterator = valuesDictionary.getIterator(executionContext);
  if (iterator.isNull()) {
    // Non-iterable object.
    String value;
    DictionaryHelper::get(keyframeDictionary, property, value);
    result.push_back(value);
    return true;
  }

  // Iterable object.
  while (iterator.next(executionContext, exceptionState)) {
    String value;
    if (!iterator.valueAsString(value)) {
      exceptionState.throwTypeError("Unable to read keyframe value as string.");
      return false;
    }
    result.push_back(value);
  }
  return !exceptionState.hadException();
}

EffectModel* EffectInput::convertObjectForm(
    Element& element,
    const Dictionary& keyframeDictionary,
    ExecutionContext* executionContext,
    ExceptionState& exceptionState) {
  StringKeyframeVector keyframes;

  String timingFunctionString;
  RefPtr<TimingFunction> timingFunction = nullptr;
  if (DictionaryHelper::get(keyframeDictionary, "easing",
                            timingFunctionString)) {
    timingFunction = AnimationInputHelpers::parseTimingFunction(
        timingFunctionString, &element.document(), exceptionState);
    if (!timingFunction)
      return nullptr;
  }

  Nullable<double> offset;
  if (DictionaryHelper::get(keyframeDictionary, "offset", offset) &&
      !offset.isNull()) {
    if (!checkOffset(offset.get(), 0.0, exceptionState))
      return nullptr;
  }

  String compositeString;
  DictionaryHelper::get(keyframeDictionary, "composite", compositeString);

  const Vector<String>& keyframeProperties =
      keyframeDictionary.getPropertyNames(exceptionState);
  if (exceptionState.hadException())
    return nullptr;
  for (const auto& property : keyframeProperties) {
    if (property == "offset" || property == "composite" ||
        property == "easing") {
      continue;
    }

    Vector<String> values;
    if (!getPropertyIndexedKeyframeValues(keyframeDictionary, property,
                                          executionContext, exceptionState,
                                          values))
      return nullptr;

    size_t numKeyframes = values.size();
    for (size_t i = 0; i < numKeyframes; ++i) {
      RefPtr<StringKeyframe> keyframe = StringKeyframe::create();

      if (!offset.isNull())
        keyframe->setOffset(offset.get());
      else if (numKeyframes == 1)
        keyframe->setOffset(1.0);
      else
        keyframe->setOffset(i / (numKeyframes - 1.0));

      if (timingFunction)
        keyframe->setEasing(timingFunction);

      if (compositeString == "add")
        keyframe->setComposite(EffectModel::CompositeAdd);
      // TODO(alancutter): Support "accumulate" keyframe composition.

      setKeyframeValue(element, *keyframe.get(), property, values[i],
                       executionContext);
      keyframes.push_back(keyframe);
    }
  }

  std::sort(keyframes.begin(), keyframes.end(), compareKeyframes);

  DCHECK(!exceptionState.hadException());

  return createEffectModelFromKeyframes(element, keyframes, exceptionState);
}

}  // namespace blink
