/*
* Copyright (C) 2014 Eric Butler
*
* 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 com.tapchatapp.android.client.model;
import android.util.Log;
import com.google.common.collect.EvictingQueue;
import com.tapchatapp.android.app.event.BufferChangedEvent;
import com.tapchatapp.android.app.event.BufferLineAddedEvent;
import com.tapchatapp.android.app.event.BufferRemovedEvent;
import com.tapchatapp.android.client.MessageHandler;
import com.tapchatapp.android.client.message.BufferEventMessage;
import com.tapchatapp.android.client.message.MakeBufferMessage;
import com.tapchatapp.android.client.message.request.ArchiveBufferMessage;
import com.tapchatapp.android.client.message.request.DeleteBufferMessage;
import com.tapchatapp.android.client.message.request.UnarchiveBufferMessage;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public abstract class Buffer {
public static final int CHANNEL_TYPE = 1;
public static final int CONVERSATION_TYPE = 2;
public static final int CONSOLE_TYPE = 3;
public static final int MAX_EVENTS = 500;
public static final Comparator<? super Buffer> COMPARATOR = new Comparator<Buffer>() {
@Override
public int compare(Buffer buffer, Buffer buffer1) {
Integer weight1 = buffer.getWeight();
Integer weight2 = buffer1.getWeight();
if (weight1.equals(weight2)) {
return buffer.getName().compareToIgnoreCase(buffer1.getName());
} else {
return weight2.compareTo(weight1);
}
}
};
private static final String TAG = "Buffer";
private Connection mConnection;
private boolean mExists = false;
private long mId;
private String mName;
private boolean mArchived;
private final EvictingQueue<BufferEvent> mEvents = EvictingQueue.create(MAX_EVENTS);
private List<Long> mMessageIds = new ArrayList<Long>();
private Map<String, MessageHandler> mMessageHandlers;
private Map<String, MessageHandler> mInitializedMessageHandlers;
private long mLastSeenEid;
private long mLastEid;
private boolean mUnread;
private int mHighlightCount;
Buffer(Connection connection, MakeBufferMessage message) throws Exception {
mConnection = connection;
mId = message.bid;
mMessageHandlers = getMessageHandlers();
mInitializedMessageHandlers = getInitializedMessageHandlers();
reload(message);
}
public long getId() {
return mId;
}
public abstract int getType();
public String getName() {
return mName;
}
public String getDisplayName() {
return mName;
}
public Connection getConnection() {
return mConnection;
}
public boolean isArchived() {
return mArchived;
}
public boolean isActive() {
return (getConnection().getState() == Connection.STATE_CONNECTED);
}
public BufferEvent[] getBacklog() {
synchronized (mEvents) {
return (BufferEvent[]) mEvents.toArray(new BufferEvent[mEvents.size()]);
}
}
public BufferEvent getLastEvent() {
synchronized (mEvents) {
BufferEvent[] backlog = getBacklog();
if (backlog.length > 0) {
return backlog[backlog.length - 1];
}
}
return null;
}
public BufferEvent getLastMessage() {
synchronized (mEvents) {
BufferEvent[] backlog = getBacklog();
BufferEvent event;
if (backlog.length > 0) {
for (int i = backlog.length - 1; i >= 0; i--) {
event = backlog[i];
if (event.getFirstItem().getMessage().type.equals("buffer_msg")) {
return event;
}
}
}
return null;
}
}
void setArchived(boolean archived) {
mArchived = archived;
}
boolean hasFocus() {
return getConnection().getService().getSelectedBuffer() == this;
}
public int getHighlightCount() {
return mHighlightCount;
}
public boolean isUnread() {
return mUnread;
}
public void markAllRead() {
BufferEvent[] backlog = getBacklog();
if (backlog.length > 0) {
long lastEid = backlog[backlog.length - 1].getLastItem().getEid();
markRead(lastEid);
}
}
public void markRead(long eid) {
if (eid < mLastEid) {
return;
}
mLastSeenEid = eid;
mUnread = false;
mHighlightCount = 0;
notifyChanged();
}
public void archive() {
ArchiveBufferMessage message = new ArchiveBufferMessage();
message.id = getId();
mConnection.post(message, null);
}
public void unarchive() {
UnarchiveBufferMessage message = new UnarchiveBufferMessage();
message.id = getId();
mConnection.post(message, null);
}
public void delete() {
DeleteBufferMessage message = new DeleteBufferMessage();
message.id = getId();
mConnection.post(message, null);
}
synchronized void processMessage(BufferEventMessage message) throws Exception {
long eid = message.eid;
String type = message.type;
if (eid > -1) { // FIXME
if (mMessageIds.contains(eid)) {
Log.w("Buffer", "Got duplicate message! " + message);
return;
}
mMessageIds.add(eid);
}
if (eid > mLastEid) {
mLastEid = eid;
}
if (eid > 0 && (!UNRENDERED_MESSAGES.contains(type))) {
BufferEvent lastEvent = getLastEvent();
BufferEventItem item = new BufferEventItem(message);
if (lastEvent != null && lastEvent.shouldMerge(item)) {
lastEvent.addItem(item);
} else {
addEvent(new BufferEvent(item));
}
if (eid > mLastSeenEid) {
if (hasFocus() || message.isSelf()) {
markRead(eid);
} else {
if (message.isImportant() && !mUnread) {
mUnread = true;
notifyChanged();
}
if (message.isHighlight()) {
mHighlightCount ++;
notifyChanged();
}
}
}
}
boolean isBacklogMessage = message.is_backlog;
if ((!isBacklogMessage) && (!getConnection().isBacklog()) && mInitializedMessageHandlers.containsKey(type)) {
mInitializedMessageHandlers.get(type).handleMessage(message);
}
if (mMessageHandlers.containsKey(type)) {
mMessageHandlers.get(type).handleMessage(message);
}
}
void notifyChanged() {
getConnection().getService().postToBus(new BufferChangedEvent(this));
}
void notifyRemoved() {
getConnection().getService().postToBus(new BufferRemovedEvent(this));
}
protected Map<String, MessageHandler> getMessageHandlers() {
return new HashMap<>();
}
protected Map<String, MessageHandler> getInitializedMessageHandlers() {
return new HashMap<>();
}
private void addEvent(BufferEvent event) {
synchronized (mEvents) {
mEvents.add(event);
}
getConnection().getService().postToBus(new BufferLineAddedEvent(this, event));
}
private static final List<String> UNRENDERED_MESSAGES = Arrays.asList(
"makebuffer",
"channel_init",
"connecting_finished",
// Channel status
"user_away",
"user_back",
"user_details",
"channel_timestamp",
// Conversation status
"whois_response",
"away",
// Connection status
"isupport_params",
"self_away",
"self_back",
// Overlay
"names_reply",
"query_too_long",
"try_again",
"accept_list",
"ban_list",
"ban_exception_list",
"links_response",
"silence_list",
"trace_response",
"who_response",
"ison",
"list_response_toomany",
"list_response",
"list_response_fetching",
"map_list",
"remote_isupport_params",
"userhost",
// Prompt
"channel_full",
"too_many_targets",
"no_messages_from_non_registered",
"not_registered",
"already_registered",
"no_such_nick",
"bad_channel_name",
"bad_channel_key",
"banned_from_channel",
"invite_only_chan",
"need_registered_nick",
"no_such_channel",
"too_many_channels"
);
public long getLastSeenEid() {
return mLastSeenEid;
}
public void reload(MakeBufferMessage message) {
mExists = true;
mName = message.name;
mArchived = (message.archived || message.hidden);
mLastSeenEid = message.last_seen_eid;
mHighlightCount = 0;
}
public boolean exists() {
return mExists;
}
@Override
public String toString() {
return String.format("%s{id=%s, name=%s, connection={%s}}", getClass().getName(), getId(), getName(), getConnection());
}
void serviceDisconnected() {
mExists = false;
}
public int getWeight() {
int weight = 0;
if (isArchived()) {
weight -= 99;
}
if (this instanceof ChannelBuffer) {
weight ++; // Show channels first
ChannelBuffer channelBuffer = (ChannelBuffer) this;
if (channelBuffer.isJoined()) {
weight ++; // Show joined channels first
}
}
return weight;
}
}