package topasin.calculate;
import static topasin.util.TopAsinUtil.log;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.lang3.ArrayUtils;
import topasin.describer.AsinDescriberFactory;
import topasin.filter.AsinDetailFilterFactory;
import topasin.processor.AsinDetailFiller;
import topasin.util.AsinDetailSortComparator;
import topasin.util.TopAsinContext;
import topasin.util.TopAsinUtil;
/**
* fill details to top asin and output top asin.
*
* @author mengzang
*
*/
public class TopAsinDescriptionOutputer {
TopAsinContext topAsinContext;
public TopAsinDescriptionOutputer(TopAsinContext context) {
this.topAsinContext = context;
}
public void outputTopAsinAnlysisResult(Map<String, TopAsinsCalculator> topAsinResult) {
Map<String, Map<String, AsinDetailAnalysisFields>> group2TopAsinMap = prepareTopAsinMap(topAsinResult);
Map<String, Map<String, AsinDetailAnalysisFields>> topAsinWithDetails = fillAsinDetailData2TopAsin(group2TopAsinMap);
dumpTopAsin(topAsinWithDetails);
}
private void dumpTopAsin(Map<String, Map<String, AsinDetailAnalysisFields>> topAsinWithDetails) {
PrintWriter output = null;
try {
output = topAsinContext.getOutput();
} catch (FileNotFoundException e) {
throw new IllegalArgumentException(TopAsinUtil.OUTPUT_FILE_NOT_CREATEABLE_ERR, e);
}
List<String> describerNames = AsinDescriberFactory.getAllDescriberNames();
for (int i = 0; i < describerNames.size(); i++) {
log("Outputing top asin decription using describer " + describerNames.get(i) + "...");
Collection<Entry<String, Map<String, AsinDetailAnalysisFields>>> sortedTopAsinEntries = TopAsinUtil
.sortMapEntryByGroupKey(topAsinWithDetails.entrySet());
Comparator<AsinDetailAnalysisFields> topAsinComparatorByAbsDiff = AsinDetailSortComparator.getInstance();
for (Entry<String, Map<String, AsinDetailAnalysisFields>> topAsin4Group : sortedTopAsinEntries) {
AsinDetailAnalysisFields[] sortedTopAsin4Group = topAsin4Group.getValue().values()
.toArray(new AsinDetailAnalysisFields[0]);
if (ArrayUtils.isEmpty(sortedTopAsin4Group) == true) {
continue;
}
output.println(sortedTopAsin4Group[0].getDescribers()[i].getTopAsinGroupStartDescription());
Arrays.sort(sortedTopAsin4Group, topAsinComparatorByAbsDiff);
for (AsinDetailAnalysisFields topAsin : sortedTopAsin4Group) {
String description = topAsin.getDescribers()[i].getTopAsinDescription();
output.println(description);
}
output.println("");
}
}
output.close();
log("Output top asin decription finished.");
}
private CountDownLatch startFillAsinDetailsData(BufferedReader origReader, int source, int threadNumber,
Map<String, Map<String, AsinDetailAnalysisFields>> group2TopAsins) {
AtomicInteger origLineCounter = new AtomicInteger();
Runnable[] fillers = new Runnable[threadNumber];
for (int i = 0; i < threadNumber; i++) {
fillers[i] = new AsinDetailFiller(origReader, source, AsinDetailFilterFactory.getFilter(), group2TopAsins,
origLineCounter);
}
String fillerName = TopAsinContext.ORIG_SOURCE == source ? "Original asin detail filler"
: "New asin detail filler";
int logInterval = (Integer) topAsinContext.getRTOptions().get(TopAsinContext.LOG_INTERVAL);
final CountDownLatch finishLock = new CountDownLatch(1);
TopAsinUtil.asyncExecuteMulthThreadAndWait4Termination(fillerName, fillers, logInterval, origLineCounter,
new Runnable() {
@Override
public void run() {
finishLock.countDown();
}
});
return finishLock;
}
private Map<String, Map<String, AsinDetailAnalysisFields>> fillAsinDetailData2TopAsin(
Map<String, Map<String, AsinDetailAnalysisFields>> group2TopAsins) {
int outputThreadNumber = (Integer) topAsinContext.getRTOptions().get(TopAsinContext.OUTPUT_THREAD_NUMBER);
int origFileIteratorThread = outputThreadNumber;
int newFileIteratorThread = outputThreadNumber;
log("Filling top asin with asin details...");
try {
BufferedReader origReader = topAsinContext.getOriginalFileReader();
CountDownLatch origFillerLock = startFillAsinDetailsData(origReader, TopAsinContext.ORIG_SOURCE,
origFileIteratorThread, group2TopAsins);
origFillerLock.await();
BufferedReader newReader = topAsinContext.getNewFileReader();
CountDownLatch newFillerLock = startFillAsinDetailsData(newReader, TopAsinContext.NEW_SOURCE,
newFileIteratorThread, group2TopAsins);
newFillerLock.await();
log("Filling top asin with asin finished");
} catch (IOException e) {
System.exit(119);
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return group2TopAsins;
}
/**
* move top asin from TopAsins's queue to a Map<String(Asin),AsinDetailAnalysisFields>
*
* @param topAsinResult
* @return
*/
private static Map<String, Map<String, AsinDetailAnalysisFields>> prepareTopAsinMap(
Map<String, TopAsinsCalculator> topAsinResult) {
// no multi-thread write. use HashMap
Map<String, Map<String, AsinDetailAnalysisFields>> group2TopAsins = new HashMap<String, Map<String, AsinDetailAnalysisFields>>(
topAsinResult.size() * 2);
for (Entry<String, TopAsinsCalculator> entry : topAsinResult.entrySet()) {
TopAsinsCalculator topAsins4Group = entry.getValue();
String groupKey = entry.getKey();
Collection<AsinDetailAnalysisFields> asins = topAsins4Group.getTopAsins();
Map<String, AsinDetailAnalysisFields> value = new HashMap<String, AsinDetailAnalysisFields>(
asins.size() * 2);
group2TopAsins.put(groupKey, value);
for (AsinDetailAnalysisFields asin : asins) {
asin.setDescribers(AsinDescriberFactory.getAllDescribers());
value.put(asin.getAsin(), asin);
}
}
return group2TopAsins;
}
}