package com.zulip.android.models;
import com.google.gson.annotations.SerializedName;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.dao.RuntimeExceptionDao;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.stmt.SelectArg;
import com.j256.ormlite.table.DatabaseTable;
import com.zulip.android.ZulipApp;
import com.zulip.android.util.ZLog;
import org.apache.commons.lang.builder.HashCodeBuilder;
import java.sql.SQLException;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@DatabaseTable(tableName = "people")
public class Person {
public static final String NAME_FIELD = "name";
public static final String MESSAGESPARTICIPATEDIN_FIELD = "messagesParticipatedIn";
public static final String EMAIL_FIELD = "email";
public static final String ISBOT_FIELD = "isBot";
public static final String ISACTIVE_FIELD = "isActive";
private static final String ID_FIELD = "id";
private static final String AVATARURL_FIELD = "avatarUrl";
@SerializedName("user_id")
@DatabaseField(columnName = ID_FIELD, id = true)
protected int id;
@SerializedName("full_name")
@DatabaseField(columnName = NAME_FIELD)
private String name;
@SerializedName("email")
@DatabaseField(columnName = EMAIL_FIELD, uniqueIndex = true)
private String email;
@DatabaseField(columnName = AVATARURL_FIELD)
private String avatarURL;
@SerializedName("is_bot")
@DatabaseField(columnName = ISBOT_FIELD)
private boolean isBot;
@DatabaseField(columnName = ISACTIVE_FIELD)
private boolean isActive;
@SerializedName("is_admin")
private boolean isAdmin;
@SerializedName("domain")
private String domain;
@SerializedName("short_name")
private String shortName;
@SerializedName("is_mirror_dummy")
private boolean isMirrorDummy;
/**
* used to get person id in case of {@link Message.ZulipDirectMessage}
*/
@SerializedName("id")
private int recipientId;
public Person(String name, String email) {
this.setName(name);
this.setEmail(email);
}
public Person(String name, String email, String avatarURL) {
this(name, email);
this.setAvatarURL(avatarURL);
this.isActive = false;
}
public Person(int id, String name, String email, String avatarURL, boolean isBot, boolean isActive) {
this.setId(id);
this.setName(name);
this.setEmail(email);
this.setAvatarURL(avatarURL);
this.setActive(isActive);
this.setBot(isBot);
}
/**
* Construct an empty Person object.
*/
public Person() {
}
public static Person getByEmail(ZulipApp app, String email) {
try {
return getByEmail(app.getDatabaseHelper().getDao(
Person.class), email);
} catch (SQLException e) {
ZLog.logException(e);
}
return null;
}
@SuppressWarnings("WeakerAccess")
public static Person getByEmail(Dao<Person, ?> dao, String email) {
try {
return dao.queryBuilder().where()
.eq(Person.EMAIL_FIELD, new SelectArg(email))
.queryForFirst();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
@SuppressWarnings("WeakerAccess")
/**
* Returns person object {@link Person} from the database if exists or newly created object using
* the passed parameters.
* Note: always call this method with valid Person id {@link Person#id} passed as argument.
*
* @param app Zulip god object {@link ZulipApp}
* @param email person email {@link Person#email}
* @param name person name {@link Person#name}
* @param avatarURL person avatar url {@link Person#avatarURL}
* @param personId person id {@link Person#id}
* @param personCache person cache used ofr faster fetching of results
* @return {@link Person} object
*/
public static Person getOrUpdate(ZulipApp app, String email, String name,
String avatarURL, int personId, Map<String, Person> personCache) {
Person person = null;
if (personCache != null) {
person = personCache.get(email);
}
if (person == null) {
person = getByEmail(app, email);
if (personCache != null) {
personCache.put(email, person);
}
}
if (person == null) {
person = new Person(name, email, avatarURL);
// use the person id passed to generate person skeleton object which is consistent
// with server id.
person.setId(personId);
person.setActive(true);
app.getDao(Person.class).createOrUpdate(person);
} else {
boolean changed = false;
if (name != null && !name.equals(person.name)) {
person.name = name;
changed = true;
}
if (avatarURL != null && !avatarURL.equals(person.avatarURL)) {
person.avatarURL = avatarURL;
changed = true;
}
if (changed) {
person.setActive(true);
app.getDao(Person.class).update(person);
}
}
return person;
}
/**
* This function is called from setEmail {@link ZulipApp#setEmail(String)}.
* It is used to get current user person {@link Person} object if it exists in the database
* or create a new object using {@param email}.
*
* @param app {@link ZulipApp}
* @param email Person email id {@link Person#email}
* @return {@link Person} object
*/
public static Person get(ZulipApp app, String email) {
Person foundPerson = getByEmail(app, email);
if (foundPerson == null) {
// fake it till you make it
return new Person(null, email);
}
return foundPerson;
}
/**
* This function is used to call {@link Person#getOrUpdate(ZulipApp, String, String, String, int, Map)}
* with no cache.
* Note: always call this method with valid Person id {@link Person#id} passed as argument.
*
* @param app Zulip god object {@link ZulipApp}
* @param email person email {@link Person#email}
* @param name person name {@link Person#name}
* @param avatarURL person avatar url {@link Person#avatarURL}
* @param personId person id {@link Person#id}
* @return {@link Person} object
*/
public static Person getOrUpdate(ZulipApp app, String email, String name,
String avatarURL, int personId) {
return getOrUpdate(app, email, name, avatarURL, personId, null);
}
public static Person getById(ZulipApp app, int id) {
RuntimeExceptionDao<Person, Object> dao = app.getDao(Person.class);
return dao.queryForId(id);
}
public static List<Person> getAllPeople(ZulipApp app) throws SQLException {
RuntimeExceptionDao<Person, Object> dao = app.getDao(Person.class);
return dao.queryBuilder().where().eq(Person.ISBOT_FIELD, false).query();
}
public static void sortByPresence(ZulipApp app, List<Person> people) {
final Map<String, Presence> presenceCopy = new HashMap<>(
app.presences);
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person a, Person b) {
Presence aPresence = presenceCopy.get(a.getEmail());
Presence bPresence = presenceCopy.get(b.getEmail());
final int inactiveTimeout = 2 * 60;
if (aPresence == null && bPresence == null) {
return a.getName().toLowerCase(Locale.US)
.compareTo(b.getName().toLowerCase(Locale.US));
} else if (aPresence == null) {
return 1;
} else if (bPresence == null) {
return -1;
} else if (aPresence.getAge() > inactiveTimeout
&& bPresence.getAge() > inactiveTimeout) {
return a.getName().toLowerCase(Locale.US)
.compareTo(b.getName().toLowerCase(Locale.US));
} else if (aPresence.getAge() > inactiveTimeout) {
return 1;
} else if (bPresence.getAge() > inactiveTimeout) {
return -1;
} else if (aPresence.getStatus() == bPresence.getStatus()) {
return a.getName().toLowerCase(Locale.US)
.compareTo(b.getName().toLowerCase(Locale.US));
} else if (aPresence.getStatus() == PresenceType.ACTIVE) {
return -1;
} else {
return 1;
}
}
});
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
private void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
private void setEmail(String email) {
if (email != null) {
this.email = email.toLowerCase(Locale.US);
}
}
public boolean getIsBot() {
return isBot;
}
public String getAvatarURL() {
return avatarURL;
}
private void setAvatarURL(String avatarURL) {
this.avatarURL = avatarURL;
}
/**
* Calculate the Humbug realm for the person, currently by splitting the
* email address.
* <p/>
* In the future, realms may be distinct from your email hostname.
*
* @return the Person's realm.
*/
public String getRealm() {
String[] splitEmail = this.getEmail().split("@");
return splitEmail[splitEmail.length - 1];
}
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (obj == this) {
return true;
}
if (!(obj instanceof Person)) {
return false;
}
Person per = (Person) obj;
if (this.name == null || this.email == null)
return false;
return this.name.equals(per.getName()) && this.email.equals(per
.getEmail());
}
public int hashCode() {
return new HashCodeBuilder(17, 31).append(name).append(email)
.toHashCode();
}
@SuppressWarnings("WeakerAccess")
public void setBot(boolean isBot) {
this.isBot = isBot;
}
public void setActive(boolean active) {
isActive = active;
}
public int getRecipientId() {
return this.recipientId;
}
public void setRecipientId(int id) {
this.recipientId = id;
}
}