/**
 * This file is part of Erjang - A JVM-based Erlang VM
 *
 * Copyright (c) 2009 by Trifork
 *
 * 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 erjang.m.ets;

import clojure.lang.IPersistentCollection;
import clojure.lang.IPersistentMap;
import clojure.lang.ISeq;
import clojure.lang.PersistentHashMap;
import clojure.lang.PersistentList;
import clojure.lang.PersistentTreeMap;

/**
 * 
 */
public class PersistentBag extends Object implements IPersistentBag {

	public static PersistentBag EMPTY = new PersistentBag(PersistentHashMap.EMPTY, 0);
	IPersistentMap impl;
	int count;

	private PersistentBag(IPersistentMap impl, int count) {
		this.impl = impl;
		this.count = count;
	}

	@Override
	public IPersistentBag disjoin(Object element) {
		Integer val = (Integer) impl.valAt(element);
		if (val == null) {
			return this;
		} else if (val == 1) {
			try {
				return new PersistentBag(impl.without(element), count - 1);
			} catch (Exception e) {
				throw new Error(e);
			}
		} else {
			return new PersistentBag(impl.assoc(element, val - 1), count - 1);
		}
	}

	@Override
	public IPersistentCollection cons(Object element) {
		Integer val = (Integer) impl.valAt(element);
		if (val == null) {
			return new PersistentBag(impl.assoc(element, 1), count + 1);
		} else {
			return new PersistentBag(impl.assoc(element, val + 1), count + 1);
		}
	}

	@Override
	public int count() {
		return count;
	}

	@Override
	public IPersistentCollection empty() {
		return new PersistentBag(PersistentTreeMap.EMPTY, 0);
	}

	@Override
	public boolean equiv(Object arg0) {
		throw new UnsupportedOperationException();
	}

	class ElemSeq implements ISeq {

		private final int total;
		private final int pos;
		private final ISeq pairs;

		@Override
		public ISeq cons(Object arg0) {
			// TODO Auto-generated method stub
			return null;
		}

		@Override
		public Object first() {
			ISeq elem_count_pair = (ISeq) pairs.first();
			return elem_count_pair.first();
		}

		@Override
		public ISeq more() {
			ISeq next = next();
			if (next == null)
				return PersistentList.EMPTY;
			return next;
		}

		@Override
		public ISeq next() {
			ISeq elem_count_pair = (ISeq) pairs.first();
			int count = (Integer) elem_count_pair.next().first();
			if (count == pos + 1) {
				ISeq succ = pairs.next();
				if (succ == null) {
					return null;
				} else {
					return new ElemSeq(succ, 0, total-1);
				}
			} else {
				return new ElemSeq(pairs, pos + 1, total-1);
			}
		}

		@Override
		public int count() {
			return total;
		}

		@Override
		public IPersistentCollection empty() {
			return PersistentBag.EMPTY;
		}

		@Override
		public boolean equiv(Object arg0) {
			throw new UnsupportedOperationException();
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see clojure.lang.Seqable#seq()
		 */
		@Override
		public ISeq seq() {
			return this;
		}

		ElemSeq(ISeq pairs, int count, int total) {
			this.pairs = pairs;
			this.pos = count;
			this.total = total;
		}

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see clojure.lang.Seqable#seq()
	 */
	@Override
	public ISeq seq() {
		return new ElemSeq(impl.seq(), 0, count);
	}

}

@@ -677,16 +677,47 @@
 m.ets;%0A%0A
+import clojure.lang.IMapEntry;%0A
 import c
@@ -2420,35 +2420,40 @@
 t first() %7B%0A%09%09%09I
-Seq
+MapEntry
  elem_count_pair
@@ -2449,35 +2449,40 @@
 _count_pair = (I
-Seq
+MapEntry
 ) pairs.first();
@@ -2508,21 +2508,22 @@
 nt_pair.
-first
+getKey
 ();%0A%09%09%7D%0A
@@ -2695,19 +2695,24 @@
 ) %7B%0A%09%09%09I
-Seq
+MapEntry
  elem_co
@@ -2724,19 +2724,24 @@
 air = (I
-Seq
+MapEntry
 ) pairs.
@@ -2794,20 +2794,16 @@
 air.
-next().first
+getValue
 ();%0A
@@ -3627,24 +3627,57 @@
 Seq seq() %7B%0A
+%09%09if (count() == 0) return null;%0A
 %09%09return new

Fix bug in PersistentBag: seq() was wrong