/*
 * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 *
 */

#include "config.h"
#include "StepRange.h"

#include "HTMLNames.h"
#include "HTMLParserIdioms.h"
#include <wtf/MathExtras.h>
#include <wtf/NeverDestroyed.h>

namespace WebCore {

using namespace HTMLNames;

StepRange::StepRange()
    : m_maximum(100)
    , m_minimum(0)
    , m_step(1)
    , m_stepBase(0)
    , m_stepDescription()
{
}

StepRange::StepRange(const StepRange& stepRange)
    : m_maximum(stepRange.m_maximum)
    , m_minimum(stepRange.m_minimum)
    , m_step(stepRange.m_step)
    , m_stepBase(stepRange.m_stepBase)
    , m_stepDescription(stepRange.m_stepDescription)
    , m_hasRangeLimitations(stepRange.m_hasRangeLimitations)
    , m_hasStep(stepRange.m_hasStep)
{
}

StepRange::StepRange(const Decimal& stepBase, RangeLimitations rangeLimitations, const Decimal& minimum, const Decimal& maximum, const Decimal& step, const StepDescription& stepDescription)
    : m_maximum(maximum)
    , m_minimum(minimum)
    , m_step(step.isFinite() ? step : 1)
    , m_stepBase(stepBase.isFinite() ? stepBase : 1)
    , m_stepDescription(stepDescription)
    , m_hasRangeLimitations(rangeLimitations == RangeLimitations::Valid)
    , m_hasStep(step.isFinite())
{
    ASSERT(m_maximum.isFinite());
    ASSERT(m_minimum.isFinite());
    ASSERT(m_step.isFinite());
    ASSERT(m_stepBase.isFinite());
}

Decimal StepRange::acceptableError() const
{
    // FIXME: We should use DBL_MANT_DIG instead of FLT_MANT_DIG regarding to HTML5 specification.
    static NeverDestroyed<const Decimal> twoPowerOfFloatMantissaBits(Decimal::Positive, 0, UINT64_C(1) << FLT_MANT_DIG);
    return m_stepDescription.stepValueShouldBe == StepValueShouldBeReal ? m_step / twoPowerOfFloatMantissaBits : Decimal(0);
}

Decimal StepRange::alignValueForStep(const Decimal& currentValue, const Decimal& newValue) const
{
    static NeverDestroyed<const Decimal> tenPowerOf21(Decimal::Positive, 21, 1);
    if (newValue >= tenPowerOf21)
        return newValue;

    return stepMismatch(currentValue) ? newValue : roundByStep(newValue, m_stepBase);
}

Decimal StepRange::clampValue(const Decimal& value) const
{
    const Decimal inRangeValue = std::max(m_minimum, std::min(value, m_maximum));
    if (!m_hasStep)
        return inRangeValue;
    // Rounds inRangeValue to minimum + N * step.
    const Decimal roundedValue = roundByStep(inRangeValue, m_minimum);
    const Decimal clampedValue = roundedValue > m_maximum ? roundedValue - m_step : roundedValue;
    ASSERT(clampedValue >= m_minimum);
    ASSERT(clampedValue <= m_maximum);
    return clampedValue;
}

Decimal StepRange::parseStep(AnyStepHandling anyStepHandling, const StepDescription& stepDescription, const String& stepString)
{
    if (stepString.isEmpty())
        return stepDescription.defaultValue();

    if (equalLettersIgnoringASCIICase(stepString, "any")) {
        switch (anyStepHandling) {
        case RejectAny:
            return Decimal::nan();
        case AnyIsDefaultStep:
            return stepDescription.defaultValue();
        default:
            ASSERT_NOT_REACHED();
        }
    }

    Decimal step = parseToDecimalForNumberType(stepString);
    if (!step.isFinite() || step <= 0)
        return stepDescription.defaultValue();

    switch (stepDescription.stepValueShouldBe) {
    case StepValueShouldBeReal:
        step *= stepDescription.stepScaleFactor;
        break;
    case ParsedStepValueShouldBeInteger:
        // For date, month, and week, the parsed value should be an integer for some types.
        step = std::max(step.round(), Decimal(1));
        step *= stepDescription.stepScaleFactor;
        break;
    case ScaledStepValueShouldBeInteger:
        // For datetime, datetime-local, time, the result should be an integer.
        step *= stepDescription.stepScaleFactor;
        step = std::max(step.round(), Decimal(1));
        break;
    default:
        ASSERT_NOT_REACHED();
    }

    ASSERT(step > 0);
    return step;
}

Decimal StepRange::roundByStep(const Decimal& value, const Decimal& base) const
{
    return base + ((value - base) / m_step).round() * m_step;
}

bool StepRange::stepMismatch(const Decimal& valueForCheck) const
{
    if (!m_hasStep)
        return false;
    if (!valueForCheck.isFinite())
        return false;
    const Decimal value = (valueForCheck - m_stepBase).abs();
    if (!value.isFinite())
        return false;
    // Decimal's fractional part size is DBL_MAN_DIG-bit. If the current value
    // is greater than step*2^DBL_MANT_DIG, the following computation for
    // remainder makes no sense.
    static NeverDestroyed<const Decimal> twoPowerOfDoubleMantissaBits(Decimal::Positive, 0, UINT64_C(1) << DBL_MANT_DIG);
    if (value / twoPowerOfDoubleMantissaBits > m_step)
        return false;
    // The computation follows HTML5 4.10.7.2.10 `The step attribute' :
    // ... that number subtracted from the step base is not an integral multiple
    // of the allowed value step, the element is suffering from a step mismatch.
    const Decimal remainder = (value - m_step * (value / m_step).round()).abs();
    // Accepts erros in lower fractional part which IEEE 754 single-precision
    // can't represent.
    const Decimal computedAcceptableError = acceptableError();
    return computedAcceptableError < remainder && remainder < (m_step - computedAcceptableError);
}

} // namespace WebCore
