/*
 * Copyright (C) 2021 Apple 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:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "config.h"
#include "TemporalCalendarPrototype.h"

#include "BuiltinNames.h"
#include "IteratorOperations.h"
#include "JSCInlines.h"
#include "ObjectConstructor.h"
#include "TemporalCalendar.h"

namespace JSC {

static JSC_DECLARE_HOST_FUNCTION(temporalCalendarPrototypeFuncFields);
static JSC_DECLARE_HOST_FUNCTION(temporalCalendarPrototypeFuncMergeFields);
static JSC_DECLARE_HOST_FUNCTION(temporalCalendarPrototypeFuncToString);
static JSC_DECLARE_HOST_FUNCTION(temporalCalendarPrototypeFuncToJSON);
static JSC_DECLARE_CUSTOM_GETTER(temporalCalendarPrototypeGetterId);

}

#include "TemporalCalendarPrototype.lut.h"

namespace JSC {

const ClassInfo TemporalCalendarPrototype::s_info = { "Temporal.Calendar"_s, &Base::s_info, &temporalCalendarPrototypeTable, nullptr, CREATE_METHOD_TABLE(TemporalCalendarPrototype) };

/* Source for TemporalCalendarPrototype.lut.h
@begin temporalCalendarPrototypeTable
    fields          temporalCalendarPrototypeFuncFields       DontEnum|Function 1
    mergeFields     temporalCalendarPrototypeFuncMergeFields  DontEnum|Function 2
    toString        temporalCalendarPrototypeFuncToString     DontEnum|Function 0
    toJSON          temporalCalendarPrototypeFuncToJSON       DontEnum|Function 0
    id              temporalCalendarPrototypeGetterId         ReadOnly|DontEnum|CustomAccessor
@end
*/

TemporalCalendarPrototype* TemporalCalendarPrototype::create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
{
    TemporalCalendarPrototype* object = new (NotNull, allocateCell<TemporalCalendarPrototype>(vm)) TemporalCalendarPrototype(vm, structure);
    object->finishCreation(vm, globalObject);
    return object;
}

Structure* TemporalCalendarPrototype::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
{
    return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
}

TemporalCalendarPrototype::TemporalCalendarPrototype(VM& vm, Structure* structure)
    : Base(vm, structure)
{
}

void TemporalCalendarPrototype::finishCreation(VM& vm, JSGlobalObject*)
{
    Base::finishCreation(vm);
    ASSERT(inherits(info()));
    JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
}

// https://tc39.es/proposal-temporal/#sec-get-temporal.calendar.prototype.id
JSC_DEFINE_CUSTOM_GETTER(temporalCalendarPrototypeGetterId, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName))
{
    return JSValue::encode(JSValue::decode(thisValue).toString(globalObject));
}

// https://tc39.es/proposal-temporal/#sup-temporal.calendar.prototype.fields
JSC_DEFINE_HOST_FUNCTION(temporalCalendarPrototypeFuncFields, (JSGlobalObject* globalObject, CallFrame* callFrame))
{
    VM& vm = globalObject->vm();
    auto scope = DECLARE_THROW_SCOPE(vm);

    auto* calendar = jsDynamicCast<TemporalCalendar*>(callFrame->thisValue());
    if (!calendar)
        return throwVMTypeError(globalObject, scope, "Temporal.Calendar.prototype.fields called on value that's not a Calendar"_s);

    bool isISO8601 = calendar->isISO8601();
    bool shouldAddEraAndEraYear = false;
    MarkedArgumentBuffer fieldNames;
    forEachInIterable(globalObject, callFrame->argument(0), [isISO8601, &shouldAddEraAndEraYear, &fieldNames](VM& vm, JSGlobalObject* globalObject, JSValue value) {
        auto scope = DECLARE_THROW_SCOPE(vm);
        if (!value.isString()) {
            throwTypeError(globalObject, scope, "fields include non string value"_s);
            return;
        }
        if (!isISO8601 && !shouldAddEraAndEraYear) {
            auto string = jsCast<JSString*>(value)->value(globalObject);
            RETURN_IF_EXCEPTION(scope, void());
            if (string == "year"_s)
                shouldAddEraAndEraYear = true;
        }
        fieldNames.append(value);
    });
    RETURN_IF_EXCEPTION(scope, { });

    if (shouldAddEraAndEraYear) {
        fieldNames.append(jsNontrivialString(vm, vm.propertyNames->era.impl()));
        fieldNames.append(jsNontrivialString(vm, vm.propertyNames->eraYear.impl()));
    }

    RELEASE_AND_RETURN(scope, JSValue::encode(constructArray(globalObject, static_cast<ArrayAllocationProfile*>(nullptr), fieldNames)));
}

