package com.idega.util;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import com.idega.idegaweb.IWUserContext;
import com.idega.presentation.IWContext;
import com.idega.presentation.ui.HiddenInput;
/**
*@author <a href="mailto:thomas@idega.is">Thomas Hilbig</a>
*@version 1.0
*
* This list iterator can be used to step through a list by getting subsets
* of the list.
* There are also some methods to store and to retrieve the state of an
* instance into and from the session.
*
*
*/
public class SetIterator implements ListIterator {
public final static String SET_ITERATOR_STATE_KEY = "set_iterator_state_key";
public final static String SET_ITERATOR_LIST_ID_KEY = "set_iterator_list_id_key";
private final static String STATE_STRING_DELIMITER = ":";
private List list = null;
private int increment = 1;
private int quantity = 1;
private int lastIndex = -1;
private int firstIndex = -1;
// start index of the current set
private int firstIndexOfCurrentSet;
// index of the current element
private int indexOfCurrentElement;
public SetIterator() {
}
public SetIterator(List list) {
this( 0 , (list.size() - 1));
this.list = list;
}
public SetIterator(int firstIndex, int lastIndex) {
this.firstIndex = firstIndex;
this.lastIndex = lastIndex;
this.firstIndexOfCurrentSet = firstIndex;
this.indexOfCurrentElement = firstIndex - 1;
}
public static void releaseStoredState(IWUserContext iwuc, String id) {
iwuc.removeSessionAttribute(SET_ITERATOR_STATE_KEY + id);
iwuc.removeSessionAttribute(SET_ITERATOR_LIST_ID_KEY + id);
}
/**
* @see java.util.Iterator#hasNext()
*/
public boolean hasNext() {
return (this.indexOfCurrentElement < this.lastIndex);
}
/**
* @see java.util.Iterator#next()
*/
public Object next() {
if (! hasNext()) {
throw new NoSuchElementException();
}
this.indexOfCurrentElement++;
return getElement(this.indexOfCurrentElement);
}
/**
* @see java.util.ListIterator#hasPrevious()
*/
public boolean hasPrevious() {
return (this.indexOfCurrentElement > this.firstIndex);
}
/**
* @see java.util.ListIterator#previous()
*/
public Object previous() {
if (! hasPrevious()) {
throw new NoSuchElementException();
}
this.indexOfCurrentElement--;
return getElement(this.indexOfCurrentElement);
}
/**
* @see java.util.ListIterator#nextIndex()
*/
public int nextIndex() {
return this.indexOfCurrentElement + 1;
}
/**
* @see java.util.ListIterator#previousIndex()
*/
public int previousIndex() {
return this.indexOfCurrentElement - 1;
}
public int currentIndex() {
return this.indexOfCurrentElement;
}
//first index is not necessarily zero
public int currentIndexRelativeToZero() {
return calculateIndexRelativeToZero(currentIndex());
}
public int currentFirstIndexSet() {
return ( this.firstIndexOfCurrentSet < this.firstIndex) ? this.firstIndex : this.firstIndexOfCurrentSet;
}
// first index is not necessarily zero
public int currentFirstIndexSetRelativeToZero() {
return calculateIndexRelativeToZero(currentFirstIndexSet());
}
public int currentLastIndexSet() {
int realLastIndexSet = currentFirstIndexSet() + this.quantity - 1;
return (realLastIndexSet > this.lastIndex) ? this.lastIndex : realLastIndexSet;
}
public void setIncrement(int increment) {
this.increment = (increment > 0) ? increment : 1;
// increment has changed..
adjustFirstIndexOfCurrentSet();
}
public int getIncrement() {
return this.increment;
}
public void setQuantity(int quantity) {
this.quantity = (quantity > 0) ? quantity : 1;
}
public int getQuantity() {
return this.quantity;
}
public void previousSet() {
goToSetRelativeToCurrentSet(-1);
}
public void nextSet() {
goToSetRelativeToCurrentSet(1);
}
public void goToSetRelativeToCurrentSet(int steps) {
int newFirstIndexOfSet = this.firstIndexOfCurrentSet + (steps * this.increment);
if (newFirstIndexOfSet > this.lastIndex || newFirstIndexOfSet < this.firstIndex) {
throw new NoSuchElementException("There is not such a subset");
}
this.firstIndexOfCurrentSet = newFirstIndexOfSet;
currentSet();
}
public int getNegativeNumberOfPreviousSetsRelativeToCurrentSet() {
int position = this.firstIndexOfCurrentSet - this.firstIndex + 1;
int division = (position / this.increment);
int mod = position % this.increment;
if (mod == 0) {
division -= 1;
}
return -division;
}
public int getPositiveNumberOfNextSetsRelativeToCurrentSet() {
int position = this.lastIndex - this.firstIndexOfCurrentSet + 1;
int division = (position / this.increment);
int mod = position % this.increment;
if (mod == 0) {
division -= 1;
}
return division;
}
public void currentSet() {
this.indexOfCurrentElement = (this.firstIndexOfCurrentSet < this.firstIndex) ?
this.firstIndex - 1 : this.firstIndexOfCurrentSet - 1;
}
public int size() {
return this.lastIndex - this.firstIndex + 1;
}
public int sizeSet() {
return currentLastIndexSet() - currentFirstIndexSet() + 1;
}
/**
* Returns true if there is a next set containing at least
* one element else false
*/
public boolean hasNextSet() {
return (this.firstIndexOfCurrentSet + this.increment <= this.lastIndex);
}
/** Returns true if there is a previous set containing at least
* one element else false
*/
public boolean hasPreviousSet() {
return (this.firstIndexOfCurrentSet > this.firstIndex);
}
/** Returns true if the next element is within the current set
* else false
*/
public boolean hasNextInSet() {
return (hasNext() &&
(this.indexOfCurrentElement + 1 < this.firstIndexOfCurrentSet + this.quantity) &&
(this.indexOfCurrentElement + 1 >= this.firstIndexOfCurrentSet));
}
/** Returns true if the previous element is within the current set
* else false
*/
public boolean hasPreviousInSet() {
return (hasPrevious() &&
(this.indexOfCurrentElement - 1 >= this.firstIndexOfCurrentSet) &&
(this.indexOfCurrentElement - 1 < this.firstIndexOfCurrentSet + this.quantity));
}
/** Gets current state as string */
public String getStateAsString() {
return storeStateIntoString();
}
/** Gets current state as hidden input
*/
public HiddenInput getStateAsHiddenInput(int id) {
return new HiddenInput(SET_ITERATOR_STATE_KEY + Integer.toString(id), storeStateIntoString());
}
public void storeStateInSession(IWUserContext iwuc, String listId, String id) {
iwuc.setSessionAttribute(SET_ITERATOR_STATE_KEY + id, storeStateIntoString());
iwuc.setSessionAttribute(SET_ITERATOR_LIST_ID_KEY + id, listId);
}
public boolean retrieveStateFromRequest(IWContext iwc, int id) {
String key = SET_ITERATOR_STATE_KEY + Integer.toString(id);
String stateString;
if (iwc.isParameterSet(key)) {
stateString = iwc.getParameter(key);
}
else {
return false;
}
return retrieveStateFromString(stateString);
}
public boolean retrieveStateFromSession(IWUserContext iwuc, String listId, String id) {
// retrieve current one
String stateString = (String) iwuc.getSessionAttribute(SET_ITERATOR_STATE_KEY + id);
String listIdString = (String) iwuc.getSessionAttribute(SET_ITERATOR_LIST_ID_KEY + id);
if (stateString == null || listIdString == null || (! listIdString.equals(listId))) {
if (stateString != null) {
iwuc.removeSessionAttribute(SET_ITERATOR_STATE_KEY + id);
}
if (listIdString != null) {
iwuc.removeSessionAttribute(SET_ITERATOR_LIST_ID_KEY + id);
}
return false;
}
return retrieveStateFromString(stateString);
}
/**
* Not supported.
* @see java.util.Iterator#remove()
*/
public void remove() {
throw new UnsupportedOperationException();
}
/**
* Not supported.
* @see java.util.ListIterator#set(Object)
*/
public void set(Object arg0) {
throw new UnsupportedOperationException();
}
/**
* Not supported.
* @see java.util.ListIterator#add(Object)
*/
public void add(Object arg0) {
throw new UnsupportedOperationException();
}
private Object getElement(int index) {
return (this.list == null) ? new Integer(index) : this.list.get(index);
}
private String storeStateIntoString() {
StringBuffer stateString = new StringBuffer();
// if you change this order or add or remove something do the same with the method
// retrieveStateFromString
stateString
.append(this.indexOfCurrentElement)
.append(STATE_STRING_DELIMITER)
.append(this.firstIndex)
.append(STATE_STRING_DELIMITER)
.append(this.lastIndex)
.append(STATE_STRING_DELIMITER)
.append(this.firstIndexOfCurrentSet)
.append(STATE_STRING_DELIMITER)
.append(this.increment)
.append(STATE_STRING_DELIMITER)
.append(this.quantity);
return stateString.toString();
}
private boolean retrieveStateFromString(String stateString) {
StringTokenizer tokenizer = new StringTokenizer(stateString, STATE_STRING_DELIMITER);
if (tokenizer.countTokens() != 6) {
return false;
}
// if you change this order or add or remove something do the same with the method
// storeStateIntoString
int indexOfCurrentElement = Integer.parseInt(tokenizer.nextToken());
int firstIndex = Integer.parseInt(tokenizer.nextToken());
int lastIndex = Integer.parseInt(tokenizer.nextToken());
int firstIndexOfCurrentSet = Integer.parseInt(tokenizer.nextToken());
int increment = Integer.parseInt(tokenizer.nextToken());
int quantity = Integer.parseInt(tokenizer.nextToken());
if (increment > 0) {
this.increment = increment;
}
if (quantity > 0) {
this.quantity = quantity;
}
// adjust values (list has changed)
if (this.firstIndex == firstIndex && this.lastIndex == lastIndex) {
// list has not changed its size
this.indexOfCurrentElement = indexOfCurrentElement;
this.firstIndexOfCurrentSet = firstIndexOfCurrentSet;
return true;
}
// list has changed, repair it....
int diff = firstIndex - this.firstIndex;
firstIndexOfCurrentSet += diff;
// is the new value within the range?
if (firstIndexOfCurrentSet > this.lastIndex) {
this.firstIndexOfCurrentSet = this.lastIndex;
}
else {
this.firstIndexOfCurrentSet = firstIndexOfCurrentSet;
}
// now adjust the current set
adjustFirstIndexOfCurrentSet();
return true;
}
private void adjustFirstIndexOfCurrentSet() {
int size = size();
if (size == 0) {
// list is empty (compare constructor)
this.firstIndexOfCurrentSet = this.firstIndex;
this.indexOfCurrentElement = this.firstIndex - 1;
return;
}
int position = this.firstIndexOfCurrentSet - this.firstIndex + 1;
// positionFromZero is now at least 1
int division = position / this.increment;
int mod = position % this.increment;
if (mod == 0) {
division -= 1;
}
this.firstIndexOfCurrentSet = division * this.increment;
currentSet();
return;
}
private int calculateIndexRelativeToZero(int index) {
return index - this.firstIndex;
}
}