package tc.oc.api.model;
import java.util.Optional;
import javax.inject.Inject;
import javax.inject.Provider;
import com.google.common.reflect.TypeParameter;
import com.google.common.reflect.TypeToken;
import com.google.inject.TypeLiteral;
import tc.oc.api.docs.virtual.Model;
import tc.oc.api.docs.virtual.PartialModel;
import tc.oc.api.message.types.FindMultiResponse;
import tc.oc.api.message.types.ModelUpdate;
import tc.oc.api.message.types.PartialModelUpdate;
import tc.oc.commons.core.formatting.StringUtils;
import tc.oc.commons.core.reflect.Types;
import static tc.oc.commons.core.reflect.Types.assertFullySpecified;
public class ModelMeta<M extends Model, P extends PartialModel> {
private final TypeToken<P> partialType;
private final TypeToken<M> completeType;
private final TypeToken<PartialModelUpdate<P>> partialUpdateType;
private final TypeToken<ModelUpdate<M>> completeUpdateType;
private final TypeToken<FindMultiResponse<M>> multiResponseType;
private final Provider<Optional<ModelStore<M>>> store;
private final String name;
private final String singularName;
private final String pluralName;
@Inject ModelMeta(TypeLiteral<M> completeType, TypeLiteral<P> partialType, Provider<Optional<ModelStore<M>>> store) {
this.partialType = Types.toToken(partialType);
this.completeType = Types.toToken(completeType);
partialUpdateType = assertFullySpecified(new TypeToken<PartialModelUpdate<P>>(){}.where(new TypeParameter<P>(){}, this.partialType));
completeUpdateType = assertFullySpecified(new TypeToken<ModelUpdate<M>>(){}.where(new TypeParameter<M>(){}, this.completeType));
multiResponseType = assertFullySpecified(new TypeToken<FindMultiResponse<M>>(){}.where(new TypeParameter<M>(){}, this.completeType));
this.store = store;
final ModelName annot = completeType.getRawType().getAnnotation(ModelName.class);
if(annot != null) {
name = annot.value();
singularName = annot.singular().length() > 0 ? annot.singular() : name.toLowerCase();
pluralName = annot.plural().length() > 0 ? annot.plural() : StringUtils.pluralize(singularName);
} else {
name = completeType.getRawType().getSimpleName();
singularName = name.toLowerCase();
pluralName = StringUtils.pluralize(singularName);
}
}
public TypeToken<P> partialType() {
return partialType;
}
public TypeToken<M> completeType() {
return completeType;
}
public Class<P> partialTypeRaw() {
return (Class<P>) partialType().getRawType();
}
public Class<M> completeTypeRaw() {
return (Class<M>) completeType().getRawType();
}
public TypeToken<PartialModelUpdate<P>> partialUpdateType() {
return partialUpdateType;
}
public TypeToken<ModelUpdate<M>> completeUpdateType() {
return completeUpdateType;
}
public TypeToken<FindMultiResponse<M>> multiResponseType() {
return multiResponseType;
}
public Optional<ModelStore<M>> store() {
return store.get();
}
public String name() {
return name;
}
public String singularName() {
return singularName;
}
public String pluralName() {
return pluralName;
}
public interface Builder<M extends Model> {
Builder<M> partial(Class<? extends PartialModel> type);
Builder<M> store(Class<? extends ModelStore<M>> type);
}
}