package org.solrmarc.mixin;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.marc4j.marc.DataField;
import org.marc4j.marc.Record;
import org.marc4j.marc.Subfield;
import org.marc4j.marc.VariableField;
import org.solrmarc.index.SolrIndexerMixin;
import org.solrmarc.index.indexer.ValueIndexerFactory;
import org.solrmarc.index.mapping.AbstractMultiValueMapping;
public class SummaryHoldingsMixin extends SolrIndexerMixin
{
// process summary holdings info
public Set<String> getSummaryHoldingsInfo(Record record, String libraryMapName, String locationMapName) throws Exception
{
Set<String> result = new LinkedHashSet<String>();
Set<String> ivyresult = new LinkedHashSet<String>();
String fieldsToUseStr = "852|853|863|866|867";
String fieldsToUse[] = fieldsToUseStr.split("[|]");
AbstractMultiValueMapping libraryMap = ValueIndexerFactory.instance().createMultiValueMapping(libraryMapName);
AbstractMultiValueMapping locationMap = ValueIndexerFactory.instance().createMultiValueMapping(locationMapName);
List<VariableField> fields = record.getVariableFields();
DataField libraryField = null;
for (int i = 0; i < fields.size(); i++)
{
String holdingsField;
VariableField vf = fields.get(i);
if (!(vf instanceof DataField)) continue;
DataField df = (DataField)vf;
if (!df.getTag().startsWith("8")) continue;
if (df.getTag().equals("852"))
{
libraryField = df;
if (getSubfieldVal(libraryField, "hiz", null) != null)
{
holdingsField = buildHoldingsField(libraryField, libraryMap, locationMap, "", getSubfieldVal(libraryField, 'z', ""), "", getSubfieldVal(libraryField, "hi", ""));
addHoldingsField(result, ivyresult, holdingsField);
}
}
else if (df.getTag().equals("853")) continue; // ignore 853's here.
else if (df.getTag().equals("866"))
{
holdingsField = buildHoldingsField(libraryField, libraryMap, locationMap, getSubfieldVal(df, 'a', ""), getSubfieldVal(df, 'z', ""), "Library has", null);
addHoldingsField(result, ivyresult, holdingsField);
}
else if (df.getTag().equals("867"))
{
holdingsField = buildHoldingsField(libraryField, libraryMap, locationMap, getSubfieldVal(df, "z+a", ""), getSubfieldVal(df, "-z", ""), "Suppl text holdings", null);
addHoldingsField(result, ivyresult, holdingsField);
}
else if (df.getTag().equals("868"))
{
holdingsField = buildHoldingsField(libraryField, libraryMap, locationMap, getSubfieldVal(df, 'a', ""), getSubfieldVal(df, 'z', ""), "Index text holdings", null);
addHoldingsField(result, ivyresult, holdingsField);
}
else if (df.getTag().equals("863"))
{
// look ahead for other 863's to combine
String linktag = df.getSubfield('8') != null ? df.getSubfield('8').getData() : null;
int j = i+1;
for (; j < fields.size(); j++)
{
VariableField nvf = fields.get(j);
if (!(nvf instanceof DataField)) break;
DataField ndf = (DataField)nvf;
String nlinktag = ndf.getSubfield('8') != null ? ndf.getSubfield('8').getData() : null;
if (linktag == null || nlinktag == null || !getLinkPrefix(linktag).equals(getLinkPrefix(nlinktag)))
break;
}
DataField labelField = null;
if (linktag != null) labelField = getLabelField(record, getLinkPrefix(linktag));
if (labelField != null && j == i + 1)
{
holdingsField = buildHoldingsField(libraryField, libraryMap, locationMap, processEncodedField(df, labelField), getSubfieldVal(df, 'z', ""), "Library has", null);
addHoldingsField(result, ivyresult, holdingsField);
}
else if (labelField != null && j > i + 1)
{
VariableField nvf = fields.get(j-1);
DataField ndf = (DataField)nvf;
holdingsField = buildHoldingsField(libraryField, libraryMap, locationMap, processEncodedFieldRange(df, ndf, labelField), getSubfieldVal(df, 'z', ""), "Library has", null);
addHoldingsField(result, ivyresult, holdingsField);
i = j - 1;
}
}
}
if (ivyresult.size() != 0)
{
for (String ivy : ivyresult)
{
result.add(ivy);
}
}
return(result);
}
private void addHoldingsField(Set<String> result, Set<String> ivyresult, String holdingsField)
{
if (holdingsField != null)
{
if (holdingsField.startsWith("Ivy"))
ivyresult.add(holdingsField);
else
result.add(holdingsField);
}
}
private String getSubfieldVal(DataField df, String subfieldTags, String defValue)
{
List<Subfield> subfields = (List<Subfield>)df.getSubfields();
if (subfields.size() == 0) return(defValue);
String result = "";
boolean found_a = false;
boolean getBefore_a = subfieldTags.contains("+");
boolean getAfter_a = subfieldTags.contains("-");
// boolean addlineBreak = subfieldTags.contains("/");
for (Subfield sf : subfields)
{
if (!subfieldTags.contains("a") && ! getBefore_a && ! getAfter_a && subfieldTags.contains(""+sf.getCode()))
{
String spacer = ((result.length() > 0) ? " " : "");
// if (addlineBreak && sf.getCode() == 'z') spacer = "<br>";
result = result + ((result.length() > 0) ? spacer : "") + sf.getData();
}
else if (sf.getCode() == 'a')
{
if (subfieldTags.contains(""+sf.getCode()))
{
result = result + ((result.length() > 0) ? " " : "") + sf.getData();
}
found_a = true;
}
else if (getBefore_a && !found_a && sf.getCode() != 'a' && subfieldTags.contains(""+sf.getCode()) )
{
result = result + ((result.length() > 0) ? " " : "") + sf.getData();
}
else if (!getBefore_a && found_a && sf.getCode() != 'a' && subfieldTags.contains(""+sf.getCode()) )
{
result = result + ((result.length() > 0) ? " " : "") + sf.getData();
}
}
return result;
}
private String getSubfieldVal(DataField df, char subfieldTag, String defValue)
{
List<Subfield> subfields = (List<Subfield>)df.getSubfields(subfieldTag);
if (subfields.size() == 0) return(defValue);
String result = "";
for (Subfield sf : subfields)
{
result = result + sf.getData();
}
return result;
}
private String buildHoldingsField(DataField libraryField, AbstractMultiValueMapping libraryMap, AbstractMultiValueMapping locationMap, String holdingsValue, String publicNote, String holdingsType, String callNumber) throws Exception
{
if (libraryField == null || ((holdingsValue == null || holdingsValue.length() == 0) && (publicNote.length() == 0 && (callNumber == null || callNumber.length() == 0)))) return(null);
String libraryName = libraryField.getSubfield('b') != null ? libraryMap.mapSingle(libraryField.getSubfield('b').getData()) : null;
String locName = libraryField.getSubfield('c') != null ? locationMap.mapSingle(libraryField.getSubfield('c').getData()) : null;
if (libraryName == null) libraryName = "";
if (locName == null) locName = "";
if (callNumber == null) callNumber = "";
return(libraryName +"|"+ locName +"|"+ holdingsValue+"|"+publicNote+"|"+holdingsType+"|"+callNumber);
}
private String processEncodedField(DataField df, DataField labelField)
{
boolean normalize_date = false;
if (labelField == null) return(null);
StringBuffer result = new StringBuffer();
for (char subfield = 'a'; subfield <= 'f'; subfield++)
{
String label = getSubfieldVal(labelField, subfield, null);
String data = getSubfieldVal(df, subfield, null);
if (label == null || data == null) break;
if (subfield != 'a') result.append(", ");
if (label.startsWith("(") && label.endsWith(")")) label = "";
result.append(label);
result.append(data);
}
StringBuffer alt = new StringBuffer();
for (char subfield = 'g'; subfield <= 'h'; subfield++)
{
String label = getSubfieldVal(labelField, subfield, null);
String data = getSubfieldVal(df, subfield, null);
if (label == null || data == null) break;
if (subfield != 'g') alt.append(", ");
alt.append(label);
alt.append(data);
}
if (alt.length() != 0)
{
result.append(" (").append(alt).append(")");
}
String year = null;
StringBuffer date = new StringBuffer();
if (normalize_date)
{
for (char subfield = 'i'; subfield <= 'm'; subfield++)
{
boolean appendComma = false;
String label = getSubfieldVal(labelField, subfield, null);
String data = getSubfieldVal(df, subfield, null);
if (label == null || data == null) break;
// if (subfield != 'i') result.append(", ");
if (label.equalsIgnoreCase("(month)") || label.equalsIgnoreCase("(season)"))
{
data = expandMonthOrSeason(data);
}
else if (year != null && !label.equalsIgnoreCase("(day)"))
{
date.append(year);
year = null;
}
else
{
appendComma = true;
}
if (label.equalsIgnoreCase("(year)"))
{
year = data;
}
else if (label.equalsIgnoreCase("(day)"))
{
date.append(" ").append(data);
if (appendComma) date.append(", ");
}
else
{
date.append(data);
if (appendComma) date.append(", ");
}
}
if (year != null) date.append(year);
}
else
{
boolean prependStr = false;
String strToPrepend = "";
for (char subfield = 'i'; subfield <= 'm'; subfield++)
{
String label = getSubfieldVal(labelField, subfield, null);
String data = getSubfieldVal(df, subfield, null);
if (label == null || data == null) break;
if (label.equalsIgnoreCase("(month)") || label.equalsIgnoreCase("(season)"))
{
data = expandMonthOrSeason(data);
strToPrepend = ":";
}
else if (label.equalsIgnoreCase("(day)"))
{
data = expandMonthOrSeason(data);
strToPrepend = " ";
}
if (prependStr)
{
date.append(strToPrepend).append(data);
}
else
{
date.append(data);
}
prependStr = true;
}
}
if (date.length() > 0)
{
if (result.length() > 0) result.append(" (").append(date).append(")");
else result.append(date);
}
return result.toString();
}
private String processEncodedFieldRange(DataField df1, DataField df2, DataField labelField)
{
boolean normalize_date = false;
if (labelField == null) return(null);
StringBuffer result = new StringBuffer();
StringBuffer vol1 = new StringBuffer();
StringBuffer vol2 = new StringBuffer();
for (char subfield = 'a'; subfield <= 'f'; subfield++)
{
String label = getSubfieldVal(labelField, subfield, null);
String data1 = getSubfieldVal(df1, subfield, null);
String data2 = getSubfieldVal(df2, subfield, null);
if (label == null || data1 == null || data2 == null) break;
if (subfield != 'a')
{
vol1.append(", ");
vol2.append(", ");
}
if (label.startsWith("(") && label.endsWith(")")) label = "";
vol1.append(label);
vol1.append(data1);
vol2.append(label);
vol2.append(data2);
}
result.append(rangify(vol1.toString(), vol2.toString()));
StringBuffer alt = new StringBuffer();
for (char subfield = 'g'; subfield <= 'h'; subfield++)
{
String label = getSubfieldVal(labelField, subfield, null);
String data1 = getSubfieldVal(df1, subfield, null);
String data2 = getSubfieldVal(df2, subfield, null);
if (label == null || data1 == null || data2 == null) break;
if (subfield != 'g') alt.append(", ");
alt.append(label);
alt.append(rangify(data1, data2));
}
if (alt.length() != 0)
{
result.append(" (").append(alt).append(")");
}
StringBuffer date1 = new StringBuffer();
StringBuffer date2 = new StringBuffer();
{
boolean prependStr = false;
String strToPrepend = "";
for (char subfield = 'i'; subfield <= 'm'; subfield++)
{
String label = getSubfieldVal(labelField, subfield, null);
String data1 = getSubfieldVal(df1, subfield, null);
String data2 = getSubfieldVal(df2, subfield, null);
if (label == null || data1 == null || data2 == null) break;
if (label.equalsIgnoreCase("(month)") || label.equalsIgnoreCase("(season)"))
{
data1 = expandMonthOrSeason(data1);
data2 = expandMonthOrSeason(data2);
strToPrepend = ":";
}
else if (label.equalsIgnoreCase("(day)"))
{
strToPrepend = " ";
}
if (prependStr)
{
date1.append(strToPrepend).append(data1);
date2.append(strToPrepend).append(data2);
}
else
{
date1.append(data1);
date2.append(data2);
}
prependStr = true;
}
}
if (date1.length() > 0 && date2.length() > 0)
{
if (result.length() > 0) result.append(" (").append(rangify(date1.toString(), date2.toString())).append(")");
else result.append(rangify(date1.toString(), date2.toString()));
}
return result.toString();
}
private Object rangify(String data1, String data2)
{
int i;
if (data1.equals(data2)) return(data1);
for (i = 0; i < data1.length() && i < data2.length(); i++)
{
if (data1.charAt(i) != data2.charAt(i)) break;
}
int preBackstep = i;
if ( i < data1.length() && i < data2.length() && Character.isDigit(data1.charAt(i)) && Character.isDigit(data2.charAt(i)))
{
while (Character.isDigit(data1.charAt(i)) && Character.isDigit(data2.charAt(i)) &&
i > 0 && Character.isDigit(data1.charAt(i-1)) && Character.isDigit(data2.charAt(i-1)))
{
i--;
}
}
else if ( i < data1.length() && i < data2.length() && Character.isLetter(data1.charAt(i)) && Character.isLetter(data2.charAt(i)))
{
while (Character.isLetter(data1.charAt(i)) && Character.isLetter(data2.charAt(i)) &&
i > 0 && Character.isLetter(data1.charAt(i-1)) && Character.isLetter(data2.charAt(i-1)))
{
i--;
}
}
String result;
if (i <= 3 && data1.length() > 6 && data2.length() > 6 && preBackstep < 6)
result = data1 + "-" + data2;
else if ( i < data1.length() && i < data2.length())
result = data1.substring(0, i) + data1.substring(i) + "-" + data2.substring(i);
else
result = data1;
return result;
}
private String expandMonthOrSeason(String data)
{
data = data.replaceAll("01", "Jan");
data = data.replaceAll("02", "Feb");
data = data.replaceAll("03", "Mar");
data = data.replaceAll("04", "Apr");
data = data.replaceAll("05", "May");
data = data.replaceAll("06", "Jun");
data = data.replaceAll("07", "Jul");
data = data.replaceAll("08", "Aug");
data = data.replaceAll("09", "Sept");
data = data.replaceAll("10", "Oct");
data = data.replaceAll("11", "Nov");
data = data.replaceAll("12", "Dec");
data = data.replaceAll("21", "Spring");
data = data.replaceAll("22", "Summer");
data = data.replaceAll("23", "Autumn");
data = data.replaceAll("24", "Winter");
return(data);
}
private DataField getLabelField(Record record, String linkPrefix)
{
if (linkPrefix == null) return(null);
List<VariableField> fields = (List<VariableField>)record.getVariableFields("853");
for (VariableField vf : fields)
{
if (!(vf instanceof DataField)) continue;
DataField df = (DataField)vf;
String link = df.getSubfield('8') != null ? df.getSubfield('8').getData() : null;
if (link != null && link.equals(linkPrefix))
{
return(df);
}
}
return(null);
}
private String getLinkPrefix(String linktag)
{
String prefix = null;
int index;
if ((index = linktag.indexOf('.')) == -1)
prefix = linktag;
else
prefix = linktag.substring(0, index);
return(prefix);
}
}