/*
* CATMA Computer Aided Text Markup and Analysis
*
* Copyright (C) 2009-2013 University Of Hamburg
*
* 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 de.catma.document.standoffmarkup.usermarkup;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import de.catma.document.AccessMode;
import de.catma.document.repository.Repository;
import de.catma.document.source.ContentInfoSet;
import de.catma.tag.Property;
import de.catma.tag.TagInstance;
import de.catma.tag.TagManager;
import de.catma.tag.TagsetDefinition;
import de.catma.util.Pair;
/**
* A manager that handles a list of {@link UserMarkupCollection}s. Handles all
* kinds of operations upon a {@link UserMarkupCollection} and its content.
*
* @author marco.petris@web.de
*
*/
public class UserMarkupCollectionManager implements Iterable<UserMarkupCollection>{
private Logger logger = Logger.getLogger(this.getClass().getName());
private TagManager tagManager;
private Repository repository;
private List<UserMarkupCollection> userMarkupCollections;
/**
* @param repository the underlying repository (addition and removal of content
* of a UserMarkupCollection is passed through up to the repository
*/
public UserMarkupCollectionManager(Repository repository) {
this.tagManager = repository.getTagManager();
this.repository = repository;
userMarkupCollections = new ArrayList<UserMarkupCollection>();
}
/**
* Updates given UserMarkupCollections
* with the TagsetDefinition. That is all the {@link de.catma.tag.TagLibrary TagLibraries}
* and all the {@link TagInstance}s are updated with the new TagsetDefinition.
* The actual persistent modifications are made through {@link Repository#update(List, TagsetDefinition)}.
* @param outOfSynchCollections
* @param tagsetDefinition
*/
public void updateUserMarkupCollections(
List<UserMarkupCollection> outOfSynchCollections,
TagsetDefinition tagsetDefinition) {
for (UserMarkupCollection userMarkupCollection : outOfSynchCollections) {
logger.info("synching " + userMarkupCollection);
tagManager.synchronize(
userMarkupCollection.getTagLibrary().getTagsetDefinition(
tagsetDefinition.getUuid()),
tagsetDefinition);
userMarkupCollection.synchronizeTagInstances();
}
repository.update(outOfSynchCollections, tagsetDefinition);
}
public void add(UserMarkupCollection userMarkupCollection) {
if (!this.userMarkupCollections.contains(userMarkupCollection)) {
logger.info(
"Adding UMC " + userMarkupCollection + "#"
+ ((userMarkupCollection == null)?"N/A":userMarkupCollection.getId())
+ " to UserMarkupCollectionManager " + this.hashCode());
this.userMarkupCollections.add(userMarkupCollection);
}
}
@Override
public Iterator<UserMarkupCollection> iterator() {
return userMarkupCollections.iterator();
}
/**
* Updates the UserMarkupCollection. Persistence part is handled by {@link
* Repository#update(UserMarkupCollection, List)}
* @param tagReferences
* @param userMarkupCollection
*/
public void addTagReferences(
List<TagReference> tagReferences,
UserMarkupCollection userMarkupCollection) {
userMarkupCollection.addTagReferences(tagReferences);
repository.update(userMarkupCollection, tagReferences);
}
/**
* @return non modifiable list of the contained UserMarkupCollections
*/
public List<UserMarkupCollection> getUserMarkupCollections() {
return Collections.unmodifiableList(userMarkupCollections);
}
/**
* @param tagsetDefinition
* TagsetDefinition
* @return a list {@link TagsetDefinition#isSynchronized(TagsetDefinition) of out ot synch} UserMarkupCollections
*/
public List<UserMarkupCollection> getOutOfSyncUserMarkupCollections(
TagsetDefinition tagsetDefinition) {
List<UserMarkupCollection> result =
new ArrayList<UserMarkupCollection>();
for (UserMarkupCollection userMarkupCollection : userMarkupCollections) {
// FIXME: regardless of tagsetdef containment, check tagdef containment as well to support old standard tagsets and move operations
// no need to check non writable collections, they won't be updated anyway
if (userMarkupCollection.getAccessMode().equals(AccessMode.WRITE)
&&
userMarkupCollection.getTagLibrary().contains(tagsetDefinition)) {
// if (userMarkupCollection.getTagLibrary().contains(tagsetDefinition)) {
TagsetDefinition containedTagsetDef =
userMarkupCollection.getTagLibrary().getTagsetDefinition(
tagsetDefinition.getUuid());
if (!containedTagsetDef.isSynchronized(tagsetDefinition)) {
result.add(userMarkupCollection);
}
}
}
return result;
}
/**
* Removes the given {@link TagInstance}s from the {@link UserMarkupCollection}s
* that contains them. If there is no such collection in this manager, this is
* noop.
* @param instanceID the TagInstance to be removed
*/
public void removeTagInstance(Collection<String> instanceIDs) {
Map<UserMarkupCollection, List<TagReference>> toBeDeletedByUmc =
new HashMap<UserMarkupCollection, List<TagReference>>();
for (String instanceID : instanceIDs) {
UserMarkupCollection userMarkupCollection =
getUserMarkupCollectionForTagInstance(instanceID);
// the instance may be deleted alred but can still be in a stale Analyzer-Window
// so we silently assume that the instance has been deleted already if the
// umc can not be found
if (userMarkupCollection != null) {
List<TagReference> toBeDeletedRefs = toBeDeletedByUmc.get(userMarkupCollection);
if (toBeDeletedRefs == null) {
toBeDeletedRefs = new ArrayList<TagReference>();
toBeDeletedByUmc.put(userMarkupCollection, toBeDeletedRefs);
}
List<TagReference> tagReferences =
userMarkupCollection.getTagReferences(instanceID);
userMarkupCollection.removeTagReferences(tagReferences);
toBeDeletedRefs.addAll(tagReferences);
}
}
for (Map.Entry<UserMarkupCollection, List<TagReference>> entry : toBeDeletedByUmc.entrySet()) {
if (!entry.getValue().isEmpty()) {
repository.update(entry.getKey(), entry.getValue());
}
}
}
/**
* Removes the given {@link TagInstance} from the {@link UserMarkupCollection}
* that contains it. If there is no such collection in this manager, this is
* noop.
* @param instanceID the TagInstance to be removed
*/
public void removeTagInstance(String instanceID) {
removeTagInstance(Collections.singletonList(instanceID));
}
/**
* @param instanceID
* @return the collections that contains the {@link TagInstance} with the
* given ID or <code>null</code> if there is no such collection in this
* manager
*/
private UserMarkupCollection getUserMarkupCollectionForTagInstance(
String instanceID) {
for (UserMarkupCollection userMarkupCollection : userMarkupCollections) {
if (userMarkupCollection.hasTagInstance(instanceID)) {
return userMarkupCollection;
}
}
return null;
}
/**
* @param userMarkupCollectionReference
* @return the referenced collection or <code>null</code> if there is
* no such collection in this manager
*/
public UserMarkupCollection getUserMarkupCollection(
UserMarkupCollectionReference userMarkupCollectionReference) {
for (UserMarkupCollection umc : userMarkupCollections) {
if (umc.getId().equals(userMarkupCollectionReference.getId())) {
return umc;
}
}
return null;
}
public void remove(UserMarkupCollection userMarkupCollection) {
logger.info(
"Removing UMC " + userMarkupCollection + "#"
+ ((userMarkupCollection == null)?"N/A":userMarkupCollection.getId())
+ " from UserMarkupCollectionManager " + this.hashCode());
userMarkupCollections.remove(userMarkupCollection);
}
/**
* Updates {@link ContentInfoSet bibliographical Metadata} of the
* given {@link UserMarkupCollection}.
* @param userMarkupCollectionReference
* @return the modified collection
*/
public UserMarkupCollection updateUserMarkupCollection(
UserMarkupCollectionReference userMarkupCollectionReference) {
UserMarkupCollection userMarkupCollection =
getUserMarkupCollection(userMarkupCollectionReference);
userMarkupCollection.setContentInfoSet(
userMarkupCollectionReference.getContentInfoSet());
return userMarkupCollection;
}
/**
* @param instanceIDs a list of {@link TagInstance#getUuid() uuid}s of TagInstances
* @return a list of all TagInstances as {@link Pair pairs} with the {@link de.catma.tag.TagLibrary#getTagPath(de.catma.tag.TagDefinition) Tag path}
* and the corresponding {@link TagInstance}.
*/
public List<TagInstanceInfo> getTagInstanceInfos(Collection<String> instanceIDs) {
List<TagInstanceInfo> result =
new ArrayList<TagInstanceInfo>();
for (String instanceID : instanceIDs) {
TagInstanceInfo ti = getTagInstanceInfo(instanceID);
if (ti == null) {
throw new IllegalStateException(
"TagInstance #"+instanceID +
" could not be found in this UserMarkupCollectionManager!");
}
result.add(ti);
}
return result;
}
/**
* @param instanceID the {@link TagInstance#getUuid() uuid} of the TagInstance
* @return a TagInstanceInfo with the {@link de.catma.tag.TagLibrary#getTagPath(de.catma.tag.TagDefinition) Tag path},
* the corresponding {@link TagInstance} and the relevant {@link UserMarkupCollection}.
*/
public TagInstanceInfo getTagInstanceInfo(String instanceID) {
for (UserMarkupCollection umc : userMarkupCollections) {
if (umc.hasTagInstance(instanceID)) {
Pair<String, TagInstance> tagInstanceWithPath =
umc.getInstance(instanceID);
return new TagInstanceInfo(
tagInstanceWithPath.getSecond(),
umc,
tagInstanceWithPath.getFirst());
}
}
return null;
}
/**
* @param tagInstanceID the {@link TagInstance#getUuid() uuid} of the TagInstance
* @return a list of the tag references of the given instance
*/
public Collection<TagReference> getTagReferences(String tagInstanceID) {
Set<TagReference> result = new HashSet<TagReference>();
for (UserMarkupCollection umc : userMarkupCollections) {
if (umc.hasTagInstance(tagInstanceID)) {
result.addAll(umc.getTagReferences(tagInstanceID));
}
}
return result;
}
/**
* @param umcRef
* @return <code>true</code> if this manager contains the given collection (tested by
* id equality)
*/
public boolean contains(UserMarkupCollectionReference umcRef) {
return getUserMarkupCollection(umcRef) != null;
}
/**
* @param userMarkupCollectionId
* @return <code>true</code> if this manager contains the given collection
*/
public boolean contains(String userMarkupCollectionId) {
for (UserMarkupCollection umc : userMarkupCollections) {
if (umc.getId().equals(userMarkupCollectionId)) {
return true;
}
}
return false;
}
/**
* @param userMarkupCollectionId
* @return the collection or <code>null</code> if there is no such
* collection
*/
public UserMarkupCollection getUserMarkupCollection(
String userMarkupCollectionId) {
for (UserMarkupCollection umc : userMarkupCollections) {
if (umc.getId().equals(userMarkupCollectionId)) {
return umc;
}
}
return null;
}
/**
* The persistent part of this operation is handled by {@link
* Repository#update(TagInstance, Collection)}
* @param tagInstance
* @param properties
* @throws IOException
*/
public void updateProperty(TagInstance tagInstance, Collection<Property> properties) throws IOException {
repository.update(tagInstance, properties);
}
}