// https://tc39.es/proposal-temporal/#sec-temporal-defaultmergefields
static JSObject* defaultMergeFields(JSGlobalObject* globalObject, JSObject* fields, JSObject* additionalFields)
{
    VM& vm = globalObject->vm();
    auto scope = DECLARE_THROW_SCOPE(vm);

    auto* merged = constructEmptyObject(globalObject);

    {
        PropertyNameArray originalKeys(vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude);
        fields->methodTable()->getOwnPropertyNames(fields, globalObject, originalKeys, DontEnumPropertiesMode::Include);
        RETURN_IF_EXCEPTION(scope, { });

        for (const auto& nextKey : originalKeys) {
            if (nextKey != vm.propertyNames->month && nextKey != vm.propertyNames->monthCode) {
                JSValue propValue = fields->get(globalObject, nextKey);
                RETURN_IF_EXCEPTION(scope, { });
                if (!propValue.isUndefined()) {
                    PutPropertySlot slot(merged, true);
                    merged->putOwnDataProperty(vm, nextKey, propValue, slot);
                    RETURN_IF_EXCEPTION(scope, { });
                }
            }
        }
    }

    bool includesMonthOrMonthCode = false;
    {
        PropertyNameArray newKeys(vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude);
        additionalFields->methodTable()->getOwnPropertyNames(additionalFields, globalObject, newKeys, DontEnumPropertiesMode::Include);
        RETURN_IF_EXCEPTION(scope, { });

        for (const auto& nextKey : newKeys) {
            if (!includesMonthOrMonthCode) {
                if (nextKey == vm.propertyNames->month || nextKey == vm.propertyNames->monthCode)
                    includesMonthOrMonthCode = true;
            }

            JSValue propValue = additionalFields->get(globalObject, nextKey);
            RETURN_IF_EXCEPTION(scope, { });
            if (!propValue.isUndefined()) {
                PutPropertySlot slot(merged, true);
                merged->putOwnDataProperty(vm, nextKey, propValue, slot);
                RETURN_IF_EXCEPTION(scope, { });
            }
        }
    }

    if (!includesMonthOrMonthCode) {
        JSValue month = fields->get(globalObject, vm.propertyNames->month);
        RETURN_IF_EXCEPTION(scope, { });
        if (!month.isUndefined()) {
            PutPropertySlot slot(merged, true);
            merged->putOwnDataProperty(vm, vm.propertyNames->month, month, slot);
            RETURN_IF_EXCEPTION(scope, { });
        }

        JSValue monthCode = fields->get(globalObject, vm.propertyNames->monthCode);
        RETURN_IF_EXCEPTION(scope, { });
        if (!monthCode.isUndefined()) {
            PutPropertySlot slot(merged, true);
            merged->putOwnDataProperty(vm, vm.propertyNames->monthCode, monthCode, slot);
            RETURN_IF_EXCEPTION(scope, { });
        }
    }

    return merged;
}

