/*******************************************************************************
* Copyright (c) 2000, 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.rubypeople.rdt.internal.core;
import java.util.ArrayList;
import org.rubypeople.rdt.core.IParent;
import org.rubypeople.rdt.core.IRegion;
import org.rubypeople.rdt.core.IRubyElement;
/**
* @see IRegion
*/
public class Region implements IRegion
{
/**
* A collection of the top level elements that have been added to the region
*/
protected ArrayList<IRubyElement> fRootElements;
/**
* Creates an empty region.
*
* @see IRegion
*/
public Region()
{
fRootElements = new ArrayList<IRubyElement>(1);
}
/**
* @see IRegion#add(IRubyElement)
*/
public void add(IRubyElement element)
{
if (!contains(element))
{
// "new" element added to region
removeAllChildren(element);
fRootElements.add(element);
fRootElements.trimToSize();
}
}
/**
* @see IRegion
*/
public boolean contains(IRubyElement element)
{
int size = fRootElements.size();
ArrayList<IRubyElement> parents = getAncestors(element);
for (int i = 0; i < size; i++)
{
IRubyElement aTop = fRootElements.get(i);
if (aTop.equals(element))
{
return true;
}
for (int j = 0, pSize = parents.size(); j < pSize; j++)
{
if (aTop.equals(parents.get(j)))
{
// an ancestor is already included
return true;
}
}
}
return false;
}
/**
* Returns a collection of all the parents of this element in bottom-up order.
*/
private ArrayList<IRubyElement> getAncestors(IRubyElement element)
{
ArrayList<IRubyElement> parents = new ArrayList<IRubyElement>();
IRubyElement parent = element.getParent();
while (parent != null)
{
parents.add(parent);
parent = parent.getParent();
}
parents.trimToSize();
return parents;
}
/**
* @see IRegion
*/
public IRubyElement[] getElements()
{
int size = fRootElements.size();
IRubyElement[] roots = new IRubyElement[size];
for (int i = 0; i < size; i++)
{
roots[i] = (IRubyElement) fRootElements.get(i);
}
return roots;
}
/**
* @see IRegion#remove(IRubyElement)
*/
public boolean remove(IRubyElement element)
{
removeAllChildren(element);
return fRootElements.remove(element);
}
/**
* Removes any children of this element that are contained within this region as this parent is about to be added to
* the region.
* <p>
* Children are all children, not just direct children.
*/
protected void removeAllChildren(IRubyElement element)
{
if (element instanceof IParent)
{
ArrayList<IRubyElement> newRootElements = new ArrayList<IRubyElement>();
for (int i = 0, size = fRootElements.size(); i < size; i++)
{
IRubyElement currentRoot = fRootElements.get(i);
// walk the current root hierarchy
IRubyElement parent = currentRoot.getParent();
boolean isChild = false;
while (parent != null)
{
if (parent.equals(element))
{
isChild = true;
break;
}
parent = parent.getParent();
}
if (!isChild)
{
newRootElements.add(currentRoot);
}
}
fRootElements = newRootElements;
}
}
/**
* Returns a printable representation of this region.
*/
public String toString()
{
StringBuffer buffer = new StringBuffer();
IRubyElement[] roots = getElements();
buffer.append('[');
for (int i = 0; i < roots.length; i++)
{
buffer.append(roots[i].getElementName());
if (i < (roots.length - 1))
{
buffer.append(", "); //$NON-NLS-1$
}
}
buffer.append(']');
return buffer.toString();
}
}