package com.workshare.msnos.core.receipts;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import com.workshare.msnos.core.Message;
import com.workshare.msnos.core.Receipt;
import com.workshare.msnos.core.Message.Status;
public class MultiReceipt implements Receipt {
private final UUID messageUuid;
private final Set<Receipt> receipts;
public MultiReceipt(Message message, Receipt... someReceipts) {
this(message, Arrays.asList(someReceipts));
}
public MultiReceipt(Message message, List<Receipt> someReceipts) {
this.messageUuid = message.getUuid();
this.receipts = Collections.newSetFromMap(new ConcurrentHashMap<Receipt, Boolean>());
receipts.addAll(someReceipts);
}
public void add(Receipt receipt) {
receipts.add(receipt);
}
public Set<Receipt> getReceipts() {
return Collections.unmodifiableSet(receipts);
}
public UUID getMessageUuid() {
return messageUuid;
}
public Status getStatus() {
Status status = Status.UNKNOWN;
for (Receipt receipt : receipts) {
if (receipt.getStatus() == Status.FAILED && status == Status.UNKNOWN) {
status = Status.FAILED;
}
else if (receipt.getStatus() == Status.PENDING) {
status = Status.PENDING;
}
else if (receipt.getStatus() == Status.DELIVERED) {
status = Status.DELIVERED;
break;
}
}
return status;
}
public boolean waitForDelivery(long amount, TimeUnit unit) throws InterruptedException {
final long tenth = unit.toMillis(amount)/10;
while(amount > 0) {
amount-=tenth;
if (receipts.size() == 0)
justWait(tenth);
else
if (waitForDelivery(tenth))
return true;
}
return getStatus() == Status.DELIVERED;
}
private synchronized void justWait(long millis) throws InterruptedException {
this.wait(millis);
}
private boolean waitForDelivery(long millis) throws InterruptedException {
long slice = millis / receipts.size();
for (Receipt receipt : receipts) {
boolean res = receipt.waitForDelivery(slice, TimeUnit.MILLISECONDS);
if (res == true)
return true;
}
return false;
}
public int size() {
return receipts.size();
}
@Override
public String getGate() {
StringBuilder buffer = new StringBuilder();
for (Receipt receipt : receipts) {
if (receipt.getStatus() == Status.DELIVERED)
return receipt.getGate();
if (receipt.getStatus() == Status.FAILED)
continue;
if (buffer.length() > 0)
buffer.append("+");
buffer.append(receipt.getGate());
}
return buffer.toString();
}
@Override
public String toString() {
return getStatus()+":"+messageUuid;
}
}