// https://tc39.es/proposal-temporal/#sup-temporal.calendar.prototype.mergefields
JSC_DEFINE_HOST_FUNCTION(temporalCalendarPrototypeFuncMergeFields, (JSGlobalObject* globalObject, CallFrame* callFrame))
{
    VM& vm = globalObject->vm();
    auto scope = DECLARE_THROW_SCOPE(vm);

    auto* calendar = jsDynamicCast<TemporalCalendar*>(callFrame->thisValue());
    if (!calendar)
        return throwVMTypeError(globalObject, scope, "Temporal.Calendar.prototype.mergeFields called on value that's not a Calendar"_s);

    auto* fields = callFrame->argument(0).toObject(globalObject);
    RETURN_IF_EXCEPTION(scope, { });

    auto* additionalFields = callFrame->argument(1).toObject(globalObject);
    RETURN_IF_EXCEPTION(scope, { });

    if (calendar->isISO8601())
        RELEASE_AND_RETURN(scope, JSValue::encode(defaultMergeFields(globalObject, fields, additionalFields)));

    auto copyObject = [](JSGlobalObject* globalObject, JSObject* object) -> JSObject* {
        VM& vm = globalObject->vm();
        auto scope = DECLARE_THROW_SCOPE(vm);

        auto* copied = constructEmptyObject(globalObject);

        PropertyNameArray keys(vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude);
        object->methodTable()->getOwnPropertyNames(object, globalObject, keys, DontEnumPropertiesMode::Include);
        RETURN_IF_EXCEPTION(scope, { });

        for (const auto& key : keys) {
            JSValue propValue = object->get(globalObject, key);
            RETURN_IF_EXCEPTION(scope, { });
            if (!propValue.isUndefined()) {
                PutPropertySlot slot(copied, true);
                copied->putOwnDataProperty(vm, key, propValue, slot);
                RETURN_IF_EXCEPTION(scope, { });
            }
        }

        return copied;
    };

    auto* fieldsCopied = copyObject(globalObject, fields);
    RETURN_IF_EXCEPTION(scope, { });

    auto* additionalFieldsCopied = copyObject(globalObject, additionalFields);
    RETURN_IF_EXCEPTION(scope, { });

    JSValue newMonth = jsUndefined();
    JSValue newMonthCode = jsUndefined();
    JSValue newYear = jsUndefined();
    JSValue newEra = jsUndefined();
    JSValue newEraYear = jsUndefined();
    {
        PropertyNameArray keys(vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude);
        additionalFieldsCopied->methodTable()->getOwnPropertyNames(additionalFieldsCopied, globalObject, keys, DontEnumPropertiesMode::Include);
        RETURN_IF_EXCEPTION(scope, { });

        for (const auto& key : keys) {
            JSValue propValue = additionalFieldsCopied->get(globalObject, key);
            RETURN_IF_EXCEPTION(scope, { });
            if (!propValue.isUndefined()) {
                if (key == vm.propertyNames->month)
                    newMonth = propValue;
                else if (key == vm.propertyNames->monthCode)
                    newMonthCode = propValue;
                else if (key == vm.propertyNames->year)
                    newYear = propValue;
                else if (key == vm.propertyNames->era)
                    newEra = propValue;
                else if (key == vm.propertyNames->eraYear)
                    newEraYear = propValue;
                else {
                    PutPropertySlot slot(fieldsCopied, true);
                    fieldsCopied->putOwnDataProperty(vm, key, propValue, slot);
                    RETURN_IF_EXCEPTION(scope, { });
                }
            }
        }
    }

    if (!newMonth.isUndefined() || !newMonthCode.isUndefined()) {
        {
            PutPropertySlot slot(fieldsCopied, true);
            fieldsCopied->putOwnDataProperty(vm, vm.propertyNames->month, newMonth, slot);
            RETURN_IF_EXCEPTION(scope, { });
        }
        {
            PutPropertySlot slot(fieldsCopied, true);
            fieldsCopied->putOwnDataProperty(vm, vm.propertyNames->monthCode, newMonthCode, slot);
            RETURN_IF_EXCEPTION(scope, { });
        }
    }

    if (!newYear.isUndefined() || !newEra.isUndefined() || !newEraYear.isUndefined()) {
        {
            PutPropertySlot slot(fieldsCopied, true);
            fieldsCopied->putOwnDataProperty(vm, vm.propertyNames->year, newYear, slot);
            RETURN_IF_EXCEPTION(scope, { });
        }
        {
            PutPropertySlot slot(fieldsCopied, true);
            fieldsCopied->putOwnDataProperty(vm, vm.propertyNames->era, newEra, slot);
            RETURN_IF_EXCEPTION(scope, { });
        }
        {
            PutPropertySlot slot(fieldsCopied, true);
            fieldsCopied->putOwnDataProperty(vm, vm.propertyNames->eraYear, newEraYear, slot);
            RETURN_IF_EXCEPTION(scope, { });
        }
    }

    return JSValue::encode(fieldsCopied);
}

// https://tc39.es/proposal-temporal/#sec-temporal.calendar.prototype.tostring
JSC_DEFINE_HOST_FUNCTION(temporalCalendarPrototypeFuncToString, (JSGlobalObject* globalObject, CallFrame* callFrame))
{
    VM& vm = globalObject->vm();
    auto scope = DECLARE_THROW_SCOPE(vm);

    auto* calendar = jsDynamicCast<TemporalCalendar*>(callFrame->thisValue());
    if (!calendar)
        return throwVMTypeError(globalObject, scope, "Temporal.Calendar.prototype.toString called on value that's not a Calendar"_s);

    return JSValue::encode(jsString(vm, intlAvailableCalendars()[calendar->identifier()]));
}

// https://tc39.es/proposal-temporal/#sec-temporal.calendar.prototype.tojson
JSC_DEFINE_HOST_FUNCTION(temporalCalendarPrototypeFuncToJSON, (JSGlobalObject* globalObject, CallFrame* callFrame))
{
    return JSValue::encode(callFrame->thisValue().toString(globalObject));
}

} // namespace JSC
