package zinara.ast.type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
import java.util.Iterator;
import zinara.exceptions.KeyErrorException;
import zinara.exceptions.InvalidVariantException;
public class VariantType extends Type {
private HashMap base; // HashMap<String, Type>
private HashMap joins; // HashMap<String, HashMap<String, Type>>
private HashMap offsets; // HashMap<String, Int>
private int size;
public VariantType(HashMap b, HashMap js) throws InvalidVariantException {
base = b;
joins = js;
offsets = new HashMap();
String key;
Type ct;
Iterator it = base.keySet().iterator(), it2;
int offset = 0;
while(it.hasNext()) {
key = (String)it.next();
ct = (Type)base.get(key);
offsets.put(key, new Integer(offset));
offset += ct.size();
}
int maxOffset = offset;
int newOffset;
HashMap tablei;
it = joins.keySet().iterator();
while(it.hasNext()) {
tablei = (HashMap)joins.get((String)it.next());
it2 = tablei.keySet().iterator();
newOffset = offset;
while(it2.hasNext()) {
key = (String)it2.next();
ct = (Type)tablei.get(key);
if (offsets.put(key, ct) != null)
throw new InvalidVariantException("Los variantes no pueden tener claves repetidas, la clave " + key + " lo esta");
newOffset += ct.size();
}
if (maxOffset < newOffset) maxOffset = newOffset;
}
size = maxOffset;
}
public Iterator getIterator() { return base.keySet().iterator(); }
//public int len() { return }
public int size() { return size; }
public Type get(String key) {
Type type = (Type)base.get(key);
if (type != null) return type;
Iterator it = joins.keySet().iterator(), it2;
HashMap tablei;
while(it.hasNext()) {
tablei = (HashMap)joins.get((String)it.next());
it2 = tablei.keySet().iterator();
while(it2.hasNext()) {
type = (Type)tablei.get((String)it2.next());
if (type != null) return type;
}
}
return type;
}
public Type getOrDie(String key) throws KeyErrorException {
Type type = (Type)base.get(key);
if (type != null) return type;
Iterator it = joins.keySet().iterator(), it2;
HashMap tablei;
while(it.hasNext()) {
tablei = (HashMap)joins.get((String)it.next());
it2 = tablei.keySet().iterator();
while(it2.hasNext()) {
type = (Type)tablei.get((String)it2.next());
if (type != null) return type;
}
}
throw new KeyErrorException("La clave " + key + " no se encuentra definida en el tipo de diccionario " + toString());
}
public HashMap getVariant(String var) {
return (HashMap)joins.get(var);
}
public Integer getOffsetFor(String key) { return (Integer)offsets.get(key); }
public String toString() {
if (!name.equals("")) return "<" + name + ">";
String ret = "<{";
Set keySet = base.keySet();
Iterator it = keySet.iterator(), it2;
String currentKey;
while (it.hasNext()) {
currentKey = (String)it.next();
ret += currentKey + ": " + (Type)base.get(currentKey) + ", ";
}
ret = ret.substring(0, ret.length()-2);
ret += "} joined to";
it = joins.keySet().iterator();
HashMap tablai;
while(it.hasNext()) {
currentKey = (String)it.next();
ret += " " + currentKey + "{";
tablai = (HashMap)joins.get(currentKey);
it2 = tablai.keySet().iterator();
while(it2.hasNext()) {
currentKey = (String)it2.next();
ret += currentKey + ": " + (Type)tablai.get(currentKey) + ", ";
}
ret = ret.substring(0, ret.length()-2);
ret += "}";
}
return ret + ">";
}
public Type getType() { return this; }
public boolean equals(Type other) {
return false; // No se puede comparar nada contra un variant, pero si contra sus elementos.
// if (!(other instanceof VariantType)) return false;
// VariantType otherVariant = (VariantType)other;
// if (!otherVariant.getName().equals("") && !name.equals("")) return otherVariant.getName().equals(name);
// // Checks internally
// if (size() != otherVariant.size()) return false;
// Iterator it1 = getIterator();
// Iterator it2 = otherVariant.getIterator();
// String ckey1, ckey2;
// while(it1.hasNext()) {
// ckey1 = (String)it1.next();
// ckey2 = (String)it2.next();
// if (ckey1 != ckey2 || !get(ckey1).equals(((Type)otherVariant.get(ckey2)).getType()))
// return false;
// }
// return true;
}
public void setName(String n) { name = n; }
public String getName() { return name; }
}