/**
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.waveprotocol.box.server.rpc.render;
import org.waveprotocol.box.server.rpc.render.account.ProfileManager;
import org.waveprotocol.box.server.rpc.render.common.safehtml.SafeHtml;
import org.waveprotocol.box.server.rpc.render.renderer.ShallowBlipRenderer;
import org.waveprotocol.box.server.rpc.render.view.IntrinsicBlipMetaView;
import org.waveprotocol.wave.model.conversation.ConversationBlip;
import org.waveprotocol.wave.model.document.Document;
import org.waveprotocol.wave.model.supplement.ReadableSupplementedWave;
import org.waveprotocol.wave.model.wave.ParticipantId;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Set;
/**
* Defines the shallow blip rendering for the server sside.
*
*@author yurize@apache.org (Yuri Zelikov)
*/
public final class HtmlShallowBlipRenderer implements ShallowBlipRenderer {
private static final int MAX_CONTRIBUTORS = 3;
private final static long SEC_MS = 1000;
private final static long MIN_MS = 60 * SEC_MS;
private final static long HOUR_MS = 60 * MIN_MS;
/** Provides names and avatars of participants. */
private final ProfileManager manager;
/** Provides read state of blips. */
private final ReadableSupplementedWave supplement;
/**
* Defines the rendering function for the contents of a blip.
*/
public interface DocumentRenderer {
SafeHtml render(String blipId, Document doc);
}
public HtmlShallowBlipRenderer(
ProfileManager manager, ReadableSupplementedWave supplement) {
this.manager = manager;
this.supplement = supplement;
}
@Override
public void render(ConversationBlip blip, IntrinsicBlipMetaView view) {
// blip.hackGetRaw().get
renderContributors(blip, view);
renderTime(blip, view);
renderRead(blip, view);
}
@Override
public void renderContributors(ConversationBlip blip, IntrinsicBlipMetaView meta) {
Set<ParticipantId> contributors = blip.getContributorIds();
if (!contributors.isEmpty()) {
meta.setAvatar(avatarOf(contributors.iterator().next()));
meta.setMetaline(buildNames(contributors));
meta.setAuthor(blip.getAuthorId().getAddress());
} else {
// Blips are never meant to have no contributors. The wave state is broken.
meta.setAvatar("");
meta.setMetaline("anon");
}
}
@Override
public void renderTime(ConversationBlip blip, IntrinsicBlipMetaView meta) {
meta.setTime(formatPastDate(new Date(blip.getLastModifiedTime()), new Date()));
}
/**
* Package-private version, takes a fixed "now" time - used for testing
*/
public static String formatPastDate(Date date, Date now) {
// NOTE(zdwang): For now skip it for junit code; also see formatDateTime()
if (isRecent(date, now) || onSameDay(date, now)) {
SimpleDateFormat dateFmt = new SimpleDateFormat("hh:mm");
return dateFmt.format(date); // AM/PM -> am/pm
} else {
SimpleDateFormat monthFmt = new SimpleDateFormat("dd MMM yyyy");
return monthFmt.format(date);
}
}
/**
* @return true if a duration is less than six hours.
*/
private static boolean isRecent(Date date, Date now) {
return (now.getTime() - date.getTime()) < 6 * HOUR_MS;
}
/**
* @return true if a date occurs on the same day as today.
*/
private static boolean onSameDay(Date date, Date now) {
return (date.getDate() == now.getDate())
&& (date.getMonth() == now.getMonth())
&& (date.getYear() == now.getYear());
}
/**
* @return true if a date occurs in the same year as this year.
*/
private boolean isSameYear(Date date, Date now) {
return date.getYear() == now.getYear();
}
@Override
public void renderRead(ConversationBlip blip, IntrinsicBlipMetaView blipUi) {
blipUi.setRead(!supplement.isUnread(blip));
}
/**
* @return the rich text for the contributors in a blip.
*/
private String buildNames(Set<ParticipantId> contributors) {
StringBuilder names = new StringBuilder();
int i = 0;
for (ParticipantId contributor : contributors) {
if (i >= MAX_CONTRIBUTORS) {
break;
} else if (manager.shouldIgnore(contributor)) {
continue;
}
if (i > 0) {
names.append(", ");
}
names.append(nameOf(contributor));
i++;
}
return names.toString();
}
private String nameOf(ParticipantId contributor) {
return manager.getProfile(contributor).getFirstName();
}
private String avatarOf(ParticipantId contributor) {
return manager.getProfile(contributor).getImageUrl();
}
}