package eu.dnetlib.iis.common.model.extrainfo.citations; import java.text.DecimalFormatSymbols; import java.util.List; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.thoughtworks.xstream.annotations.XStreamAlias; import com.thoughtworks.xstream.annotations.XStreamAsAttribute; import com.thoughtworks.xstream.annotations.XStreamImplicit; import com.thoughtworks.xstream.annotations.XStreamOmitField; /** * Comparable citation entry. * @author mhorst * */ @XStreamAlias("citation") public class BlobCitationEntry implements Comparable<BlobCitationEntry> { /** * Citation position. */ @XStreamAsAttribute private int position; /** * Raw citation text. */ private String rawText; /** * Matched publications identifiers. */ @XStreamImplicit private List<TypedId> identifiers; @XStreamOmitField private final static Pattern alphaNumChunkPattern = Pattern.compile("(\\d+\\" + new DecimalFormatSymbols(Locale.getDefault()).getDecimalSeparator() + "\\d+)|(\\d+)|(\\D+)");; public BlobCitationEntry() { super(); } public BlobCitationEntry(String rawText) { this.rawText = rawText; } public String getRawText() { return rawText; } public void setRawText(String rawText) { this.rawText = rawText; } public List<TypedId> getIdentifiers() { return identifiers; } public void setIdentifiers(List<TypedId> identifiers) { this.identifiers = identifiers; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((identifiers == null) ? 0 : identifiers.hashCode()); result = prime * result + position; result = prime * result + ((rawText == null) ? 0 : rawText.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; BlobCitationEntry other = (BlobCitationEntry) obj; if (identifiers == null) { if (other.identifiers != null) return false; } else if (!identifiers.equals(other.identifiers)) return false; if (position != other.position) return false; if (rawText == null) { if (other.rawText != null) return false; } else if (!rawText.equals(other.rawText)) return false; return true; } @Override public int compareTo(BlobCitationEntry c2) { if (c2 != null) { if (this.position > c2.position) { return 1; } else if (this.position < c2.position) { return -1; } else { return compareProperties(c2); } } else { if (this.getRawText() != null) { return -1; } else { if (this.getIdentifiers() != null) { return -1; } else { // should we check position in any way? return 0; } } } } private int compareProperties(BlobCitationEntry c2) { if (this.getRawText() != null) { if (c2.getRawText() != null) { int textCompareResult = compareText(this.getRawText(), c2.getRawText()); if (textCompareResult == 0) { return compareIdentifiers(this.getIdentifiers(), c2.getIdentifiers()); } else { return textCompareResult; } } else { return -1; } } else { if (c2.getRawText() != null) { return 1; } else { return compareIdentifiers(this.getIdentifiers(), c2.getIdentifiers()); } } } private int compareIdentifiers(List<TypedId> ids1, List<TypedId> ids2) { if (ids2!=null) { if (ids1!=null) { if (ids1.equals(ids2)) { return 0; } else { // no matter what value, order by ids is irrelevant // we have to return non-zero value to prevent treating objects as the same return 1; } } else { return -1; } } else { if (ids1!=null) { return 1; } else { return 0; } } } private int compareText(String s1, String s2) { int compareValue = 0; Matcher s1ChunkMatcher = alphaNumChunkPattern.matcher(s1); Matcher s2ChunkMatcher = alphaNumChunkPattern.matcher(s2); String s1ChunkValue = null; String s2ChunkValue = null; while (s1ChunkMatcher.find() && s2ChunkMatcher.find() && compareValue == 0) { s1ChunkValue = s1ChunkMatcher.group(); s2ChunkValue = s2ChunkMatcher.group(); try { // compare double values - ints get converted to doubles. Eg. 100 = 100.0 Double s1Double = Double.valueOf(s1ChunkValue); Double s2Double = Double.valueOf(s2ChunkValue); compareValue = s1Double.compareTo(s2Double); } catch (NumberFormatException e) { // not a number, use string comparison. compareValue = s1ChunkValue.compareTo(s2ChunkValue); } // if they are equal thus far, but one has more left, it should come after the one that doesn't. if (compareValue == 0) { if (s1ChunkMatcher.hitEnd() && !s2ChunkMatcher.hitEnd()) { compareValue = -1; } else if (!s1ChunkMatcher.hitEnd() && s2ChunkMatcher.hitEnd()) { compareValue = 1; } } } return compareValue; } /** * @return the position */ public int getPosition() { return position; } /** * @param position the position to set */ public void setPosition(int position) { this.position = position; } }