package com.cari.voip.keyboard.stack;
import java.io.IOException;
import java.io.Writer;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import com.cari.voip.keyboard.stack.events.Packet;
import com.cari.voip.keyboard.stack.events.PacketFilter;
import com.cari.voip.keyboard.stack.events.PacketListener;
import com.cari.voip.keyboard.stack.events.PacketListenerWrapper;
public class PacketWriter {
private CCKPConnection connection;
private Writer writer;
private final BlockingQueue<Packet> queue;
private final BlockingQueue<Packet> queueSended;
private Thread writerThread;
//private Thread keepAliveThread;
private boolean done = false;
private final Map<PacketListener,PacketListenerWrapper> sendListeners =
new ConcurrentHashMap<PacketListener,PacketListenerWrapper>();
private final Map<PacketListener,PacketListenerWrapper> writeListeners =
new ConcurrentHashMap<PacketListener,PacketListenerWrapper>();
private long lastActive;
protected PacketWriter(CCKPConnection connection){
this.queue = new ArrayBlockingQueue<Packet>(500,true);
this.queueSended = new ArrayBlockingQueue<Packet>(500,true);
this.connection = connection;
init();
}
protected void init() {
done = false;
this.writerThread = new Thread(){
public void run(){
writePackets(this);
}
};
this.writerThread.setName("CCKP Packet Writer");
this.writerThread.setDaemon(true);
}
public void sendPacket(Packet packet){
if(!done){
try {
queue.put(packet);
} catch (InterruptedException e) {
e.printStackTrace();
return;
}
synchronized(queue){
queue.notifyAll();
}
processSendListeners(packet);
}
}
public void addPacketSendListener(PacketListener packetListener,PacketFilter packetFilter){
this.sendListeners.put(packetListener,
new PacketListenerWrapper(packetListener,packetFilter));
}
public void addPacketWriteListener(PacketListener packetListener,PacketFilter packetFilter){
this.writeListeners.put(packetListener,
new PacketListenerWrapper(packetListener,packetFilter));
}
public void removePakcetSendListener(PacketListener packetListener){
this.sendListeners.remove(packetListener);
}
public void removePakcetWriteListener(PacketListener packetListener){
this.writeListeners.remove(packetListener);
}
public int getPacketSendListenerCount(){
return this.sendListeners.size();
}
public int getPacketWriteListenerCount(){
return this.writeListeners.size();
}
public void startup(){
resetWriter();
this.writerThread.start();
}
public void shutdown(){
done = true;
synchronized(queue){
queue.notifyAll();
}
}
void cleanup(){
this.sendListeners.clear();
this.writeListeners.clear();
}
void resetWriter(){
this.writer = this.connection.writer;
}
public Packet nextPacketSended(){
Packet packet = null;
if(!done){
packet = this.queueSended.poll();
}
return packet;
}
protected Packet nextPacket(){
Packet packet = null;
while(!done && (packet = this.queue.poll()) == null){
try{
synchronized(queue){
queue.wait();
}
}catch(InterruptedException ie){
//do nothing
}
}
return packet;
}
protected void processSendListeners(Packet packet) {
for(PacketListenerWrapper listenerWrapper: this.sendListeners.values()){
listenerWrapper.notifyListener(packet);
}
}
protected void queuePackets(Packet packet) {
try {
this.queueSended.put(packet);
} catch (InterruptedException e) {
e.printStackTrace();
return;
}
processWriteListeners(packet);
}
protected void processWriteListeners(Packet packet) {
for(PacketListenerWrapper listenerWrapper: this.writeListeners.values()){
listenerWrapper.notifyListener(packet);
}
}
protected void writePackets(Thread thread) {
try{
openStream();
while(!done && (this.writerThread == thread)){
Packet packet = this.nextPacket();
if(packet != null){
writer.write(packet.toString());
writer.flush();
lastActive = System.currentTimeMillis();
queuePackets(packet);
}
}
while(! queue.isEmpty()){
Packet packet = queue.remove();
writer.write(packet.toString());
}
writer.flush();
queue.clear();
//close the stream
closeStream();
}
catch(IOException ioe){
if(!done){
done = true;
this.connection.notifyConnectionError(ioe);
}
}
}
void closeStream() {
try{
writer.close();
}catch(Exception e){
// do nothing
}
}
void openStream() {
// TODO Auto-generated method stub
}
}