package com.oracle.truffle.js.runtime.builtins.intl;
import java.util.Locale;
import com.ibm.icu.text.DisplayContext;
import com.ibm.icu.text.LocaleDisplayNames;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.object.Shape;
import com.oracle.truffle.js.builtins.intl.DisplayNamesFunctionBuiltins;
import com.oracle.truffle.js.builtins.intl.DisplayNamesPrototypeBuiltins;
import com.oracle.truffle.js.runtime.Errors;
import com.oracle.truffle.js.runtime.JSContext;
import com.oracle.truffle.js.runtime.JSRealm;
import com.oracle.truffle.js.runtime.builtins.JSConstructor;
import com.oracle.truffle.js.runtime.builtins.JSConstructorFactory;
import com.oracle.truffle.js.runtime.builtins.JSNonProxy;
import com.oracle.truffle.js.runtime.builtins.JSObjectFactory;
import com.oracle.truffle.js.runtime.builtins.JSOrdinary;
import com.oracle.truffle.js.runtime.builtins.PrototypeSupplier;
import com.oracle.truffle.js.runtime.objects.JSAttributes;
import com.oracle.truffle.js.runtime.objects.JSObjectUtil;
import com.oracle.truffle.js.runtime.objects.Undefined;
import com.oracle.truffle.js.runtime.util.IntlUtil;
public final class JSDisplayNames extends JSNonProxy implements JSConstructorFactory.Default.WithFunctions, PrototypeSupplier {
public static final String CLASS_NAME = "DisplayNames";
public static final String PROTOTYPE_NAME = "DisplayNames.prototype";
public static final JSDisplayNames INSTANCE = new JSDisplayNames();
private JSDisplayNames() {
}
public static boolean isJSDisplayNames(Object obj) {
return obj instanceof JSDisplayNamesObject;
}
@Override
public String getClassName() {
return CLASS_NAME;
}
@Override
public String getClassName(DynamicObject object) {
return getClassName();
}
@Override
public DynamicObject createPrototype(JSRealm realm, DynamicObject ctor) {
JSContext ctx = realm.getContext();
DynamicObject displayNamesPrototype = JSObjectUtil.createOrdinaryPrototypeObject(realm);
JSObjectUtil.putConstructorProperty(ctx, displayNamesPrototype, ctor);
JSObjectUtil.putFunctionsFromContainer(realm, displayNamesPrototype, DisplayNamesPrototypeBuiltins.BUILTINS);
JSObjectUtil.putToStringTag(displayNamesPrototype, "Intl.DisplayNames");
return displayNamesPrototype;
}
@Override
public Shape makeInitialShape(JSContext ctx, DynamicObject prototype) {
return JSObjectUtil.getProtoChildShape(prototype, INSTANCE, ctx);
}
public static JSConstructor createConstructor(JSRealm realm) {
return INSTANCE.createConstructorAndPrototype(realm, DisplayNamesFunctionBuiltins.BUILTINS);
}
public static DynamicObject create(JSContext context) {
InternalState state = new InternalState();
JSRealm realm = context.getRealm();
JSObjectFactory factory = context.getDisplayNamesFactory();
JSDisplayNamesObject obj = new JSDisplayNamesObject(factory.getShape(realm), state);
factory.initProto(obj, realm);
assert isJSDisplayNames(obj);
return obj;
}
public static class InternalState {
String locale;
String style;
String type;
String fallback;
LocaleDisplayNames displayNames;
DynamicObject toResolvedOptionsObject(JSContext context) {
DynamicObject result = JSOrdinary.create(context);
JSObjectUtil.defineDataProperty(result, IntlUtil.LOCALE, locale, JSAttributes.getDefault());
JSObjectUtil.defineDataProperty(result, IntlUtil.STYLE, style, JSAttributes.getDefault());
JSObjectUtil.defineDataProperty(result, IntlUtil.TYPE, type, JSAttributes.getDefault());
JSObjectUtil.defineDataProperty(result, IntlUtil.FALLBACK, fallback, JSAttributes.getDefault());
return result;
}
}
@TruffleBoundary
public static void setupInternalState(JSContext ctx, InternalState state, String[] locales, String optStyle, String optType, String optFallback) {
Locale selectedLocale = IntlUtil.selectedLocale(ctx, locales);
Locale strippedLocale = selectedLocale.stripExtensions();
if (strippedLocale.toLanguageTag().equals(IntlUtil.UND)) {
selectedLocale = ctx.getLocale();
strippedLocale = selectedLocale.stripExtensions();
}
state.locale = strippedLocale.toLanguageTag();
state.style = optStyle;
state.type = optType;
state.fallback = optFallback;
DisplayContext fallbackCtx = fallbackDisplayContext(optFallback);
DisplayContext styleCtx = styleDisplayContext(optStyle);
state.displayNames = LocaleDisplayNames.getInstance(strippedLocale, styleCtx, fallbackCtx);
}
private static DisplayContext fallbackDisplayContext(String optFallback) {
return IntlUtil.NONE.equals(optFallback) ? DisplayContext.NO_SUBSTITUTE : DisplayContext.SUBSTITUTE;
}
private static DisplayContext styleDisplayContext(String optStyle) {
return IntlUtil.LONG.equals(optStyle) ? DisplayContext.LENGTH_FULL : DisplayContext.LENGTH_SHORT;
}
@TruffleBoundary
public static DynamicObject resolvedOptions(JSContext context, DynamicObject displayNamesObject) {
InternalState state = getInternalState(displayNamesObject);
return state.toResolvedOptionsObject(context);
}
@TruffleBoundary
public static Object of(DynamicObject displayNamesObject, String code) {
InternalState state = getInternalState(displayNamesObject);
String type = state.type;
LocaleDisplayNames displayNames = state.displayNames;
String result;
switch (type) {
case IntlUtil.LANGUAGE:
IntlUtil.ensureIsStructurallyValidLanguageTag(code);
result = displayNames.localeDisplayName(code);
break;
case IntlUtil.REGION:
IntlUtil.ensureIsStructurallyValidRegionSubtag(code);
result = displayNames.regionDisplayName(code);
break;
case IntlUtil.SCRIPT:
IntlUtil.ensureIsStructurallyValidScriptSubtag(code);
result = displayNames.scriptDisplayName(code);
break;
case IntlUtil.CURRENCY:
IntlUtil.ensureIsWellFormedCurrencyCode(code);
result = displayNames.keyValueDisplayName(IntlUtil.CURRENCY, code);
break;
default:
throw Errors.shouldNotReachHere(type);
}
return (result == null) ? Undefined.instance : result;
}
public static InternalState getInternalState(DynamicObject displayNamesObject) {
assert isJSDisplayNames(displayNamesObject);
return ((JSDisplayNamesObject) displayNamesObject).getInternalState();
}
@Override
public DynamicObject getIntrinsicDefaultProto(JSRealm realm) {
return realm.getDisplayNamesPrototype();
}
}