/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
*
* 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 net.java.sip.communicator.impl.muc;
import java.util.*;
import java.util.regex.*;
import net.java.sip.communicator.service.contactsource.*;
import net.java.sip.communicator.service.muc.*;
import net.java.sip.communicator.service.protocol.*;
/**
* The ServerChatRoomQuery is a query over the
* ServerChatRoomContactSourceService.
*
* @author Hristo Terezov
*/
public class ServerChatRoomQuery
extends AsyncContactQuery
implements ChatRoomProviderWrapperListener
{
/**
* The query string.
*/
private String queryString;
/**
* List with the current results for the query.
*/
private Set contactResults
= new TreeSet();
/**
* MUC service.
*/
private MUCServiceImpl mucService;
/**
* The number of contact query listeners.
*/
private int contactQueryListenersCount = 0;
/**
* The provider associated with the query.
*/
private ChatRoomProviderWrapper provider = null;
/**
* Creates an instance of ChatRoomQuery by specifying
* the parent contact source, the query string to match and the maximum
* result contacts to return.
*
* @param contactSource the parent contact source
* @param queryString the query string to match
* @param provider the provider associated with the query
*/
public ServerChatRoomQuery(String queryString,
ServerChatRoomContactSourceService contactSource,
ChatRoomProviderWrapper provider)
{
super(contactSource,
Pattern.compile(queryString, Pattern.CASE_INSENSITIVE
| Pattern.LITERAL), true);
this.queryString = queryString;
mucService = MUCActivator.getMUCService();
this.provider = provider;
}
/**
* Adds listeners for the query
*/
private void initListeners()
{
mucService.addChatRoomProviderWrapperListener(this);
}
@Override
protected void run()
{
if(provider == null)
{
Iterator chatRoomProviders
= mucService.getChatRoomProviders();
while (chatRoomProviders.hasNext())
{
ChatRoomProviderWrapper provider = chatRoomProviders.next();
providerAdded(provider, true);
}
}
else
{
providerAdded(provider, true);
}
if (getStatus() != QUERY_CANCELED)
setStatus(QUERY_COMPLETED);
}
/**
* Handles adding a chat room provider.
* @param provider the provider.
* @param addQueryResult indicates whether we should add the chat room to
* the query results or fire an event without adding it to the results.
*/
private void providerAdded(final ChatRoomProviderWrapper provider,
final boolean addQueryResult)
{
final ProtocolProviderService pps = provider.getProtocolProvider();
List chatRoomNames =
MUCActivator.getMUCService().getExistingChatRooms(provider);
if (chatRoomNames == null)
{
return;
}
// Already create all the BaseChatRoomSourceContact instances since all
// the data is already available.
final Set chatRooms =
new HashSet(chatRoomNames.size());
for (final String name : chatRoomNames)
{
chatRooms.add(new BaseChatRoomSourceContact(name, name, this, pps));
}
addChatRooms(pps, chatRooms, addQueryResult);
}
/**
* Adds found result to the query results.
*
* @param pps the protocol provider associated with the found chat room.
* @param chatRoomName the name of the chat room.
* @param chatRoomID the id of the chat room.
* @param addQueryResult indicates whether we should add the chat room to
* the query results or fire an event without adding it to the results.
*/
private void addChatRoom(ProtocolProviderService pps,
String chatRoomName, String chatRoomID, boolean addQueryResult)
{
if((queryString == null
|| ((chatRoomName.contains(
queryString)
|| chatRoomID.contains(queryString)
))) && isMatching(chatRoomID, pps))
{
BaseChatRoomSourceContact contact
= new BaseChatRoomSourceContact(chatRoomName, chatRoomID, this,
pps);
synchronized (contactResults)
{
contactResults.add(contact);
}
if(addQueryResult)
{
addQueryResult(contact, false);
}
else
{
fireContactReceived(contact, false);
}
}
}
/**
* Adds found results to the query results.
*
* @param pps the protocol provider associated with the found chat room.
* @param chatRooms The set of chat rooms based on
* BaseChatRoomSourceContact. This is the full set and it will be
* filtered according to demands of the queryString.
* @param addQueryResult indicates whether we should add the chat room to
* the query results or fire an event without adding it to the
* results.
*/
private void addChatRooms(final ProtocolProviderService pps,
final Set chatRooms,
final boolean addQueryResult)
{
BaseChatRoomSourceContact room;
Iterator iterator = chatRooms.iterator();
while (iterator.hasNext())
{
room = iterator.next();
// Notice the NOT operator at the start ...
if (!((queryString == null || (room.getChatRoomName().contains(
queryString) || room.getChatRoomID().contains(queryString)))
&& isMatching(room.getChatRoomID(), pps)))
{
iterator.remove();
}
}
synchronized (contactResults)
{
contactResults.addAll(chatRooms);
}
if (addQueryResult)
{
addQueryResults(chatRooms);
}
else
{
// TODO Need something to fire one event for multiple contacts.
for (SourceContact contact : chatRooms)
{
fireContactReceived(contact, false);
}
}
}
@Override
public void chatRoomProviderWrapperAdded(ChatRoomProviderWrapper provider)
{
providerAdded(provider, false);
}
@Override
public void chatRoomProviderWrapperRemoved(ChatRoomProviderWrapper provider)
{
LinkedList tmpContactResults;
synchronized (contactResults)
{
tmpContactResults
= new LinkedList(contactResults);
for(BaseChatRoomSourceContact contact : tmpContactResults)
{
if(contact.getProvider().equals(provider.getProtocolProvider()))
{
contactResults.remove(contact);
fireContactRemoved(contact);
}
}
}
}
/**
* Clears any listener we used.
*/
private void clearListeners()
{
mucService.removeChatRoomProviderWrapperListener(this);
}
/**
* Cancels this ContactQuery.
*
* @see ContactQuery#cancel()
*/
public void cancel()
{
clearListeners();
super.cancel();
}
/**
* If query has status changed to cancel, let's clear listeners.
* @param status {@link ContactQuery#QUERY_CANCELED},
* {@link ContactQuery#QUERY_COMPLETED}
*/
public void setStatus(int status)
{
if(status == QUERY_CANCELED)
clearListeners();
super.setStatus(status);
}
@Override
public void addContactQueryListener(ContactQueryListener l)
{
super.addContactQueryListener(l);
contactQueryListenersCount++;
if(contactQueryListenersCount == 1)
{
initListeners();
}
}
@Override
public void removeContactQueryListener(ContactQueryListener l)
{
super.removeContactQueryListener(l);
contactQueryListenersCount--;
if(contactQueryListenersCount == 0)
{
clearListeners();
}
}
/**
* Checks if the contact should be added to results or not.
* @param chatRoomID the chat room id associated with the contact.
* @param pps the provider of the chat room contact.
* @return true if the result should be added to the results and
* false if not.
*/
public boolean isMatching(String chatRoomID, ProtocolProviderService pps)
{
return (MUCActivator.getMUCService().findChatRoomWrapperFromChatRoomID(
chatRoomID, pps) == null);
}
/**
* Returns the index of the contact in the contact results list.
* @param contact the contact.
* @return the index of the contact in the contact results list.
*/
public int indexOf(BaseChatRoomSourceContact contact)
{
Iterator it = contactResults.iterator();
int i = 0;
while(it.hasNext())
{
if(contact.equals(it.next()))
{
return i;
}
i++;
}
return -1;
}
}