/*******************************************************************************
* Copyright (c) 2017
* <p>
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
* <p>
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
* <p>
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*******************************************************************************/
package jsettlers.common.utils.coordinates;
import java8.util.Optional;
import jsettlers.common.position.ShortPoint2D;
import jsettlers.common.utils.mutables.Mutable;
import jsettlers.common.utils.mutables.MutableInt;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Andreas Eberle on 12.01.2017.
*/
public abstract class CoordinateStream implements Serializable {
public static final CoordinateStream EMPTY = new CoordinateStream() {
@Override
public boolean iterate(IBooleanCoordinateFunction function) {
return true;
}
};
public <T> Optional<T> iterateForResult(ICoordinateFunction<Optional<T>> function) {
Mutable<Optional<T>> result = new Mutable<>(Optional.empty());
iterate((x, y) -> {
Optional<T> currResult = function.apply(x, y);
if (currResult.isPresent()) {
result.object = currResult;
return false;
} else {
return true;
}
});
return result.object;
}
/**
* @param function
* Function called for every value of the stream. If the function returns <code>true</code> the iteration is continued. If it returns
* <code>false</code> the iteration is stopped.
* @return <code>true</code> if the iteration has not been aborted (the function never returned <code>false</code>)
*/
public abstract boolean iterate(IBooleanCoordinateFunction function);
public CoordinateStream filter(ICoordinatePredicate predicate) {
return new CoordinateStream() {
@Override
public boolean iterate(IBooleanCoordinateFunction function) {
return CoordinateStream.this.iterate((x, y) -> !predicate.test(x, y) || function.apply(x, y));
}
};
}
public CoordinateStream filterBounds(int width, int height) {
return filterBounds(0, 0, width, height);
}
/**
* @param xStart
* inclusive
* @param yStart
* inclusive
* @param xEnd
* exclusive
* @param yEnd
* exclusive
* @return
*/
public CoordinateStream filterBounds(int xStart, int yStart, int xEnd, int yEnd) {
return filter((x, y) -> xStart <= x && x < xEnd && yStart <= y && y < yEnd);
}
public void forEach(ICoordinateConsumer consumer) {
iterate((x, y) -> {
consumer.accept(x, y);
return true;
});
}
public CoordinateStream getEvery(int getIndex) {
if (getIndex <= 0) {
throw new IllegalArgumentException("parameter must be greater 0");
}
MutableInt counter = new MutableInt(0);
return filter(((x, y) -> counter.value++ % getIndex == 0));
}
public CoordinateStream skipFirst(int numberOfSkips) {
MutableInt counter = new MutableInt(0);
return filter((x, y) -> counter.value++ >= numberOfSkips);
}
public int count() {
MutableInt counter = new MutableInt(0);
forEach((x, y) -> counter.value++);
return counter.value;
}
public boolean isEmpty() {
return iterate((x, y) -> false);
}
public List<ShortPoint2D> toList() {
List<ShortPoint2D> result = new ArrayList<>();
forEach((x, y) -> result.add(new ShortPoint2D(x, y)));
return result;
}
public boolean contains(int searchedX, int searchedY) {
return !iterate((x, y) -> !(x == searchedX && y == searchedY));
}
/**
* Creates a frozen instance of this stream. The content of the frozen stream will not be changed in the future.
*
* @return
*/
public CoordinateStream freeze() {
return new CoordinatesList(this);
}
public static CoordinateStream fromList(final List<ShortPoint2D> positions) {
return new CoordinateStream() {
@Override
public boolean iterate(IBooleanCoordinateFunction function) {
for (ShortPoint2D position : positions) {
if (!function.apply(position.x, position.y)) {
return false;
}
}
return true;
}
};
}
}