package org.juxtasoftware.resource.heatmap; import java.util.Iterator; import java.util.List; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import eu.interedition.text.Range; /** * Inject heat intensity markup into the witness stream * * @author loufoster * */ @Component @Scope(BeanDefinition.SCOPE_PROTOTYPE) public class ChangeInjector implements StreamInjector<Change> { private List<Change> changes; private Iterator<Change> changeItr; private Change currChange = null; private boolean tagStarted = false; private int witnessCount; public void setWitnessCount( int size ) { this.witnessCount = size; } @Override public void initialize(List<Change> data) { this.changes = data; this.changeItr = this.changes.iterator(); if ( this.changeItr.hasNext() ) { this.currChange = this.changeItr.next(); } } @Override public List<Change> getData() { return this.changes; } @Override public boolean hasContent(long pos) { if ( this.currChange == null) { return false; } if ( this.currChange.getRange().getStart() <= pos && this.tagStarted == false || this.currChange.getRange().getEnd() <= pos && this.tagStarted == true ) { return true; } return false; } @Override public void injectContentStart(StringBuilder line, final long currPositon) { if ( this.currChange != null && this.tagStarted == false ) { if ( this.currChange.getRange().getStart() <= currPositon) { line.append( generateChangeHtml( this.currChange, this.witnessCount ) ); this.tagStarted = true; } } } @Override public void injectContentEnd(StringBuilder line, final long currPosition) { if ( this.currChange != null && this.tagStarted == true ) { if ( this.currChange.getRange().getEnd() <= currPosition) { line.append("</span>"); this.tagStarted = false; this.currChange = null; if ( this.changeItr.hasNext() ) { this.currChange = this.changeItr.next(); } } } } /** * Create a heatmap span for a change. The color intensity is based * upon the frequency of the change. * @param change * @param numWitnesses * @return */ private String generateChangeHtml(Change change, int numWitnesses ) { final int diffHighlightLen = 9; float value = ((float) change.getDifferenceFrequency() / (float)numWitnesses) * diffHighlightLen; int idx = (int) Math.round(value); idx = Math.max(0, idx); idx = Math.min(idx, diffHighlightLen); StringBuffer sb = new StringBuffer(); sb.append("<span juxta:range=\""); Range range = change.getRange(); if ( change.wasRangeAdjusted() ) { range = change.getOrignialRange(); } sb.append(range.getStart()).append(",").append(range.getEnd()).append("\""); sb.append(" juxta:diff-freq=\"").append(change.getDifferenceFrequency()).append("\""); sb.append(" class=\"heatmap heat").append(idx).append("\" id=\"").append(change.getId()).append("\">"); return sb.toString(); } }