/* * Copyright (C) 2012 Jan Pokorsky * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package cz.cas.lib.proarc.common.mods.custom; import cz.cas.lib.proarc.common.mods.custom.ArrayMapper.ArrayItem; import cz.cas.lib.proarc.common.mods.custom.ArrayMapper.ItemMapper; import cz.cas.lib.proarc.mods.Extent; import cz.cas.lib.proarc.mods.ModsDefinition; import cz.cas.lib.proarc.mods.ObjectFactory; import cz.cas.lib.proarc.mods.PhysicalDescriptionDefinition; import cz.cas.lib.proarc.mods.PhysicalDescriptionNote; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.Optional; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; /** * pairs of {@code mods/physicalDescription/extenet}s. * <p/><b>NOTE: KNAV Kramerius 3 format</b> * @see <a href='https://github.com/ceskaexpedice/kramerius/blob/master/import-cmdtool/src/main/resources/model_periodical_MODS.xsl'>model_periodical_MODS.xsl</a> * * @author Jan Pokorsky */ final class PhysicalDescriptionMapper { private static final String PRESERVATION_STATE_OF_ART = "preservationStateOfArt"; private static final String PRESERVATION_TREATMENT = "action"; private static final String NO_PRESERVATION = new String(); private final ArrayMapper<Object, ArrayItem> arrayMapper = new ArrayMapper<>(new PhysicalDescriptionItemMapper()); public List<ArrayItem> map(ModsDefinition mods) { Optional<PhysicalDescriptionDefinition> pd = mods.getPhysicalDescription().stream().findFirst(); if (!pd.isPresent()) { return new ArrayList<>(); } ArrayList<Object> items = new ArrayList<>(); items.addAll(pd.get().getExtent()); items.addAll(pd.get().getNote()); return arrayMapper.map(items); } public ModsDefinition mapPairs(ModsDefinition mods, List<ExtentPair> pairs) { return map(mods, pairs, NO_PRESERVATION, NO_PRESERVATION); } public ModsDefinition map(ModsDefinition mods, List<ExtentPair> pairs, String preservationTreatment, String preservationStateOfArt) { pairs = MapperUtils.noNull(pairs); List<ArrayItem> oldies = map(mods); List<ExtentItem> toExtents = toExtents(pairs); List<ArrayItem> news; if (NO_PRESERVATION.equals(preservationTreatment)) { List<ArrayItem> unknowns = filter(oldies, false, ExtentItem.class); news = MapperUtils.mergeList(toExtents, unknowns); } else { List<ArrayItem> unknowns = filter(oldies, false, ExtentItem.class, NoteItem.class); List<NoteItem> notes = MapperUtils.find(oldies, NoteItem.class); updateTreatmentItem(oldies, notes, preservationTreatment, PRESERVATION_TREATMENT); updateTreatmentItem(oldies, notes, preservationStateOfArt, PRESERVATION_STATE_OF_ART); news = MapperUtils.mergeList(toExtents, notes, unknowns); } return map(mods, news); } private void updateTreatmentItem(List<ArrayItem> oldies, List<NoteItem> notes, String treatment, String type) { if (treatment != null) { NoteItem ni = getPreservationItem(oldies, type); if (ni == null) { ni = new NoteItem(null, treatment, type); notes.add(ni); } ni.setValue(treatment); ni.ignore = false; } else { NoteItem ni = getPreservationItem(oldies, type); if (ni != null) { ni.setValue(treatment); } } } public ModsDefinition map(ModsDefinition mods, List<ArrayItem> items) { PhysicalDescriptionDefinition pd = mods.getPhysicalDescription().stream().findFirst().orElse(null); if (pd == null) { if (items.isEmpty()) { return mods; } else { pd = new PhysicalDescriptionDefinition(); mods.getPhysicalDescription().add(pd); } } ArrayList<Object> oldies = new ArrayList<>(); final List<Extent> extents = pd.getExtent(); final List<PhysicalDescriptionNote> notes = pd.getNote(); oldies.addAll(extents); oldies.addAll(notes); List<Object> updates = arrayMapper.map(items, oldies); extents.clear(); notes.clear(); updates.forEach(update -> { if (update instanceof Extent) { extents.add((Extent) update); } else if (update instanceof PhysicalDescriptionNote) { notes.add((PhysicalDescriptionNote) update); } else { throw new IllegalStateException(update.getClass().getName()); } }); return mods; } public static List<ExtentPair> toPairs(List<ArrayItem> items) { ArrayList<ExtentPair> pairs = new ArrayList<>(); List<ExtentItem> extents = MapperUtils.find(items, ExtentItem.class); for (Iterator<ExtentItem> it = extents.iterator(); it.hasNext();) { ExtentItem item = it.next(); ExtentPair pair = new ExtentPair(item.getValue(), item.getArrayIndex(), null, null); pairs.add(pair); if (it.hasNext()) { item = it.next(); pair.setSize(item.getValue()); pair.setSizeIndex(item.getArrayIndex()); } } return pairs; } public static List<ExtentItem> toExtents(List<ExtentPair> pairs) { ArrayList<ExtentItem> items = new ArrayList<>(pairs.size() * 2); for (ExtentPair pair : pairs) { items.add(new ExtentItem(pair.getExtentIndex(), pair.getExtent())); items.add(new ExtentItem(pair.getSizeIndex(), pair.getSize())); } return items; } public static String getPreservationTreatment(List<ArrayItem> items) { NoteItem ni = getPreservationItem(items, PRESERVATION_TREATMENT); return ni != null ? ni.getValue() : null; } public static String getPreservationStateOfArt(List<ArrayItem> items) { NoteItem ni = getPreservationItem(items, PRESERVATION_STATE_OF_ART); return ni != null ? ni.getValue() : null; } private static NoteItem getPreservationItem(List<ArrayItem> items, String type) { for (ArrayItem item : items) { if (item instanceof NoteItem && type.equals(((NoteItem) item).getType())) { return (NoteItem) item; } } return null; } @XmlAccessorType(XmlAccessType.FIELD) public static class ExtentPair { @XmlElement(name = ModsConstants.FIELD_PHYSICAL_DESCRIPTIONS_EXTENT) private String extent; private Integer extentIndex; @XmlElement(name = ModsConstants.FIELD_PHYSICAL_DESCRIPTIONS_SIZE) private String size; private Integer sizeIndex; public ExtentPair() { } public ExtentPair(String extent, Integer extentIndex, String size, Integer sizeIndex) { this.extent = extent; this.extentIndex = extentIndex; this.size = size; this.sizeIndex = sizeIndex; } public String getExtent() { return extent; } public void setExtent(String extent) { this.extent = extent; } public Integer getExtentIndex() { return extentIndex; } public void setExtentIndex(Integer extentIndex) { this.extentIndex = extentIndex; } public String getSize() { return size; } public void setSize(String size) { this.size = size; } public Integer getSizeIndex() { return sizeIndex; } public void setSizeIndex(Integer sizeIndex) { this.sizeIndex = sizeIndex; } @Override public String toString() { return String.format("ExtentPair{extent: %s, extentIndex: %s, size: %s, sizeIndex: %s}", extent, extentIndex, size, sizeIndex); } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final ExtentPair other = (ExtentPair) obj; if ((this.extent == null) ? (other.extent != null) : !this.extent.equals(other.extent)) { return false; } if (this.extentIndex != other.extentIndex && (this.extentIndex == null || !this.extentIndex.equals(other.extentIndex))) { return false; } if ((this.size == null) ? (other.size != null) : !this.size.equals(other.size)) { return false; } if (this.sizeIndex != other.sizeIndex && (this.sizeIndex == null || !this.sizeIndex.equals(other.sizeIndex))) { return false; } return true; } } public static <T extends ArrayItem> List<T> filter(List<T> list, boolean include, Class<? extends ArrayItem>... types) { ArrayList<T> result = new ArrayList<>(); for (T t : list) { boolean equals = false; for (Class<? extends ArrayItem> type : types) { equals = type == t.getClass(); if (equals) { break; } } if (include == true && include == equals || include == false && include == equals) { result.add(t); } } return result; } private static final class PhysicalDescriptionItemMapper implements ItemMapper<Object, ArrayItem> { private final ObjectFactory factory = new ObjectFactory(); @Override public ArrayItem map(Object source) { if (source instanceof Extent) { ExtentItem result = new ExtentItem(); result.setValue(((Extent) source).getValue()); return result; } else if (source instanceof PhysicalDescriptionNote) { PhysicalDescriptionNote note = (PhysicalDescriptionNote) source; return new NoteItem(null, note.getValue(), note.getType()); } else { return new UnkownItem(); } } @Override public Object map(ArrayItem item, Object origin) { Object source = origin; if (origin == null) { if (item instanceof ExtentItem) { source = factory.createExtent(); } else if (item instanceof NoteItem) { NoteItem noteItem = (NoteItem) item; PhysicalDescriptionNote note = factory.createPhysicalDescriptionNote(); note.setType(noteItem.getType()); source = note; } else { throw new IllegalStateException("unsupported array item: " + item.getClass()); } } if (item instanceof ExtentItem) { ExtentItem extentItem = (ExtentItem) item; Extent extentSource = (Extent) source; // delete with empty string to prevent XML nil extentSource.setValue(extentItem.getValue() != null ? extentItem.getValue() : ""); } else if (item instanceof NoteItem && !((NoteItem) item).ignore) { NoteItem noteItem = (NoteItem) item; PhysicalDescriptionNote noteType = (PhysicalDescriptionNote) source; noteType.setValue(noteItem.getValue()); } return source; } } static final class UnkownItem implements ArrayItem { private Integer index; public UnkownItem() { } public UnkownItem(Integer index) { this.index = index; } @Override public Integer getArrayIndex() { return index; } @Override public void setArrayIndex(Integer index) { this.index = index; } @Override public String toString() { return String.format("UnkownItem{%s}", index); } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final UnkownItem other = (UnkownItem) obj; return Objects.equals(this.index, other.index); } } public static class ExtentItem implements ArrayItem { private Integer index; private String value; public ExtentItem() { } public ExtentItem(Integer index, String value) { this.index = index; this.value = value; } public String getValue() { return value; } public void setValue(String value) { this.value = MapperUtils.normalize(value); } @Override public Integer getArrayIndex() { return index; } @Override public void setArrayIndex(Integer index) { this.index = index; } @Override public String toString() { return String.format("ExtentItem{index: %s, value: %s}", index, value); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final ExtentItem other = (ExtentItem) obj; return Objects.equals(this.value, other.value) && Objects.equals(this.index, other.index); } } public static class NoteItem implements ArrayItem { private Integer index; private String value; private String type; private boolean ignore = true; public NoteItem() { } public NoteItem(Integer index, String value, String type) { this.index = index; this.value = value; this.type = type; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } @Override public Integer getArrayIndex() { return index; } @Override public void setArrayIndex(Integer index) { this.index = index; } @Override public String toString() { return "NoteItem{" + "index=" + index + ", value=" + value + ", type=" + type + ", ignore=" + ignore + '}'; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final NoteItem other = (NoteItem) obj; return Objects.equals(this.value, other.value) && Objects.equals(this.type, other.type) && Objects.equals(this.index, other.index); } } }