/*
 * Copyright (c) 2013 Philipp Meinen <philipp@bind.ch>
 * 
 * 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:
 * 
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 * 
 * 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 ch.bind.philib.msg;

import java.util.ArrayList;
import java.util.List;

import ch.bind.philib.validation.Validation;

/**
 * 
 * @author Philipp Meinen
 */
public final class SimpleCowList<E> {

	private final Class<E> clazz;

	private final List<E> all = new ArrayList<E>();

	private volatile E[] empty;

	private volatile E[] view;

	public SimpleCowList(Class<E> clazz) {
		Validation.notNull(clazz);
		this.clazz = clazz;
	}

	public boolean add(E e) {
		if (e == null) {
			return false;
		}
		synchronized (all) {
			boolean update = all.add(e);
			if (update) {
				updateView();
			}
			return update;
		}
	}

	public boolean remove(E e) {
		if (e == null) {
			return false;
		}
		synchronized (all) {
			boolean update = all.remove(e);
			if (update) {
				updateView();
			}
			return update;
		}
	}

	private void updateView() {
		int n = all.size();
		if (n == 0) {
			view = null;
		} else {
			view = all.toArray(mkArray(clazz, n));
		}
	}

	/**
	 * @return the current content of the copy-on-write set ; do not modify!
	 */
	public E[] getView() {
		E[] v = view;
		if (v == null) {
			return getEmpty();
		}
		return v;
	}

	public boolean isEmpty() {
		E[] v = view;
		return v == null || v.length == 0;
	}

	private E[] getEmpty() {
		E[] e = empty;
		if (e == null) {
			e = mkArray(clazz, 0);
			empty = e;
		}
		return e;
	}

	private static <E> E[] mkArray(Class<E> clazz, int size) {
		return (E[]) java.lang.reflect.Array.newInstance(clazz, size);
	}
}

@@ -1219,32 +1219,8 @@
 st;%0D
-%0Aimport java.util.List;%0D
 %0A%0D%0Ai
@@ -1270,24 +1270,536 @@
 %0D%0A%0D%0A/**%0D%0A * 
+A simple implementation of a copy-on-write list.%3Cbr /%3E%0D%0A * There are two modification methods: %7B@link #add(Object)%7D and %7B@link #remove(Object)%7D%3Cbr /%3E%0D%0A * and one read method: %7B@link #getView()%7D %3Cbr /%3E%0D%0A * Every modification through the %7B@code add%7D or %7B@code remove%7D methods will update the view. %3Cbr /%3E%0D%0A * The view is shared among all clients and must therefore %3Cb%3Enot be written to%3C/b%3E.%3Cbr/%3E%0D%0A * The modification methods are not optimized for speed since the intent of this cow-list is to guarantee fast reads.
 %0D%0A * @author
@@ -1910,24 +1910,29 @@
 e final 
+Array
 List%3CE%3E 
 all = ne
@@ -1923,19 +1923,23 @@
 List%3CE%3E 
-all
+content
  = new A
@@ -1950,17 +1950,55 @@
 List%3CE%3E(
-)
+4);%0D%0A%0D%0A%09private int numRemovesSinceTrim
 ;%0D%0A%0D%0A%09pr
@@ -2236,35 +2236,39 @@
 %09%09synchronized (
-all
+content
 ) %7B%0D%0A%09%09%09boolean 
@@ -2276,19 +2276,23 @@
 pdate = 
-all
+content
 .add(e);
@@ -2456,19 +2456,23 @@
 onized (
-all
+content
 ) %7B%0D%0A%09%09%09
@@ -2488,19 +2488,23 @@
 pdate = 
-all
+content
 .remove(
@@ -2537,32 +2537,190 @@
 %09updateView();%0D%0A
+%09%09%09%09if (numRemovesSinceTrim %3E content.size()) %7B%0D%0A%09%09%09%09%09content.trimToSize();%0D%0A%09%09%09%09%09numRemovesSinceTrim = 0;%0D%0A%09%09%09%09%7D else %7B%0D%0A%09%09%09%09%09numRemovesSinceTrim++;%0D%0A%09%09%09%09%7D%0D%0A
 %09%09%09%7D%0D%0A%09%09%09return 
@@ -2779,19 +2779,23 @@
 int n = 
-all
+content
 .size();
@@ -2852,19 +2852,23 @@
 %09view = 
-all
+content
 .toArray

make sure that space is reclaimed on the damn arraylist