/*
* Copyright (c) 2006-2011 Rogério Liesenfeld
* This file is subject to the terms of the MIT license (see LICENSE.txt).
*/
package mockit.emulation.hibernate3.ast.fromClause;
import java.util.*;
import mockit.emulation.hibernate3.ast.*;
final class FromJoin
{
enum JoinType { Inner, Full, LeftOuter, RightOuter }
final JoinType type;
final PathAndAlias pathAndAlias;
final Map<Object, List<Object>> result;
FromJoin nextJoin;
FromJoin(JoinType type, PathAndAlias pathAndAlias)
{
this.type = type;
this.pathAndAlias = pathAndAlias;
result = new HashMap<Object, List<Object>>();
}
static FromJoin parse(Tokens tokens)
{
String token = tokens.next().toLowerCase();
JoinType joinType;
if ("join".equals(token)) {
joinType = JoinType.Inner;
}
else if ("inner".equals(token)) {
tokens.next("join");
joinType = JoinType.Inner;
}
else if ("full".equals(token)) {
tokens.next("join");
joinType = JoinType.Full;
}
else if ("left".equals(token)) {
parseOuterJoin(tokens);
joinType = JoinType.LeftOuter;
}
else if ("right".equals(token)) {
parseOuterJoin(tokens);
joinType = JoinType.RightOuter;
}
else {
tokens.pushback();
return null;
}
token = tokens.next();
if (!"fetch".equalsIgnoreCase(token)) {
tokens.pushback();
}
PathAndAlias path = new PathAndAlias(tokens);
return new FromJoin(joinType, path);
}
private static void parseOuterJoin(Tokens tokens)
{
String token = tokens.next().toLowerCase();
if ("outer".equals(token)) {
tokens.next("join");
}
else if (!"join".equals(token)) {
throw new QuerySyntaxException(tokens);
}
}
int depth()
{
return 1 + (nextJoin == null ? 0 : nextJoin.depth());
}
public int tupleCount(Object entity)
{
List<Object> childValues = result.get(entity);
if (nextJoin == null) {
return childValues.size();
}
else {
int count = 0;
for (Object childValue : childValues) {
count += nextJoin.tupleCount(childValue);
}
return count;
}
}
boolean matches(Object entity, String entityAlias)
{
String initialElement = pathAndAlias.pathElements[0];
if (!entityAlias.equals(initialElement)) {
throw new RuntimeException(
"Unknown path element \"" + initialElement + "\", expected " + entityAlias);
}
Object joinResult = pathAndAlias.evaluate(entity);
if (joinResult == null) return false;
Collection<?> joinResultCollection;
if (joinResult instanceof Collection) {
joinResultCollection = (Collection<?>) joinResult;
if (joinResultCollection.isEmpty()) {
return false;
}
}
else {
joinResultCollection = null;
}
if (nextJoin == null) {
addResult(entity, joinResult);
return true;
}
String pathAlias = pathAndAlias.alias;
boolean matchesNextJoin;
if (joinResultCollection != null) {
matchesNextJoin = true;
for (Object resultElement : joinResultCollection) {
if (!nextJoin.matches(resultElement, pathAlias)) {
matchesNextJoin = false;
break;
}
}
}
else {
matchesNextJoin = nextJoin.matches(joinResult, pathAlias);
}
if (matchesNextJoin) {
addResult(entity, joinResult);
}
return matchesNextJoin;
}
private void addResult(Object parentEntity, Object joinResult)
{
List<Object> childrenValues = new LinkedList<Object>();
if (joinResult instanceof Collection) {
childrenValues.addAll((Collection<?>) joinResult);
}
else {
childrenValues.add(joinResult);
}
result.put(parentEntity, childrenValues);
}
int columnIndex(String alias)
{
if (alias.equals(pathAndAlias.alias)) {
return 1;
}
else if (nextJoin != null) {
return 1 + nextJoin.columnIndex(alias);
}
else {
return -1;
}
}
}