/** * Copyright (C) 2013 Kametic <epo.jemba@kametic.com> * * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE, Version 3, 29 June 2007; * or any later version * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.gnu.org/licenses/lgpl-3.0.txt * * 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 org.nuunframework.kernel.commons.function; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import org.nuunframework.kernel.commons.AssertUtils; public class ForEachCollection<T> { public static <T> ForEachCollection<T> foreach(Collection<T> resources) { return new ForEachCollection<T>(resources); } private Collection<T> resources = new ArrayList<T>(); private SelectHolder<T> selectHolder; private ForEachHolder<T> foreachHolder; public ForEachCollection(Collection<T> resources) { this.resources = resources; } public void add(T resource) { this.resources.add(resource); } static class SelectHolder<T> { public final Predicate<T> predicate; public final Object[] args; public SelectHolder(Predicate<T> predicate, Object[] args) { this.predicate = predicate; this.args = args; } } static class ForEachHolder<T> { public final BlockContextInternal context; public final Block<T> uniqBlock; public final Predicate<T> ifPredicate; public final Object predicateArgs; public final Block<T> thenBlock; public final Block<T> elseBlock; public ForEachHolder(BlockContextInternal context, Predicate<T> ifPredicate, Object predicateArgs, Block<T> thenBlock, Block<T> elseBlock) { this.context = context; this.ifPredicate = ifPredicate; this.predicateArgs = predicateArgs; this.thenBlock = thenBlock; this.elseBlock = elseBlock; // null this.uniqBlock = null; } public ForEachHolder(BlockContextInternal context, Block<T> uniqBlock) { this.context = context; this.uniqBlock = uniqBlock; // null this.ifPredicate = null; this.predicateArgs = null; this.thenBlock = null; this.elseBlock = null; } public void evaluate(T each) { if (uniqBlock != null) { uniqBlock.evaluate(context, each); } else {// alternate execution if (ifPredicate.is(each, predicateArgs)) { thenBlock.evaluate(context, each); } else { elseBlock.evaluate(context, each); } } } } public static interface ResultBuilder { <T> T get(); } public ResultBuilder forEachDo(final Block <T> block) { BlockContextInternal context = new BlockContextInternal(); foreachHolder = new ForEachHolder<T>(context, block); iterate(); ResultBuilder rb = new ResultBuilder() { @SuppressWarnings({ "unchecked", "hiding" }) @Override public <T> T get() { T o = (T) foreachHolder.context.map().get(block); return o; } }; return rb; } public ResultBuilder forEachDo(Predicate<T> predicate, Block<T> thenBlock, Block<T> elseBlock) { return forEachDo(predicate, null, thenBlock, elseBlock); } public ResultBuilder forEachDo(final Predicate<T> predicate, Object predicateArg, Block<T> thenBlock, Block<T> elseBlock) { BlockContextInternal context = new BlockContextInternal(); foreachHolder = new ForEachHolder<T>(context, predicate, predicateArg, thenBlock, elseBlock); iterate(); ResultBuilder rb = new ResultBuilder() { @SuppressWarnings("hiding") @Override public <T> T get() { @SuppressWarnings("unchecked") T o = (T) foreachHolder.context.map().get(predicate); return o; } }; return rb; } private void iterate() { int count = 0; int size = resources.size(); Iterator<T> it = resources.iterator(); while (it.hasNext()) { T each = it.next(); foreachHolder.context.map().put("count", count); int loopinfo = updateLoopinfo(count, size); foreachHolder.context.loopinfo(loopinfo); // select if (selectHolder.predicate.is(each, selectHolder.args)) { foreachHolder.evaluate(each); } count++; } } private int updateLoopinfo(int count, int size) { int loopinfo = 0; if (count == 0) { loopinfo |= LoopInfo.FIRST; } if (count == (size - 1)) { loopinfo |= LoopInfo.LAST; } if (count == (size - 2)) { loopinfo |= LoopInfo.PENULTIMATE; } if (count == (size - 3)) { loopinfo |= LoopInfo.ANTEPENULTIMATE; } return loopinfo; } public ForEachCollection<T> select(Predicate<T> predicate, Object... args) { AssertUtils.assertNotNull(predicate, "predicate can not be null"); this.selectHolder = new SelectHolder<T>(predicate, args); return this; } @SuppressWarnings("unchecked") public ForEachCollection<T> select() { this.selectHolder = new SelectHolder<T>(Predicate.TRUE, new Object[0]); return this; } }