package com.niklim.clicktrace.service;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
import com.niklim.clicktrace.ErrorNotifier;
import com.niklim.clicktrace.TimeMeter;
import com.niklim.clicktrace.msg.ErrorMsgs;
/**
* Compresses and saves images in own thread.
*/
public class ImageSaver implements Runnable {
private static final Logger log = LoggerFactory.getLogger(ImageSaver.class);
private static Format format = new SimpleDateFormat("yyyy.MM.dd-HH.mm.ss");
private final FileCompressor compressor = new FileCompressor("jpg", "png");
private final BlockingQueue<SaveTask> queue = new LinkedBlockingDeque<SaveTask>();
@Inject
private FileManager fileManager;
private static class SaveTask {
BufferedImage image;
String sessionName;
Date date;
public SaveTask(BufferedImage image, String sessionName, Date date) {
this.image = image;
this.sessionName = sessionName;
this.date = date;
}
}
public ImageSaver() {
new Thread(this).start();
}
/**
* Enqueues a save task.
*
* @param image
* @param sessionName
* @throws IOException
*/
public void save(BufferedImage image, String sessionName) {
queue.add(new SaveTask(image, sessionName, new Date()));
}
@Override
public void run() {
try {
while (true) {
SaveTask saving = queue.take();
try {
saveImage(saving);
} catch (IOException e) {
log.error(ErrorMsgs.SCREENSHOT_SAVE_ERROR, e);
ErrorNotifier.notify(ErrorMsgs.SCREENSHOT_SAVE_ERROR);
}
}
} catch (InterruptedException e) {
log.error(ErrorMsgs.SCREENSHOT_SAVE_ERROR, e);
ErrorNotifier.notify(ErrorMsgs.SCREENSHOT_SAVE_FATAL_ERROR);
}
}
private void saveImage(SaveTask saveTask) throws IOException {
TimeMeter tm = TimeMeter.start("ImageSaver.saveImage", log);
FileCompressor.CompressionResult compressionResult = compressor.getBestCompressed(saveTask.image);
File file = findFileToSave(saveTask.sessionName, compressionResult, saveTask.date);
FileOutputStream fop = new FileOutputStream(file);
fop.write(compressionResult.stream.toByteArray());
fop.flush();
fop.close();
tm.stop();
}
/**
* Creates filepath based on timestamp (sec precision). If file already
* exists, then appends 'x' to the timestamp and checks again if exists, and
* so on.
*
* @param sessionName
* @param compressionResult
* @return
*/
private File findFileToSave(String sessionName, FileCompressor.CompressionResult compressionResult, Date date) {
String timeStamp = format.format(date);
File file;
String postfix = "";
do {
String filename = timeStamp + postfix + "." + compressionResult.format;
String filePath = fileManager.createFilePath(sessionName, filename);
file = new File(filePath);
postfix += "x";
} while (file.exists());
return file;
}
}