content: package aliview.sequences;
  
  import java.util.BitSet;
  
  import org.apache.log4j.Logger;
  
  public class DefaultSequenceSelectionModel implements SequenceSelectionModel {
  	private static final Logger logger = Logger.getLogger(DefaultSequenceSelectionModel.class);
  	BitSet bitSelection;
  	boolean allSelected;
  
  	public boolean isSelected(int n) {
  		if(allSelected){
  			return true;
  		}
  		if(bitSelection == null){
  			return false;
  		}else{
  			return bitSelection.get(n);
  		}
  	}
  
  	private BitSet createNewSelection() {
  		allSelected = false;
  		return new BitSet();
  	}
  
  	public void clearAll() {
  		//logger.info("clearAll");
  		bitSelection = null;
  		allSelected = false;
  	}
  
  	public void selectAll() {
  		clearAll();
  		allSelected = true;
  	}
  
  	public int getFirstSelectedPosition() {
  		if(allSelected){
  			return 0;
  		}
  		if(bitSelection == null){
  			return -1;
  		}else{
  			return bitSelection.nextSetBit(0);
  		}
  	}
  
  	public int getLastSelectedPosition(int seqLength) {
  		if(allSelected){
  			return seqLength - 1;
  		}
  		if(bitSelection == null){
  			return -1;
  		}else{
  			// last bit in bitset is always set (autoshrink)
  			return bitSelection.length() - 1;
  		}
  	}
  
  	public boolean hasSelection() {
  		if(allSelected){
  			return true;
  		}
  		if(bitSelection == null){
  			return false;
  		}else{	
  			return !bitSelection.isEmpty();
  		}
  	}
  
  	public int[] getSelectedPositions(int startIndex, int endIndex) {
  		if(allSelected){
  			int[] pos = new int[endIndex - startIndex + 1];
  			for(int n = 0; n<pos.length; n++){
  				pos[n] = n;
  			}
  			return pos;
  		}
  		if(bitSelection == null){
  			return new int[0];
  		}
  		int[] pos = new int[countSelectedPositions(startIndex, endIndex)];
  		int index = 0;
  		for(int i = bitSelection.nextSetBit(startIndex); i >= 0 && i <= endIndex; i = bitSelection.nextSetBit(i+1)) {
  			pos[index] = i;
  			index++;
  		}
  
  		return pos;	
  	}
  
  	public int countPositionsUntilSelectedCount(int selectedCount) {
  		if(allSelected){
  			return selectedCount-1;
  		}
  		if(bitSelection == null){
  			logger.info("no bit selection");
  			return -1;
  		}else{
  			int index = -1;
  			int nCount = 0;
  			for (int i = bitSelection.nextSetBit(0); i >= 0 && i <= bitSelection.length(); i = bitSelection.nextSetBit(i+1)) {
  				//			    logger.info("i" + i);
  				nCount ++;
  				if(nCount == selectedCount){
  					index = i;
  					break;
  				}
  			}
  			return index;
  		}	
  	}
  
  
  	public int countSelectedPositions(int startIndex, int endIndex) {
  		if(allSelected){
  			return endIndex - startIndex + 1;
  		}
  		if(bitSelection == null){
  			return 0;
  		}else{
  			int nCount = 0;
  			for (int i = bitSelection.nextSetBit(startIndex); i >= 0 && i <= endIndex; i = bitSelection.nextSetBit(i+1)) {
  				nCount ++;
  			}
  			return nCount;
  		}	
  	}
  
  	public void clearSelectionAt(int n) {
  		clearSelection(n, n, false);
  	}
  
  	public void clearSelection(int startIndex, int endIndex, boolean clearFirst){
  		if(clearFirst){
  			clearAll();
  		}
  		if(bitSelection == null){
  			return; // already clear
  		}	
  		bitSelection.set(startIndex, endIndex + 1, false); // bitselection end index is exclusive
  	}
  
  	public void setSelectionAt(int n){
  		setSelection(n, n, false);
  	}
  
  	public void setSelection(int startIndex, int endIndex, boolean clearFirst){
  		if(clearFirst){
  			clearAll();
  		}
  		if(bitSelection == null){
  			bitSelection = createNewSelection();
  		}
  		bitSelection.set(startIndex, endIndex + 1, true); // bitselection end index is exclusive
  
  	}
  
  	public void rightPad(int length) {
  		// nothing need to be done	
  	}
  
  	public void leftPad(int length) {
  		if(hasSelection() && allSelected == false){	
  			for(int n = 0; n < length; n++){
  				insertNewPosAt(0);
  			}
  		}
  	}
  
  	public void removePosition(int index) {
  		if(hasSelection() && allSelected == false){	
  			for(int n = index; n < bitSelection.length(); n++){
  				bitSelection.set(n,bitSelection.get(n+1));
  			}
  		}
  	}
  
  	public void insertNewPosAt(int index) {
  		if(hasSelection() && allSelected == false){	
  			for(int n = bitSelection.length(); n >= index; n--){
  				bitSelection.set(n + 1,bitSelection.get(n));
  			}
  			bitSelection.set(index,false);
  		}
  	}
  
  
  	public boolean isAllSelected() {
  		return allSelected;
  	}
  
  	public void invertSelection(int length) {
  		// Full selection
  		if(allSelected){
  			clearAll();
  		}else if(hasSelection() == false){
  			selectAll();
  		}
  
  		// partial selection
  		if(hasSelection() && allSelected != true){
  			logger.info("partial");
  			bitSelection.flip(0, length);
  		}
  	}
  
  }
  