/*
* Copyright 2013 Cameron Beccario
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.nullschool.grains;
import net.nullschool.collect.AbstractEntry;
import net.nullschool.collect.AbstractIterableMap;
import net.nullschool.collect.MapIterator;
import java.util.NoSuchElementException;
/**
* 2013-03-13<p/>
*
* A partial implementation of GrainBuilder that provides a MapIterator implementation.
*
* @author Cameron Beccario
*/
public abstract class AbstractGrainBuilder extends AbstractIterableMap<String, Object> implements GrainBuilder {
/**
* {@inheritDoc}
*
* <p/>When implemented, this method's return type should be changed to return the specific grain type this
* builder builds.
*/
@Override public abstract Grain build();
@Override public abstract Object get(Object key); // the iterator uses this, so must be defined by implementers
@Override public abstract Object remove(Object key); // the iterator uses this, so must be defined by implementers
/**
* An implementation of MapIterator that iterates over an array of basis keys provided by implementers of
* AbstractGrainBuilder.
*/
protected class BasisIter implements MapIterator<String, Object> {
private static final int BAD = -1;
private final String[] keys; // the keys to iterator over
private int next = 0; // the index of the key that will be the next result of next()
private int cursor = BAD; // the index of the key that was most recently returned by next(), or BAD if none
public BasisIter(String[] keys) {
this.keys = keys;
}
@Override public boolean hasNext() {
return next != keys.length;
}
@Override public String next() {
final int i = next;
if (next != keys.length) { // if there is a next key
next = i + 1; // advance to the next key
return keys[cursor = i]; // and remember the current position
}
throw new NoSuchElementException();
}
@Override public Object value() {
final int i = cursor;
if (i != BAD) {
return get(keys[i]);
}
throw new IllegalStateException();
}
@Override public Entry<String, Object> entry() {
final int i = cursor;
if (i != BAD) {
final String key = keys[i];
return new AbstractEntry<String, Object>() {
@Override public String getKey() { return key; }
@Override public Object getValue() { return get(key); }
@Override public Object setValue(Object value) { return put(key, value); }
};
}
throw new IllegalStateException();
}
@Override public void remove() {
final int i = cursor;
if (i == BAD) {
throw new IllegalStateException();
}
AbstractGrainBuilder.this.remove(keys[i]);
cursor = BAD; // the current position has been removed
}
}
}