package com.robonobo.core.api.model;
import java.awt.image.BufferedImage;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.robonobo.common.util.TimeUtil;
import com.robonobo.core.api.proto.CoreApi.StreamAttributeMsg;
import com.robonobo.core.api.proto.CoreApi.StreamMsg;
public class Stream implements Comparable<Stream> {
protected static Pattern trackNumPat = Pattern.compile("^(\\d+)");
private static final String ARTIST = "artist";
private static final String ALBUM = "album";
private static final String TRACK = "track";
protected String mimeType;
public String streamId;
public String title;
protected String description = "";
protected BufferedImage thumbnail;
protected Set<StreamAttribute> attributes = new HashSet<StreamAttribute>();
protected Map<String, StreamAttribute> attrMap = new HashMap<String, StreamAttribute>();
protected long size;
/** Millisecs */
protected long duration;
protected Date updated;
/**
* These are kept as attributes but we keep a field too for fast retrieval, Streams are used often for sorting and
* such
*/
public String artist;
public String album;
/**
* Also kept as an attribute - this will be -1 if the attribute is not present
*/
public int track = -1;
public Stream() {
}
public Stream(StreamMsg msg) {
setStreamId(msg.getId());
setMimeType(msg.getMimeType());
setTitle(msg.getTitle());
setSize(msg.getSize());
setDuration(msg.getDuration());
for (StreamAttributeMsg saMsg : msg.getAttributeList()) {
setAttrValue(saMsg.getName(), saMsg.getValue());
}
}
public StreamMsg toMsg() {
StreamMsg.Builder b = StreamMsg.newBuilder();
b.setId(streamId);
b.setMimeType(mimeType);
b.setTitle(title);
b.setSize(size);
b.setDuration(duration);
for (StreamAttribute sa : attributes) {
b.addAttribute(sa.toMsg());
}
return b.build();
}
public void copyFrom(Stream s) {
if (s.getTitle() != null)
setTitle(s.getTitle());
if (s.getDescription() != null)
setDescription(s.getDescription());
if (s.getStreamId() != null)
setStreamId(s.getStreamId());
if (s.getMimeType() != null)
setMimeType(s.getMimeType());
setDuration(s.getDuration());
if (s.getSize() > 0)
setSize(s.getSize());
if (s.getUpdated() != null)
setUpdated(s.getUpdated());
// Don't just copy the attributes set as setAttrValue() sets the
// Attribute->Stream link
for (StreamAttribute sa : s.getAttributes()) {
setAttrValue(sa.getName(), sa.getValue());
}
}
/**
* If any of our properties are null, fill them from the supplied stream
*
* @return if any properties were changed
*/
public boolean fillBlanks(Stream s) {
boolean changed = false;
if (title == null) {
setTitle(s.getTitle());
changed = true;
}
if (description == null) {
setDescription(s.getDescription());
changed = true;
}
if (streamId == null) {
setStreamId(s.getStreamId());
changed = true;
}
if (mimeType == null) {
setMimeType(s.getMimeType());
changed = true;
}
if (duration <= 0) {
duration = s.duration;
changed = true;
}
if (size <= 0) {
size = s.size;
changed = true;
}
if (s.getUpdated() != null) {
setUpdated(s.getUpdated());
changed = true;
}
// Don't just copy the attributes set as setAttrValue() sets the
// Attribute->Stream link
for (StreamAttribute sa : s.getAttributes()) {
if (getAttrValue(sa.getName()) != null) {
setAttrValue(sa.getName(), sa.getValue());
changed = true;
}
}
if (changed)
updated = TimeUtil.now();
return changed;
}
public boolean equals(Object obj) {
return (obj instanceof Stream && ((Stream) obj).getStreamId().equals(getStreamId()));
}
/**
* Millisecs
*/
public long getDuration() {
return duration;
}
/**
* Bytes
*/
public long getSize() {
return size;
}
public Date getUpdated() {
return updated;
}
public int hashCode() {
return getClass().getName().hashCode() ^ streamId.hashCode();
}
/**
* Millisecs
*/
public void setDuration(long length) {
this.duration = length;
}
/**
* Bytes
*/
public void setSize(long size) {
this.size = size;
}
public void setUpdated(Date updated) {
this.updated = updated;
}
public String toString() {
StringBuffer sb = new StringBuffer("[Stream:id=").append(getStreamId());
sb.append(",title=").append(getTitle()).append("]");
return sb.toString();
}
public String getMimeType() {
return mimeType;
}
public void setMimeType(String mimeType) {
this.mimeType = truncate(mimeType, 128);
}
public String getStreamId() {
return streamId;
}
public void setStreamId(String streamId) {
this.streamId = streamId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = truncate(title, 256);
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = truncate(description, 512);
}
public BufferedImage getThumbnail() {
return thumbnail;
}
public void setThumbnail(BufferedImage thumbnail) {
this.thumbnail = thumbnail;
}
public Set<StreamAttribute> getAttributes() {
return attributes;
}
public void setAttributes(Set<StreamAttribute> attributes) {
this.attributes = attributes;
for (StreamAttribute a : attributes) {
String key = a.getName();
String value = a.getValue();
attrMap.put(key, a);
updateTransAttr(key, value);
}
}
public void setAttrValue(String key, String value) {
if (attrMap.containsKey(key))
attrMap.get(key).setValue(value);
else {
StreamAttribute a = new StreamAttribute(this, key, value);
a.setStream(this);
attributes.add(a);
attrMap.put(key, a);
}
updateTransAttr(key, value);
}
protected void updateTransAttr(String key, String value) {
if (key.equals(ARTIST))
artist = value;
else if (key.equals(ALBUM))
album = value;
else if(key.equals(TRACK))
track = trackFromStr(value);
}
public String getAttrValue(String key) {
StreamAttribute sa = attrMap.get(key);
if (sa == null)
return null;
return sa.getValue();
}
public int compareTo(Stream o) {
int titleCmp = title.compareTo(o.title);
if (titleCmp != 0)
return titleCmp;
return streamId.compareTo(o.streamId);
}
public String getArtist() {
return artist;
}
public String getAlbum() {
return album;
}
public int getTrack() {
return track;
}
private static int trackFromStr(String trackStr) {
Matcher m = trackNumPat.matcher(trackStr);
return m.find() ? Integer.parseInt(m.group()) : -1;
}
private String truncate(String str, int maxLen) {
if (str.length() <= maxLen)
return str;
return str.substring(0, maxLen);
}
}