/*
Copyright (C) 2008-2009 by Claas Wilke (claaswilke@gmx.net)
This file is part of the OCL 2 Java Code Generator of Dresden OCL2 for Eclipse.
Dresden OCL2 for Eclipse is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your option)
any later version.
Dresden OCL2 for Eclipse 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 Lesser General Public License
for more details.
You should have received a copy of the GNU Lesser General Public License along
with Dresden OCL2 for Eclipse. If not, see <http://www.gnu.org/licenses/>.
*/
package org.dresdenocl.ocl2java.types;
import java.util.ArrayList;
import java.util.Collection;
/**
* <p>
* An {@link OclBag} is a collection with duplicates allowed. That is, one
* object can be an element of a {@link OclBag} many times. There is no ordering
* defined on the elements in an {@link OclBag}.
* </p>
*
* @param <T>
* The type of the elements contained in this {@link OclBag}.
*
* @author Claas Wilke
*/
public class OclBag<T> extends OclCollection<T> {
/**
* <p>
* Creates a new {@link OclBag}.
* </p>
*/
public OclBag() {
this.myCollection = new ArrayList<T>();
}
/**
* @return An {@link OclBag} identical to this {@link OclBag}. This
* operation exists for convenience reasons.
*/
public OclBag<T> asBag() {
OclBag<T> result;
result = new OclBag<T>();
result.addAll(this.myCollection);
return result;
}
/**
* @return The {@link OclOrderedSet} containing all the elements from this
* {@link OclBag}, in undefined order, with duplicates removed.
*/
public OclOrderedSet<T> asOrderedSet() {
OclOrderedSet<T> result;
result = new OclOrderedSet<T>();
for (T anElement : this.myCollection) {
/* Check if the element has already been added. */
if (!result.contains(anElement)) {
result.add(anElement);
}
// no else.
}
return result;
}
/**
* @return A {@link OclSequence} that contains all the elements from this
* {@link OclBag}, in undefined order.
*/
public OclSequence<T> asSequence() {
OclSequence<T> result;
result = new OclSequence<T>();
result.addAll(this.myCollection);
return result;
}
/**
* @return The {@link OclSet} containing all the elements from this
* {@link OclBag}, with duplicates removed.
*/
public OclSet<T> asSet() {
OclSet<T> result;
result = new OclSet<T>();
for (T anElement : this.myCollection) {
/* Check if the element has already been added. */
if (!result.contains(anElement)) {
result.add(anElement);
}
// no else.
}
return result;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#equals(java.lang.Object)
*/
@SuppressWarnings("unchecked")
public boolean equals(Object anObject) {
boolean result;
try {
OclBag<T> aBag = (OclBag<T>) anObject;
result = this.equals(aBag);
}
catch (ClassCastException e) {
result = false;
}
return result;
}
/**
* @param aBag
* The {@link OclBag} this {@link OclBag} shall be compared with.
* @return True if this {@link OclBag} and the given {@link OclBag} contain
* the same elements, the same number of times.
*/
public boolean equals(OclBag<T> aBag) {
boolean result;
result = (this.size() == aBag.size());
if (result) {
for (T anElement : aBag) {
result &= (this.count(anElement) == aBag.count(anElement));
if (!result) {
break;
}
// no else.
}
}
// no else.
return result;
}
/**
* @param anObject
* The object which shall not be part of the result.
* @return The {@link OclBag} containing all elements of this {@link OclBag}
* except the given Object.
*/
public OclBag<T> excluding(T anObject) {
OclBag<T> result;
result = new OclBag<T>();
for (T anElement : this.myCollection) {
if (!anElement.equals(anObject)) {
result.add(anElement);
}
// no else.
}
return result;
}
/**
* <p>
* If the element type of this {@link OclBag} is not a {@link Collection}
* type, this results in the same {@link OclBag}. If the element type is a
* {@link Collection} type, the result is the {@link OclBag} containing all
* the elements of all the elements of the contained {@link Collection}.
* </p>
*/
@SuppressWarnings("unchecked")
public OclBag<?> flatten() {
OclBag result;
result = new OclBag();
for (T anElement : this.myCollection) {
/* The element is a collection, add all its elements. */
if (anElement instanceof Collection) {
Collection aCollection;
aCollection = (Collection) anElement;
result.addAll(aCollection);
}
/* Else add the element itself. */
else {
result.add(anElement);
}
}
return result;
}
/**
* @param anObject
* The object which shall be included to this {@link OclBag}.
* @return The {@link OclBag} containing all elements of this {@link OclBag}
* and the given Object.
*/
public OclBag<T> including(T anObject) {
OclBag<T> result;
result = new OclBag<T>();
result.addAll(this.myCollection);
result.add(anObject);
return result;
}
/**
* @param collection
* The {@link OclBag} this {@link OclBag} shall be intersected
* with.
* @return The intersection of this {@link OclBag} and a given
* {@link OclBag}.
*/
public OclBag<T> intersection(OclBag<T> aBag) {
OclBag<T> result;
result = new OclBag<T>();
for (T anElement : aBag) {
/* Check if anElement was already added to the result. */
if (result.excludes(anElement)) {
int minOccurrence;
/* Get the minimum occurrence of anElement in both collections. */
minOccurrence = Math.min(aBag.count(anElement), this
.count(anElement));
/* Add anElement to the result minOccurence times. */
for (int i = 0; i < minOccurrence; i++) {
result.add(anElement);
}
}
// no else.
}
return result;
}
/**
* @param collection
* The {@link OclBag} this {@link OclBag} shall be intersected
* with.
* @return The intersection of this {@link OclBag} and a given
* {@link OclBag}.
*/
public OclBag<T> intersection(OclSet<T> aSet) {
OclBag<T> result;
result = new OclBag<T>();
for (T anElement : aSet) {
/* Check if anElement occurs also to this OclBag. */
if (this.contains(anElement)) {
result.add(anElement);
}
// no else.
}
return result;
}
/**
* @param aBag
* The {@link OclBag} this {@link OclBag} shall be united with.
* @return The union of this {@link OclBag} and the given {@link OclBag}.
*/
public OclBag<T> union(OclBag<T> aBag) {
OclBag<T> result;
result = new OclBag<T>();
result.addAll(this.myCollection);
result.addAll(aBag);
return result;
}
/**
* @param aSet
* The {@link OclSet} this {@link OclBag} shall be united with.
* @return The union of this {@link OclBag} and the given {@link OclSet}.
*/
public OclBag<T> union(OclSet<T> aSet) {
OclBag<T> result;
result = new OclBag<T>();
result.addAll(this.myCollection);
result.addAll(aSet);
return result;
}
}