package esmska.data;
import esmska.data.event.ActionEventSupport;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.ListIterator;
import java.util.logging.Logger;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
/** SMS history entity
*
* @author ripper
*/
public class History {
/** shared instance */
private static final History instance = new History();
/** new record added */
public static final int ACTION_ADD_RECORD = 0;
/** existing record removed */
public static final int ACTION_REMOVE_RECORD = 1;
/** all records removed */
public static final int ACTION_CLEAR_RECORDS = 2;
private static final Logger logger = Logger.getLogger(History.class.getName());
private final List<Record> records = Collections.synchronizedList(new ArrayList<Record>());
// <editor-fold defaultstate="collapsed" desc="ActionEvent support">
private ActionEventSupport actionSupport = new ActionEventSupport(this);
public void addActionListener(ActionListener actionListener) {
actionSupport.addActionListener(actionListener);
}
public void removeActionListener(ActionListener actionListener) {
actionSupport.removeActionListener(actionListener);
}
// </editor-fold>
/** disabled contructor */
private History() {
}
/** Get shared instance */
public static History getInstance() {
return instance;
}
/** get all records in unmodifiable list */
public List<Record> getRecords() {
return Collections.unmodifiableList(records);
}
/** get record at index */
public Record getRecord(int index) {
return records.get(index);
}
/** add new record */
public void addRecord(Record record) {
records.add(record);
actionSupport.fireActionPerformed(ACTION_ADD_RECORD, null);
logger.finer("New history record added: " + record);
}
/** add new records */
public void addRecords(Collection<Record> records) {
for (Record record : records) {
this.records.add(record);
}
logger.finer(records.size() + " new history records added");
actionSupport.fireActionPerformed(ACTION_ADD_RECORD, null);
}
/** remove existing record */
public void removeRecord(Record record) {
records.remove(record);
actionSupport.fireActionPerformed(ACTION_REMOVE_RECORD, null);
logger.finer("A history record removed: " + record);
}
/** remove existing records */
public void removeRecords(Collection<Record> records) {
for (Record record : records) {
this.records.remove(record);
}
logger.finer(records.size() + " history records removed");
actionSupport.fireActionPerformed(ACTION_REMOVE_RECORD, null);
}
/** Remove all records older than limit time
* @param date limit time which records to keep, older are removed; not null
*/
public void removeRecordsOlderThan(Date date) {
Validate.notNull(date);
logger.fine("Erasing all history records older than: " + date);
synchronized (records) {
ListIterator<Record> iter = records.listIterator();
while (iter.hasNext()) {
Record record = iter.next();
if (record.getDate().before(date)) {
iter.remove();
} else {
//records are sorted in time, therefore on first newer message
//stop iterating
break;
}
}
}
}
/** delete all records */
public void clearRecords() {
records.clear();
actionSupport.fireActionPerformed(ACTION_CLEAR_RECORDS, null);
logger.finer("All history records removed");
}
/** Find last (as in time) record sent to specified gateway.
* @param gatewayName name of the gateway
* @return the last (the most recent) record sent to specified gateway.
* Null when none found.
*/
public synchronized Record findLastRecord(String gatewayName) {
ListIterator<Record> iter = records.listIterator(records.size());
while (iter.hasPrevious()) {
Record record = iter.previous();
if (ObjectUtils.equals(record.getGateway(), gatewayName)) {
return record;
}
}
return null;
}
/** Single history record */
public static class Record {
private String number; //recipient number
private String name; //recipient name
private String text; //message text
private String senderNumber;
private String senderName;
private String gateway;
private Date date;
private String smsId; //message ID from SMS
/** Create new Record. For detailed parameters restrictions see individual setter methods.
* @param number not null nor empty
* @param text not null
* @param gateway not null nor empty
* @param name
* @param senderNumber
* @param senderName
* @param date null for current time
* @param smsId
*/
public Record(String number, String text, String gateway, String name,
String senderNumber, String senderName, Date date, String smsId) {
setName(name);
setNumber(number);
setText(text);
setSenderNumber(senderNumber);
setSenderName(senderName);
setGateway(gateway);
setDate(date);
setSmsId(smsId);
}
// <editor-fold defaultstate="collapsed" desc="Get Methods">
/** Recepient number in international format (starting with "+").
* Never null nor empty. */
public String getNumber() {
return number;
}
/** Name of the recepient. Never null. */
public String getName() {
return name;
}
/** Text of the message. Never null. */
public String getText() {
return text;
}
/** Sender number. Never null. */
public String getSenderNumber() {
return senderNumber;
}
/** Sender name. Never null. */
public String getSenderName() {
return senderName;
}
/** Gateway of the message. Never null nor empty. */
public String getGateway() {
return gateway;
}
/** SMS ID **/
public String getSmsId() {
return smsId;
}
/** Date of the sending. Never null. */
public Date getDate() {
return date;
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Set Methods">
/** Recepient number in international format (starting with "+").
* May not be null nor empty. */
public void setNumber(String number) {
Validate.notEmpty(number);
if (!number.startsWith("+")) {
throw new IllegalArgumentException("Number does not start with '+': " + number);
}
this.number = number;
}
/** Name of the recepient. Null value is changed to empty string. */
public void setName(String name) {
this.name = StringUtils.defaultString(name);
}
/** Text of the message. May not be null. */
public void setText(String text) {
Validate.notNull(text);
this.text = text;
}
/** Sender number. Null value is changed to empty string. */
public void setSenderNumber(String senderNumber) {
this.senderNumber = StringUtils.defaultString(senderNumber);
}
/** Sender name. Null value is changed to empty string. */
public void setSenderName(String senderName) {
this.senderName = StringUtils.defaultString(senderName);
}
/** Gateway of the message. May not be null nor empty. */
public void setGateway(String gateway) {
Validate.notEmpty(gateway);
this.gateway = gateway;
}
/** SMS ID.
* This is used for matching fragments of the same SMS.
* If there already is a record in the history with the same smsId,
* the text of the new record is appended to the text of the
* previous record, and no new record is created. Can be null for
* no ID.
*/
public void setSmsId(String smsId) {
this.smsId = smsId;
}
/** Date of the sending. Null value is inicialized with current time. */
public void setDate(Date date) {
if (date == null) {
date = new Date();
}
this.date = date;
}
// </editor-fold>
@Override
public String toString() {
return "[date=" + date + ", name=" + name + "]";
}
}
}