package org.liveSense.server.i18n;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import com.google.gwt.i18n.client.LocalizableResource.Key;
import com.google.gwt.i18n.client.Messages.DefaultMessage;
import com.google.gwt.i18n.client.Messages.PluralCount;
import com.google.gwt.i18n.client.Messages.PluralText;
import com.google.gwt.i18n.client.PluralRule;
public class GenericMessages extends GenericX {
public GenericMessages(Class<?> _itf, String lang, String country, String variant, ClassLoader classLoader, ResourceBundle bundle) throws IOException, InvalidParameterException {
super(_itf, lang, country, variant, classLoader, bundle);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (!String.class.equals(method.getReturnType())) {
return "Invalid return type of the method " + method.toString();
}
//first, try to use the annotation if there is one.
Key k = method.getAnnotation(Key.class);
String result = null;
if (k != null) {
result = buildMessage(k.value(), method, args);
}
if (result == null) {
result = buildMessage(method.getName(), method, args);
}
return result;
}
private String buildMessage(String propertyName, Method method, Object[] args) throws Throwable {
PluralText pluralTextAnnotation = method.getAnnotation(PluralText.class);
Map<Integer, String> pluralParamIndex2pattern = new HashMap<Integer, String>();
String pluralKey ="";
Map<String,String> pluralKey2defaultValue = new HashMap<String,String>();
if (pluralTextAnnotation != null) {
String[] pairs = pluralTextAnnotation.value();
for(int i=0; (i+1)<pairs.length; i+=2) {
pluralKey2defaultValue.put(pairs[i], pairs[i+1]);
}
}
Annotation[][] paramsAnnotations = method.getParameterAnnotations();
Class<?>[] paramTypes = method.getParameterTypes();
for (int i = 0; i < paramTypes.length; i++) {
Class<?> paramType = paramTypes[i];
PluralCount pc = getAnnotation(paramsAnnotations[i], PluralCount.class);
if (pc == null) {
continue;
} else if (pc.value() != PluralRule.class) {
//user plural rule is not supported
} else {
// manage plural text
//TODO manage primitive types
int n = -1;
if (isA(paramType, Number.class)
|| isA(paramType, byte.class)
|| isA(paramType, short.class)
|| isA(paramType, int.class)
|| isA(paramType, long.class)) {
n = ((Number) args[i]).intValue();
}
if (n == 0) {
pluralKey += "[none]";
pluralParamIndex2pattern.put(i, null);
} else if (n == 1) {
pluralKey += "[one]";
pluralParamIndex2pattern.put(i, null);
} else if (n == 2) {
pluralKey += "[two]";
pluralParamIndex2pattern.put(i, null);
} else if (3 <= n && n <= 10) {
pluralKey += "[few]";
} else if (11 <= n && n <= 99) {
pluralKey += "[many]";
}
pluralParamIndex2pattern.put(i, "\\{" + i + ",number\\}");
}
}
String template = properties.getProperty(propertyName + pluralKey);
if (resourceBundle != null) template = resourceBundle.getString(propertyName + pluralKey);
if (template == null) {
DefaultMessage dm = method.getAnnotation(DefaultMessage.class);
if (dm == null) {} else {
template = dm.value();
}
if (template == null) {
return null;
}
}
assert template != null;
if (args != null) {
for (int i = 0; i < args.length; i++) {
String value = args[i] == null ? "null" : args[i].toString();
String replacedPattern = null;
if (pluralParamIndex2pattern.containsKey(i)) {
replacedPattern = pluralParamIndex2pattern.get(i);
} else {
replacedPattern = "\\{" + i + "\\}";
}
if (replacedPattern != null) {
template = template.replaceAll(replacedPattern, value == null ? "" : value);
}
}
}
return template;
}
@SuppressWarnings("unchecked")
<T extends Annotation> T getAnnotation(Annotation[] as, Class<T> annotation) {
for(Annotation a : as) {
if (isA(a.getClass(), annotation)) {
return (T)a;
}
}
return null;
}
@SuppressWarnings("unchecked")
<T extends Annotation> List<T> getAnnotations(Annotation[] as, Class<T> a) {
List<T> foundAnnotations = new ArrayList<T>();
for(Annotation _a : as) {
if (_a.getClass().equals(a.getClass())) {
foundAnnotations.add((T)_a);
}
}
return foundAnnotations;
}
}