package edu.brown.catalog.special;
import java.util.ArrayList;
import java.util.Arrays;
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 org.voltdb.catalog.Catalog;
import org.voltdb.catalog.CatalogType;
import org.voltdb.catalog.Database;
import org.voltdb.catalog.Procedure;
import org.voltdb.utils.NotImplementedException;
import edu.brown.catalog.CatalogFieldComparator;
import edu.brown.catalog.CatalogUtil;
import edu.brown.utils.ClassUtil;
import edu.brown.utils.CollectionUtil;
import edu.brown.utils.StringUtil;
public class InnerMultiAttributeCatalogType<T extends CatalogType> extends CatalogType implements MultiAttributeCatalogType<T> {
private static final Map<Class<? extends CatalogType>, CatalogFieldComparator<CatalogType>> COMPARATORS = new HashMap<Class<? extends CatalogType>, CatalogFieldComparator<CatalogType>>();
private static final Map<Database, Map<Collection<? extends CatalogType>, MultiAttributeCatalogType<? extends CatalogType>>> SINGLETONS = new HashMap<Database, Map<Collection<? extends CatalogType>, MultiAttributeCatalogType<? extends CatalogType>>>();
private final Class<? extends MultiAttributeCatalogType<T>> base_class;
private final List<T> attributes = new ArrayList<T>();
protected InnerMultiAttributeCatalogType(Class<? extends MultiAttributeCatalogType<T>> base_class, Collection<T> attributes) {
this.base_class = base_class;
this.attributes.addAll(attributes);
assert (this.attributes.isEmpty() == false);
assert (new HashSet<T>(this.attributes).size() == this.attributes.size()) :
"Duplicate Attributes: " + this.attributes;
CatalogType last_parent = null;
for (T c : this.attributes) {
if (last_parent != null)
assert (c.getParent().equals(last_parent)) :
"Catalog items do not have the same parent: " + CatalogUtil.debug(this.attributes);
last_parent = c.getParent();
} // FOR
}
/**
* @param <T>
* @param <U>
* @param clazz
* @param attrs
* @return
* @throws Exception
*/
@SuppressWarnings("unchecked")
protected static <T extends CatalogType, U extends MultiAttributeCatalogType<T>> U get(Class<U> clazz, T... attrs) {
assert(attrs.length > 1) : String.format("Trying to create a %s with %d attributes %s",
clazz.getSimpleName(), attrs.length, Arrays.toString(attrs));
for (int i = 0; i < attrs.length; i++) {
assert(attrs[i] != null) :
String.format("The catalog attribute at offset %d is null - %s", i, Arrays.toString(attrs));
// Make sure that they don't try to nest a MultiAttributeCatalogType inside of each other
assert(attrs[i].getClass().equals(clazz) == false) :
String.format("Trying to nest a %s inside of another at offset %d %s",
clazz.getSimpleName(), i, Arrays.toString(attrs));
} // FOR
List<T> attributes = (List<T>) CollectionUtil.addAll(new ArrayList<T>(), attrs);
CatalogFieldComparator<T> comparator = (CatalogFieldComparator<T>) COMPARATORS.get(clazz);
if (comparator == null) {
comparator = new CatalogFieldComparator<T>("index");
COMPARATORS.put((Class<? extends CatalogType>) clazz, (CatalogFieldComparator<CatalogType>) comparator);
}
// Collections.sort(attributes, comparator);
Database catalog_db = CatalogUtil.getDatabase(attrs[0]);
if (!SINGLETONS.containsKey(catalog_db)) {
SINGLETONS.put(catalog_db, new HashMap<Collection<? extends CatalogType>, MultiAttributeCatalogType<? extends CatalogType>>());
}
U obj = (U) SINGLETONS.get(catalog_db).get(attributes);
if (obj == null) {
obj = (U) ClassUtil.newInstance(clazz, new Object[] { attributes }, new Class<?>[] { Collection.class });
assert (obj != null) : "Invalid MultiAttributeCatalogType for " + attributes;
SINGLETONS.get(catalog_db).put(attributes, obj);
// Add the parameter object to the procedure's list
if (obj instanceof MultiProcParameter) {
Procedure catalog_proc = ((MultiProcParameter) obj).getParent();
((MultiProcParameter) obj).setIndex(catalog_proc.getParameters().size());
catalog_proc.getParameters().add((MultiProcParameter) obj);
}
}
return (obj);
}
// --------------------------------------------------------------------------------------------
// CATALOG TYPE METHODS
// --------------------------------------------------------------------------------------------
@SuppressWarnings("unchecked")
@Override
public <U extends CatalogType> U getParent() {
return (U) this.attributes.get(0).getParent();
}
@Override
public Catalog getCatalog() {
return this.attributes.get(0).getCatalog();
}
@Override
public String getName() {
return (this.getTypeName());
}
@Override
public String getTypeName() {
String names[] = new String[this.size()];
for (int i = 0; i < names.length; i++) {
names[i] = this.attributes.get(i).getName();
}
return ("<" + StringUtil.join(",", names) + ">");
}
@Override
public int hashCode() {
return this.attributes.hashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof InnerMultiAttributeCatalogType))
return (false);
return (this.attributes.equals(((InnerMultiAttributeCatalogType<?>) obj).attributes));
}
@Override
public Collection<T> getAttributes() {
return Collections.unmodifiableCollection(this.attributes);
}
@Override
public void update() {
assert (false);
}
@Override
public String getPrefix() {
return ("*" + this.base_class.getSimpleName() + "*");
}
// --------------------------------------------------------------------------------------------
// COLLECTION METHODS
// --------------------------------------------------------------------------------------------
@Override
public Iterator<T> iterator() {
return this.attributes.iterator();
}
@Override
public int size() {
return (this.attributes.size());
}
@Override
public T get(int idx) {
assert (idx < this.attributes.size()) : "Invalid offset '" + idx + "' for " + this;
return ((T) this.attributes.get(idx));
}
@Override
public boolean contains(Object o) {
return (this.attributes.contains(o));
}
@Override
public boolean containsAll(Collection<?> c) {
return (this.attributes.containsAll(c));
}
@Override
public boolean isEmpty() {
return (this.attributes.isEmpty());
}
@Override
public Object[] toArray() {
return this.attributes.toArray();
}
@SuppressWarnings("hiding")
@Override
public <T> T[] toArray(T[] a) {
return this.attributes.toArray(a);
}
// --------------------------------------------------------------------------------------------
// UNIMPLEMENTED
// --------------------------------------------------------------------------------------------
@Override
public boolean add(T e) {
throw new NotImplementedException(this + " is a read-only Catalog object");
}
@Override
public boolean addAll(Collection<? extends T> c) {
throw new NotImplementedException(this + " is a read-only Catalog object");
}
@Override
public void clear() {
throw new NotImplementedException(this + " is a read-only Catalog object");
}
@Override
public boolean remove(Object o) {
throw new NotImplementedException(this + " is a read-only Catalog object");
}
@Override
public boolean removeAll(Collection<?> c) {
throw new NotImplementedException(this + " is a read-only Catalog object");
}
@Override
public boolean retainAll(Collection<?> c) {
throw new NotImplementedException(this + " is a read-only Catalog object");
}
}