/*
This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2011 Servoy BV
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Affero 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along
with this program; if not, see http://www.gnu.org/licenses or write to the Free
Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
*/
package com.servoy.j2db.query;
import java.util.ArrayList;
import java.util.List;
import com.servoy.base.query.BaseQueryTable;
import com.servoy.j2db.util.serialize.ReplacedObject;
import com.servoy.j2db.util.visitor.IVisitor;
/**
* Multiple joins added together.
*
* @author rgansevles
*
*/
public final class QueryCompositeJoin implements ISQLTableJoin
{
private String name;
private List<ISQLJoin> joins = new ArrayList<ISQLJoin>();
public QueryCompositeJoin(String name)
{
this.name = name;
}
public QueryCompositeJoin(String name, List< ? extends ISQLJoin> joins)
{
this(name);
if (joins != null)
{
this.joins.addAll(joins);
}
}
public String getName()
{
return name;
}
public List<ISQLJoin> getJoins()
{
return joins;
}
public BaseQueryTable getPrimaryTable()
{
if (joins.size() > 0)
{
return joins.get(0).getPrimaryTable();
}
return null;
}
public BaseQueryTable getForeignTable()
{
if (joins.size() > 0)
{
ISQLJoin join = joins.get(joins.size() - 1);
if (join instanceof ISQLTableJoin)
{
return ((ISQLTableJoin)join).getForeignTable();
}
}
return null;
}
public AndCondition getCondition()
{
// get the last condition
if (joins.size() > 0)
{
ISQLJoin join = joins.get(joins.size() - 1);
if (join instanceof ISQLTableJoin)
{
return ((ISQLTableJoin)join).getCondition();
}
}
return null;
}
public boolean hasInnerJoin()
{
for (int i = 0; i < joins.size(); i++)
{
ISQLJoin join = joins.get(i);
if (!(join instanceof ISQLTableJoin) || ((ISQLTableJoin)join).hasInnerJoin())
{
// we don't know for custom joins, so return true to be on the safe side
return true;
}
}
return false;
}
/**
* Invert the direction of this join.
*/
public void invert(String newName)
{
List<ISQLJoin> invertedJoins = new ArrayList<ISQLJoin>();
for (int i = joins.size() - 1; i >= 0; i--)
{
ISQLJoin join = joins.get(i);
if (join instanceof ISQLTableJoin)
{
((ISQLTableJoin)join).invert(newName);
}
invertedJoins.add(join);
}
joins = invertedJoins;
this.name = newName;
}
@Override
public int getJoinType()
{
for (int i = 0; i < joins.size(); i++)
{
ISQLJoin join = joins.get(i);
if (join instanceof ISQLTableJoin)
{
return ((ISQLTableJoin)join).getJoinType();
}
}
return ISQLJoin.INNER_JOIN;
}
public void setJoinType(int joinType)
{
for (int i = 0; i < joins.size(); i++)
{
ISQLJoin join = joins.get(i);
if (join instanceof ISQLTableJoin)
{
((ISQLTableJoin)join).setJoinType(joinType);
}
}
}
@Override
public Object shallowClone() throws CloneNotSupportedException
{
return super.clone();
}
public void acceptVisitor(IVisitor visitor)
{
joins = AbstractBaseQuery.acceptVisitor(joins, visitor);
}
public static List<ISQLJoin> flatten(List<ISQLJoin> joins)
{
// flatten the list of joins, add all QueryCompositeJoin joins to the main list
return flatten(joins, 0);
}
private static List<ISQLJoin> flatten(List<ISQLJoin> joins, int start)
{
if (joins == null || (start > 0 && joins.size() <= start))
{
return null;
}
for (int i = start; i < joins.size(); i++)
{
ISQLJoin join = joins.get(i);
if (join instanceof QueryCompositeJoin)
{
// only start copying stuff when there is actually something to flatten
if (start == 0 && joins.size() == 1)
{
// usual case: just 1 composite join
return flatten(((QueryCompositeJoin)join).getJoins());
}
List<ISQLJoin> flattened = new ArrayList<ISQLJoin>();
for (int j = start; j < i - 1; j++)
{
flattened.add(joins.get(j));
}
List<ISQLJoin> f = flatten(((QueryCompositeJoin)join).getJoins());
if (f != null)
{
flattened.addAll(f);
}
f = flatten(joins, i + 1);
if (f != null)
{
flattened.addAll(f);
}
return flattened;
}
}
if (start == 0)
{
return joins; // there was nothing to flatten
}
return joins.subList(start, joins.size());
}
@Override
public String toString()
{
return new StringBuilder("Joins(").append(name).append(')').append(joins.toString()).toString();
}
///////// serialization ////////////////
public Object writeReplace()
{
// Note: when this serialized structure changes, make sure that old data (maybe saved as serialized xml) can still be deserialized!
return new ReplacedObject(AbstractBaseQuery.QUERY_SERIALIZE_DOMAIN, getClass(), new Object[] { name, joins });
}
public QueryCompositeJoin(ReplacedObject s)
{
Object[] members = (Object[])s.getObject();
int i = 0;
name = (String)members[i++];
joins = (List<ISQLJoin>)members[i++];
}
}