package org.solrmarc.index.specification;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumSet;
import java.util.List;
import org.marc4j.marc.Record;
import org.marc4j.marc.VariableField;
import org.solrmarc.index.extractor.formatter.FieldFormatter;
import org.solrmarc.index.extractor.formatter.FieldFormatter.eCleanVal;
import org.solrmarc.index.extractor.formatter.FieldFormatter.eJoinVal;
import org.solrmarc.index.extractor.impl.direct.FieldMatch;
import org.solrmarc.index.mapping.AbstractMultiValueMapping;
import org.solrmarc.index.specification.conditional.Condition;
public class CompositeSpecification extends Specification
{
List<SingleSpecification> pieces = null;
List<String> tagsUsed = null;
String tags[] = null;
boolean duplicateTags = false;
public CompositeSpecification()
{
}
public CompositeSpecification(Specification spec)
{
addSpec(spec);
}
private CompositeSpecification(CompositeSpecification toClone)
{
this.pieces = new ArrayList<SingleSpecification>(toClone.pieces.size());
for (SingleSpecification spec : toClone.pieces)
{
this.pieces.add((SingleSpecification)((spec.isThreadSafe()) ? spec : spec.makeThreadSafeCopy()));
}
this.tagsUsed = toClone.tagsUsed;
this.tags = toClone.tags;
this.duplicateTags = toClone.duplicateTags;
}
@Override
public boolean hasDuplicateTags()
{
return duplicateTags;
}
public void addSpec(Specification spec)
{
if (pieces == null) pieces = new ArrayList<SingleSpecification>();
if (tagsUsed == null) tagsUsed = new ArrayList<String>();
if (spec instanceof SingleSpecification)
{
if (tagsUsed.contains(((SingleSpecification) spec).tags[0]))
{
duplicateTags = true;
}
else
{
tagsUsed.add(((SingleSpecification) spec).tags[0]);
}
pieces.add((SingleSpecification) spec);
}
else
{
for (String t : ((CompositeSpecification) spec).tagsUsed)
{
if (tagsUsed.contains(t))
{
duplicateTags = true;
}
else
{
tagsUsed.add(t);
}
}
pieces.addAll(((CompositeSpecification) spec).pieces);
}
}
public void addConditional(Condition cond)
{
for (Specification spec : pieces)
{
spec.addConditional(cond);
}
}
@Override
public List<FieldMatch> getFieldMatches(Record record)
{
List<FieldMatch> result = null;
if (!hasDuplicateTags())
{
return (super.getFieldMatches(record));
}
else
{
result = new ArrayList<FieldMatch>();
List<VariableField> fields = record.getVariableFields(getTags());
for (SingleSpecification spec : pieces)
{
for (VariableField vf : fields)
{
if (spec.specMatches(vf.getTag(), vf) && (spec.cond == null || spec.cond.matches(record, vf)))
{
result.add(new FieldMatch(vf, spec));
}
}
}
return (result);
}
}
public String[] getTags()
{
if (tags == null) tags = tagsUsed.toArray(new String[tagsUsed.size()]);
return (tags);
}
@Override
protected SingleSpecification getMatchingSpec(String tag, VariableField f)
{
for (SingleSpecification spec : pieces)
{
SingleSpecification thatMatches = spec.getMatchingSpec(tag, f);
if (thatMatches != null) return (thatMatches);
}
return null;
}
@Override
public void addFieldValues(Collection<String> result, VariableField vf) throws Exception
{
for (SingleSpecification spec : pieces)
{
spec.addFieldValues(result, vf);
}
}
// @Override
// public void addFormatter(FieldFormatterDecorator fmt)
// {
// for (SingleSpecification spec : pieces)
// {
// spec.addFormatter((FieldFormatterDecorator)fmt.makeThreadSafeCopy());
// }
// }
//
@Override
public void addMap(AbstractMultiValueMapping valueMapping)
{
for (SingleSpecification spec : pieces)
{
spec.addMap(valueMapping);
}
}
@Override
public void setFormatter(FieldFormatter fmt)
{
for (SingleSpecification spec : pieces)
{
spec.setFormatter(fmt);
}
}
public void addCleanVal(eCleanVal cleanVal)
{
for (SingleSpecification spec : pieces)
{
spec.addCleanVal(cleanVal);
}
}
public void setCleanVal(EnumSet<eCleanVal> of)
{
for (SingleSpecification spec : pieces)
{
spec.setCleanVal(of);
}
}
public void setJoinVal(eJoinVal joinVal)
{
for (SingleSpecification spec : pieces)
{
spec.setJoinVal(joinVal);
}
}
public void setSubstring(int offset, int endOffset)
{
for (SingleSpecification spec : pieces)
{
spec.setSubstring(offset, endOffset);
}
}
public void setSeparator(String separator)
{
for (SingleSpecification spec : pieces)
{
spec.setSeparator(separator);
}
}
public void setFormatPatterns(final String[] mapParts)
{
for (SingleSpecification spec : pieces)
{
spec.setFormatPatterns( mapParts);
}
}
@Override
public boolean isThreadSafe()
{
for (SingleSpecification spec : pieces)
{
if (!spec.isThreadSafe()) return(false);
}
return(true);
}
@Override
public Object makeThreadSafeCopy()
{
return new CompositeSpecification(this);
}
}