package com.swingsane.business.scanning;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import javax.swing.SwingWorker;
import javax.swing.event.EventListenerList;
import org.apache.log4j.Logger;
import au.com.southsky.jfreesane.SaneDevice;
import au.com.southsky.jfreesane.SaneException;
import au.com.southsky.jfreesane.SaneOption;
import au.com.southsky.jfreesane.SanePasswordProvider;
import au.com.southsky.jfreesane.SaneSession;
import au.com.southsky.jfreesane.SaneStatus;
import au.com.southsky.jfreesane.ScanListener;
import com.swingsane.business.notification.ConsoleNotificationImpl;
import com.swingsane.business.notification.INotification;
import com.swingsane.i18n.Localizer;
import com.swingsane.preferences.model.Scanner;
public class ScanJob {
/**
* Log4J logger.
*/
private static final Logger LOG = Logger.getLogger(ScanJob.class);
/**
* Event Listener List for Scan Events.
*/
private EventListenerList listenerList = new EventListenerList();
/**
* Scan Event.
*/
private ScanEvent scanEvent;
/**
* Status notification with console output as default implementation.
*/
private INotification notification = new ConsoleNotificationImpl();
private Scanner scanner;
private SwingWorker<Void, Void> worker;
private int pagesToScan = Integer.MAX_VALUE;
private IScanService scanService;
private boolean useADF;
private String batchPrefix;
public ScanJob(IScanService scanServiceImpl, Scanner scanner) {
scanService = scanServiceImpl;
this.scanner = scanner;
}
public final void acquire(final ScanListener rateLimitedScanListener) {
worker = new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
getNotificaiton().message(Localizer.localize("ScanStartingMessage"));
String hostAddrStr = scanner.getRemoteAddress();
int port = scanner.getRemotePortNumber();
SaneSession session = null;
SaneDevice device = null;
try {
session = SaneSession.withRemoteSane(InetAddress.getByName(hostAddrStr), port);
session.setPasswordProvider(getPasswordProvider());
device = session.getDevice(scanner.getName());
try {
if (!(device.isOpen())) {
device.open();
}
} catch (IOException e) {
getNotificaiton().message(e.getLocalizedMessage());
LOG.warn(e, e);
return null;
}
try {
scanService.configure(device, scanner);
} catch (IOException ex) {
getNotificaiton().message(ex.getLocalizedMessage());
LOG.warn(ex, ex);
// continue if we can't set a setting.
}
int pageCount = 1;
while (!isCancelled()) {
try {
BufferedImage image = device.acquireImage(rateLimitedScanListener);
getNotificaiton().message(
String.format(Localizer.localize("ScannedPageMessage"), pageCount));
fireScanEvent(image, pageCount);
} catch (SaneException e) {
if (e.getStatus() == SaneStatus.STATUS_NO_DOCS) {
break;
} else {
getNotificaiton().message(e.getLocalizedMessage());
LOG.warn(e, e);
break;
}
} catch (IOException e) {
getNotificaiton().message(e.getLocalizedMessage());
LOG.warn(e, e);
break;
}
if (!useADF && (pageCount >= pagesToScan)) {
break;
}
pageCount++;
}
} catch (UnknownHostException e) {
getNotificaiton().message(e.getLocalizedMessage());
LOG.warn(e, e);
return null;
} catch (IOException e) {
getNotificaiton().message(e.getLocalizedMessage());
LOG.warn(e, e);
return null;
} finally {
try {
if ((device != null) && device.isOpen()) {
device.close();
}
} catch (IOException e) {
getNotificaiton().message(e.getLocalizedMessage());
LOG.warn(e, e);
}
if (session != null) {
session.close();
}
}
return null;
}
@Override
protected void done() {
try {
get();
getNotificaiton().message(Localizer.localize("ScanCompleteMessage"));
} catch (InterruptedException e) {
getNotificaiton().message(e.getLocalizedMessage());
LOG.warn(e, e);
} catch (ExecutionException e) {
getNotificaiton().message(e.getLocalizedMessage());
LOG.warn(e, e);
} catch (CancellationException e) {
getNotificaiton().message(Localizer.localize("ScanCancelledMessage"));
}
fireScanEvent(null, 0);
}
};
worker.execute();
}
public final void addScanListener(final ScanEventListener listener) {
listenerList.add(ScanEventListener.class, listener);
}
public final void cancel() {
worker.cancel(true);
}
public final void checkOptions() throws Exception {
String hostAddr = scanner.getRemoteAddress();
int port = scanner.getRemotePortNumber();
SaneSession session = null;
SaneDevice device = null;
try {
session = SaneSession.withRemoteSane(InetAddress.getByName(hostAddr), port);
session.setPasswordProvider(getPasswordProvider());
device = session.getDevice(scanner.getName());
if (!(device.isOpen())) {
device.open();
}
scanService.configure(device, scanner);
scanService.setScannerOptions(device, scanner);
} catch (UnknownHostException e) {
LOG.warn(e, e);
throw e;
} catch (SaneException e) {
LOG.warn(e, e);
throw e;
} catch (IOException e) {
LOG.warn(e, e);
throw e;
} finally {
try {
if ((device != null) && device.isOpen()) {
device.close();
}
} catch (IOException e) {
LOG.warn(e, e);
}
if (session != null) {
try {
session.close();
} catch (IOException e) {
LOG.warn(e, e);
}
}
}
}
private void fireScanEvent(final BufferedImage bufferedImage, int pageNumber) {
Object[] listeners = listenerList.getListenerList();
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == ScanEventListener.class) {
if (scanEvent == null) {
scanEvent = new ScanEvent(this);
}
scanEvent.setAcquiredImage(bufferedImage);
scanEvent.setPagesToScan(pagesToScan);
scanEvent.setPageNumber(pageNumber);
scanEvent.setBatchPrefix(getBatchPrefix());
((ScanEventListener) listeners[i + 1]).eventOccurred(scanEvent);
}
}
}
private String getBatchPrefix() {
return batchPrefix;
}
/**
* Returns an instance of INotification if set.
*
* @return an instance of INotification if set.
*/
public final INotification getNotificaiton() {
return notification;
}
private SanePasswordProvider getPasswordProvider() {
return scanService.getPasswordProvider();
}
public final boolean isActive() {
return !(worker.isDone());
}
/**
* @param listener
* a scan listener
*/
public final void removeScanEventListener(final ScanEventListener listener) {
listenerList.remove(ScanEventListener.class, listener);
}
public final void setBatchPrefix(String batchPrefix) {
this.batchPrefix = batchPrefix;
}
public final void setButtonValue(String key) {
String hostAddr = scanner.getRemoteAddress();
int port = scanner.getRemotePortNumber();
SaneSession session = null;
SaneDevice device = null;
try {
session = SaneSession.withRemoteSane(InetAddress.getByName(hostAddr), port);
session.setPasswordProvider(getPasswordProvider());
device = session.getDevice(scanner.getName());
if (!(device.isOpen())) {
device.open();
}
SaneOption saneOption = device.getOption(key);
saneOption.setButtonValue(); // TODO: BUG??? doesn't do anything???
} catch (UnknownHostException e) {
LOG.warn(e, e);
} catch (SaneException e) {
LOG.warn(e, e);
} catch (IOException e) {
LOG.warn(e, e);
} finally {
try {
if ((device != null) && device.isOpen()) {
device.close();
}
} catch (IOException e) {
LOG.warn(e, e);
}
if (session != null) {
try {
session.close();
} catch (IOException e) {
LOG.warn(e, e);
}
}
}
}
/**
* Sets an instance of INotification.
*
* @param notificationImpl
* an instance of INotification
*/
public final void setNotificaiton(final INotification notificationImpl) {
notification = notificationImpl;
}
public final void setPagesToScan(int pagesToScan) {
this.pagesToScan = pagesToScan;
}
public final void setUseADF(boolean useADF) {
this.useADF = useADF;
}
}