package de.tum.in.tumcampusapp.managers;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import com.google.gson.Gson;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import de.tum.in.tumcampusapp.api.TUMCabeClient;
import de.tum.in.tumcampusapp.auxiliary.Const;
import de.tum.in.tumcampusapp.auxiliary.Utils;
import de.tum.in.tumcampusapp.exceptions.NoPrivateKey;
import de.tum.in.tumcampusapp.models.tumcabe.ChatMember;
import de.tum.in.tumcampusapp.models.tumcabe.ChatMessage;
import de.tum.in.tumcampusapp.models.tumcabe.ChatVerification;
/**
* TUMOnline cache manager, allows caching of TUMOnline requests
*/
public class ChatMessageManager extends AbstractManager {
public static final int COL_ID = 0;
public static final int COL_PREVIOUS = 1;
public static final int COL_ROOM = 2;
public static final int COL_TEXT = 3;
public static final int COL_TIMESTAMP = 4;
public static final int COL_SIGNATURE = 5;
public static final int COL_MEMBER = 6;
public static final int COL_READ = 7;
public static final int COL_SENDING = 8;
private final int mChatRoom;
/**
* Constructor, open/create database, create table if necessary
*
* @param context Context
*/
public ChatMessageManager(Context context, int room) {
super(context);
mChatRoom = room;
init(db);
}
private static void init(SQLiteDatabase db) {
// create tables if needed
db.execSQL("CREATE TABLE IF NOT EXISTS chat_message (_id INTEGER PRIMARY KEY, previous INTEGER, room INTEGER, " +
"text TEXT, timestamp VARCHAR, signature TEXT, member BLOB, read INTEGER, sending INTEGER)");
db.execSQL("CREATE TABLE IF NOT EXISTS unsent_chat_message (_id INTEGER PRIMARY KEY AUTOINCREMENT, room INTEGER, text TEXT, member BLOB, msg_id INTEGER)");
// Delete all entries that are too old
db.rawQuery("DELETE FROM chat_message WHERE timestamp<datetime('now','-1 month')", null);
}
/**
* Gets all unsent chat messages
*/
public static List<ChatMessage> getAllUnsentUpdated(Context context) {
SQLiteDatabase db = AbstractManager.getDb(context);
init(db);
Cursor cur = db.rawQuery("SELECT member, text, room, msg_id, _id FROM unsent_chat_message ORDER BY _id", null);
List<ChatMessage> list = new ArrayList<>(cur.getCount());
if (cur.moveToFirst()) {
do {
ChatMember member = new Gson().fromJson(cur.getString(0), ChatMember.class);
ChatMessage msg = new ChatMessage(cur.getString(1), member);
msg.setRoom(cur.getInt(2));
msg.setId(cur.getInt(3));
msg.internalID = cur.getInt(4);
list.add(msg);
} while (cur.moveToNext());
}
cur.close();
return list;
}
public static ChatMessage toObject(Cursor cursor) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH);
int id = cursor.getInt(COL_ID);
String text = cursor.getString(COL_TEXT);
String time = formatter.format(Utils.getISODateTime(cursor.getString(COL_TIMESTAMP)));
int previous = cursor.getInt(COL_PREVIOUS);
ChatMember member = new Gson().fromJson(cursor.getString(COL_MEMBER), ChatMember.class);
ChatMessage msg = new ChatMessage(id, text, member, time, previous);
msg.setSignature(cursor.getString(COL_SIGNATURE));
msg.setRoom(cursor.getInt(COL_ROOM));
msg.setRead(cursor.getInt(COL_READ) == 1);
msg.setStatus(cursor.getInt(COL_SENDING));
return msg;
}
/**
* Gets all messages for the room
*
* @return List of chat messages
*/
public Cursor getAll() {
markAsRead();
return db.rawQuery("SELECT c.* FROM chat_message c, (SELECT c1._id " +
"FROM chat_message c1 LEFT JOIN chat_message c2 ON c2._id=c1.previous " +
"WHERE c2._id IS NULL AND c1.room=? " +
"ORDER BY c1._id DESC " +
"LIMIT 1) AS until " +
"WHERE c._id>=until._id AND c.room=? " +
"ORDER BY c._id", new String[]{String.valueOf(mChatRoom), String.valueOf(mChatRoom)});
}
public void markAsRead() {
db.execSQL("UPDATE chat_message SET read=1 WHERE read=0 AND room=?", new String[]{String.valueOf(mChatRoom)});
}
/**
* Gets all unsent chat messages from the current room
*/
public List<ChatMessage> getAllUnsent() {
Cursor cur = db.rawQuery("SELECT member, text, room, _id FROM unsent_chat_message WHERE msg_id=0 ORDER BY _id", null);
List<ChatMessage> list = new ArrayList<>(cur.getCount());
if (cur.moveToFirst()) {
do {
ChatMember member = new Gson().fromJson(cur.getString(0), ChatMember.class);
ChatMessage msg = new ChatMessage(cur.getString(1), member);
msg.setRoom(cur.getInt(2));
msg.internalID = cur.getInt(3);
list.add(msg);
} while (cur.moveToNext());
}
cur.close();
return list;
}
/**
* Saves the given message into database
*/
public void addToUnsent(ChatMessage m) {
//TODO handle message with already set id
Utils.logv("replace into unsent " + m.getText() + " " + m.getId() + " " + m.getPrevious() + " " + m.getStatus());
db.execSQL("REPLACE INTO unsent_chat_message (text,room,member,msg_id) VALUES (?,?,?, ?)",
new String[]{m.getText(), String.valueOf(mChatRoom), new Gson().toJson(m.getMember()), String.valueOf(m.getId())});
}
/**
* Removes the message from unsent database
*/
public void removeFromUnsent(ChatMessage message) {
db.execSQL("DELETE FROM unsent_chat_message WHERE _id=?", new String[]{String.valueOf(message.internalID)});
}
/**
* Gets all messages marked as unread
*/
public Cursor getUnread() {
return db.rawQuery("SELECT c.* FROM chat_message c, (SELECT c1._id " +
"FROM chat_message c1 LEFT JOIN chat_message c2 ON c2._id=c1.previous " +
"WHERE (c2._id IS NULL OR c1.read=1) AND c1.room=? " +
"ORDER BY c1._id DESC " +
"LIMIT 1) AS until " +
"WHERE c._id>until._id AND c.room=? " +
"ORDER BY c._id", new String[]{String.valueOf(mChatRoom), String.valueOf(mChatRoom)});
}
/**
* Gets all unread chat messages
*/
public List<ChatMessage> getLastUnread() {
Cursor cur = db.rawQuery("SELECT c.member, c.text FROM chat_message c, (SELECT c1._id " +
"FROM chat_message c1 LEFT JOIN chat_message c2 ON c2._id=c1.previous " +
"WHERE (c2._id IS NULL OR c1.read=1) AND c1.room=? " +
"ORDER BY c1._id DESC " +
"LIMIT 1) AS until " +
"WHERE c._id>until._id AND c.room=? " +
"ORDER BY c._id DESC " +
"LIMIT 5", new String[]{String.valueOf(mChatRoom), String.valueOf(mChatRoom)});
List<ChatMessage> list = new ArrayList<>(cur.getCount());
if (cur.moveToFirst()) {
do {
ChatMember member = new Gson().fromJson(cur.getString(0), ChatMember.class);
ChatMessage msg = new ChatMessage(cur.getString(1), member);
list.add(msg);
} while (cur.moveToNext());
}
cur.close();
return list;
}
/**
* Saves the given message into database
*/
public void replaceInto(ChatMessage m, int memberId) {
if (m == null || m.getText() == null) {
Utils.log("Message empty");
return;
}
Utils.logv("replace " + m.getText() + " " + m.getId() + " " + m.getPrevious() + " " + m.getStatus());
db.beginTransaction();
// Query read status from the previous message and use this read status as well if it is "0"
boolean read = memberId == m.getMember().getId();
Cursor cur = db.rawQuery("SELECT read FROM chat_message WHERE _id=?", new String[]{String.valueOf(m.getId())});
if (cur.moveToFirst() && cur.getInt(0) == 1) {
read = true;
}
cur.close();
m.setStatus(ChatMessage.STATUS_SENT);
m.setRead(read);
replaceMessage(m);
db.setTransactionSuccessful();
db.endTransaction();
}
public void replaceMessage(ChatMessage m) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH);
Date date;
try {
date = formatter.parse(m.getTimestamp());
} catch (ParseException e) {
date = new Date();
}
db.execSQL("REPLACE INTO chat_message (_id,previous,room,text,timestamp,signature,member,read,sending) VALUES (?,?,?,?,?,?,?,?,?)",
new String[]{String.valueOf(m.getId()), String.valueOf(m.getPrevious()), String.valueOf(mChatRoom), m.getText(), Utils.getDateTimeString(date),
m.getSignature(), new Gson().toJson(m.getMember()), m.getRead() ? "1" : "0", String.valueOf(m.getStatus())});
}
/**
* Saves the given message into database
*/
public void replaceInto(List<ChatMessage> m) {
ChatMember member = Utils.getSetting(mContext, Const.CHAT_MEMBER, ChatMember.class);
if (member == null) {
return;
}
db.beginTransaction();
for (ChatMessage msg : m) {
replaceInto(msg, member.getId());
}
db.setTransactionSuccessful();
db.endTransaction();
}
public Cursor getNewMessages(ChatMember member, int messageId) throws NoPrivateKey, IOException {
List<ChatMessage> messages;
if (messageId == -1) {
messages = TUMCabeClient.getInstance(mContext).getNewMessages(mChatRoom, new ChatVerification(mContext, member));
} else {
messages = TUMCabeClient.getInstance(mContext).getMessages(mChatRoom, messageId, new ChatVerification(mContext, member));
}
replaceInto(messages);
return getUnread();
}
}