/*
* Copyright 2014 Artem Chikin
* Copyright 2014 Artem Herasymchuk
* Copyright 2014 Tom Krywitsky
* Copyright 2014 Henry Pabst
* Copyright 2014 Bradley Simons
*
* 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 ca.ualberta.cmput301w14t08.geochan.models;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import android.graphics.Bitmap;
import android.media.ThumbnailUtils;
import android.os.Parcel;
import android.os.Parcelable;
import ca.ualberta.cmput301w14t08.geochan.helpers.HashHelper;
import ca.ualberta.cmput301w14t08.geochan.managers.PreferencesManager;
/**
* A comment within a thread of comments. Contains the text of the comment,
* possibly an image, and meta-data relating to the Comment.
*
* @author Henry Pabst, Artem Chikin
*/
public class Comment implements Parcelable {
private String textPost;
private Date commentDate;
private Bitmap image;
private Bitmap imageThumb;
private GeoLocation location;
private String user;
private String hash;
private int depth;
private Comment parent;
private ArrayList<Comment> children;
private ArrayList<String> commentIds;
private PreferencesManager manager;
private long id;
/**
* Initializes a Comment object with a post, parent comment, image and
* GeoLocation.
*/
public Comment(String textPost, Bitmap image, GeoLocation location,
Comment parent) {
super();
this.manager = PreferencesManager.getInstance();
this.setTextPost(textPost);
this.setCommentDate(new Date());
this.setImage(image);
this.setImageThumb(ThumbnailUtils.extractThumbnail(image, 150, 150));
this.setLocation(location);
this.setUser(manager.getUser());
this.setHash(HashHelper.getHash(manager.getUser()));
if (parent == null) {
this.depth = -1;
} else {
this.depth = parent.depth + 1;
}
this.setParent(parent);
this.setChildren(new ArrayList<Comment>());
this.id = HashHelper.getCommentIdHash();
this.commentIds = new ArrayList<String>();
}
/**
* Initializes a Comment object with a post, parent comment and GeoLocation.
*/
public Comment(String textPost, GeoLocation location, Comment parent) {
super();
this.manager = PreferencesManager.getInstance();
this.setTextPost(textPost);
this.setCommentDate(new Date());
this.setImage(null);
this.setImageThumb(null);
this.setLocation(location);
this.setUser(manager.getUser());
this.setHash(HashHelper.getHash(manager.getUser()));
if (parent == null) {
this.depth = -1;
} else {
this.depth = parent.depth + 1;
}
this.setParent(parent);
this.setChildren(new ArrayList<Comment>());
this.id = HashHelper.getCommentIdHash();
this.commentIds = new ArrayList<String>();
}
/**
* Initializes a Comment object with no data.
*/
public Comment() {
super();
this.manager = PreferencesManager.getInstance();
this.textPost = "No comment.";
this.commentDate = new Date();
this.image = null;
this.location = new GeoLocation(0, 0);
this.parent = null;
this.children = new ArrayList<Comment>();
this.setUser(new String());
this.setHash(new String());
this.depth = -1;
this.setParent(null);
this.setChildren(new ArrayList<Comment>());
this.id = -1;
this.commentIds = new ArrayList<String>();
}
/**
* Simple check that returns whether this Comment has an image associated
* with it.
*
* @return true if the Comment has an image, false if not
*/
public boolean hasImage() {
return !(imageThumb == null);
}
/**
* Adds a child Comment to this Comment.
*
* @param comment
* the child Comment to add
*/
public void addChild(Comment comment) {
comment.setParent(this);
children.add(comment);
}
/**
* Searches a parent Comment's children recursively for a Comment by its
* ElasticSearch id.
*
* @param parent
* the parent Comment
* @param id
* the id
* @return the Comment if found, or null if not found
*/
public Comment findCommentById(Comment parent, String id) {
Comment c = null;
if (parent.getId().equals(id)) {
c = parent;
}
for (Comment child : parent.getChildren()) {
Comment c2 = findCommentById(child, id);
if (c2 != null) {
c = c2;
}
}
return c;
}
/**
* Determines the distance between a comment and a GeoLocation in terms of
* latitude and longitude coordinates.
*
* @param geo
* The GeoLocation to be compared with.
* @return The distance between the Comment and the passed GeoLocation in
* terms of coordinates.
*/
public double getDistanceFrom(GeoLocation geo) {
GeoLocation thisGeo = this.getLocation();
return thisGeo.distance(geo);
}
/**
* Determines the amount of time between when the Comment was posted and the
* passed date in terms of hours.
*
* @param date
* The Date to be compared with.
* @return The number of hours between when the Comment was posted and the
* passed Date.
*/
public double getTimeFrom(Date date) {
Calendar cal1 = Calendar.getInstance();
Calendar cal2 = Calendar.getInstance();
cal1.setTime(this.getCommentDate());
cal2.setTime(date);
long t1 = cal1.getTimeInMillis();
long t2 = cal2.getTimeInMillis();
if (TimeUnit.MILLISECONDS.toHours(Math.abs(t1 - t2)) < 1) {
return 0.5;
} else {
return TimeUnit.MILLISECONDS.toHours(Math.abs(t1 - t2));
}
}
/**
* Determines the "score" of the Comment in relation to its parent. Should
* never be called on the bodyComment of a ThreadComment, and will return 0
* if it does.
*
* @return The score of the Comment in relation to its parent.
*/
@Deprecated
public double getScoreFromParent() {
int distConst = 25;
int timeConst = 10;
int maxScore = 50000;
/*
* These can be changed depending on how we want to weight distance vs.
* time for comment scoring.
*/
if (this.parent == null) {
return 0;
}
double distScore = distConst
* (1 / Math.sqrt(this.getDistanceFrom(this.getParent()
.getLocation())));
double timeScore = timeConst
* (1 / Math.sqrt(this.getTimeFrom(this.getParent()
.getCommentDate())));
if ((distScore + timeScore) > maxScore) {
return maxScore;
} else {
return distScore + timeScore;
}
}
/**
* Determines the score of a comment in a thread relevant to the user's
* current location and time.
*
* @param geo
* The current GeoLocation of the user. In sorting, the
* Thread.sortLoc GeoLocation of the sorting thread is used and
* should be set in the fragment.
* @return The score of the comment in relation to the user's location and
* current time.
*/
public double getScoreFromUser(GeoLocation geo) {
int distConst = 25;
int timeConst = 10;
int maxScore = 10000;
if (geo == null) {
return 0;
}
double distScore = distConst
* (1 / Math.sqrt(this.getDistanceFrom(geo)));
double timeScore = timeConst
* (1 / Math.sqrt(this.getTimeFrom(new Date())));
if ((distScore + timeScore) > maxScore) {
return maxScore;
} else {
return distScore + timeScore;
}
}
/**
* Searches the ThreadList for the ThreadComment containing this Comment.
*
* @return the ThreadComment of the Comment if found, or null if not found
*/
public ThreadComment findThread() {
ThreadComment t = null;
for (ThreadComment thread : ThreadList.getThreads()) {
if (thread.getBodyComment().getId().equals(getId())) {
t = thread;
}
}
return t;
}
/**
* Converts the Comment's commentDate to an appropriately formatted string.
*
* @return The string of the Comment's commentDate.
*/
public String getCommentDateString() {
SimpleDateFormat formatDate = new SimpleDateFormat("MMM dd/yy",
Locale.getDefault());
SimpleDateFormat formatTime = new SimpleDateFormat("hh:mm aa",
Locale.getDefault());
return "On " + formatDate.format(commentDate) + " at "
+ formatTime.format(commentDate);
}
/**
* Describes any special objects contained in the Parcelable representation.
* Not used in our implementation.
*/
@Override
public int describeContents() {
return 0;
}
/**
* Writes a Comment object to a Parcel.
*
* @param dest
* the Parcel
* @param flags
* contextual flags
*/
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeValue(textPost);
dest.writeValue(commentDate);
dest.writeValue(image);
dest.writeValue(imageThumb);
dest.writeValue(location.getLatitude());
dest.writeValue(location.getLongitude());
dest.writeValue(user);
dest.writeValue(id);
dest.writeParcelable(parent, flags);
}
/**
* Constructs a Comment object from a Parcel.
*
* @param in
* the parcel
*/
public Comment(Parcel in) {
super();
this.setTextPost((String) in.readValue(getClass().getClassLoader()));
this.setCommentDate((Date) in.readValue(getClass().getClassLoader()));
this.setImage((Bitmap) in.readValue(getClass().getClassLoader()));
this.setImageThumb((Bitmap) in.readValue(getClass().getClassLoader()));
this.setLocation(new GeoLocation(in.readDouble(), in.readDouble()));
this.setUser((String) in.readValue(getClass().getClassLoader()));
this.setId(Long.parseLong((String) in.readValue(getClass()
.getClassLoader())));
this.setParent((Comment) in.readParcelable(getClass().getClassLoader()));
}
/**
* Creates Comments from Parcels.
*/
public static final Parcelable.Creator<Comment> CREATOR = new Parcelable.Creator<Comment>() {
public Comment createFromParcel(Parcel in) {
return new Comment(in);
}
public Comment[] newArray(int size) {
return new Comment[size];
}
};
/* Getters and setters below */
public Bitmap getImageThumb() {
return imageThumb;
}
public void setImageThumb(Bitmap imageThumb) {
this.imageThumb = imageThumb;
}
public String getHash() {
return hash;
}
public void setHash(String hash) {
this.hash = hash;
}
public int getDepth() {
return depth;
}
public void setDepth(int depth) {
this.depth = depth;
}
public String getTextPost() {
return textPost;
}
public void setTextPost(String textPost) {
this.textPost = textPost;
}
public Bitmap getImage() {
return image;
}
public void setImage(Bitmap image) {
this.image = image;
}
public GeoLocation getLocation() {
return location;
}
public void setLocation(GeoLocation location) {
if (location.getLocation() == null) {
this.location = null;
} else {
this.location = location;
}
}
public Date getCommentDate() {
return commentDate;
}
public void setCommentDate(Date commentDate) {
this.commentDate = commentDate;
}
public Comment getParent() {
return parent;
}
public void setParent(Comment parent) {
this.parent = parent;
}
public ArrayList<Comment> getChildren() {
return children;
}
public Comment getChildAtIndex(int i) {
return children.get(i);
}
public void setChildren(ArrayList<Comment> children) {
this.children = children;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getId() {
return Long.toString(id);
}
public void setId(long id) {
this.id = id;
}
public ArrayList<String> getCommentIds() {
return commentIds;
}
public void setCommentIds(ArrayList<String> commentIds) {
this.commentIds = commentIds;
}
}