package common.counterbalancing;
import common.filesystem.FileSystem;
import common.filesystem.FileSystemConstants;
import configuration.RoundDesign;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.lang.Integer;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.SizeLimitExceededException;
import org.yaml.snakeyaml.Yaml;
/**
*
* @author Tristan Goffman(tgoffman@gmail.com) Nov 7, 2011
*/
public class CounterBalancedOrdering {
public static String foldPath = FileSystem.FOLDER_CONF + File.separatorChar + FileSystemConstants.COUNTERBALANCED_ORDERING_FOLDER;
public static void reset() {
util.Util.removeDirectory(new File(foldPath));
}
private int groups;
private int numOrderables;
public int getNumOrderables() {
return numOrderables;
}
public void setNumOrderables(int numOrderables) {
this.numOrderables = numOrderables;
}
public int getGroups() {
return groups;
}
public void setGroups(int groups) {
this.groups = groups;
}
List<List<Integer>> getOrderings() {
ArrayList<List<Integer>> li = new ArrayList<List<Integer>>();
final int numOs = this.getNumOrderables();
ArrayList<Integer> colArr = new ArrayList<Integer>();
for (int i = 0; i < numOs; i++) {
colArr.add(new Integer(i));
}
while (li.size() < getGroups()) {
int temp = 0;
//NOTE: Not the best implementation by any means
List<Integer> attempt = new ArrayList<Integer>();
for (int i = 0; i < numOs; i++) {
temp = (int) Math.floor(Math.random() * numOs);
attempt.add(new Integer(temp));
}
boolean isDup = false;
for (List<Integer> other : li) {
if (other.equals(attempt)) {
isDup = true;
break;
}
}
if (!isDup && attempt.containsAll(colArr)) {
li.add(attempt);
}
}
return li;
}
protected <E> List<E> reorder(List<E> toReorder, int subjectNumber) throws SizeLimitExceededException{
if(toReorder.size() != getNumOrderables()){
throw new SizeLimitExceededException("Number of orderables is different size than list supplied");
}
List<List<Integer>> orders = getOrderings();
//Save to file
try {
Yaml yaml = new Yaml();
yaml.dump(orders, new FileWriter(getOrdFile(toReorder.size(), getGroups())));
} catch (IOException ex) {
Logger.getLogger(CounterBalancedOrdering.class.getName()).log(Level.WARNING, "Error while attempting to dump out yaml of orderings", ex);
}
int rawIndex = subjectNumber % getGroups();
List<Integer> reodering = orders.get(rawIndex);
return reorderWith(reodering, toReorder);
}
protected static <E> List<E> reorderWith(List<Integer> reodering, List<E> toReorder) {
Object[] arr = new Object[toReorder.size()];
for (int i = 0; i < reodering.size(); i++) {
arr[reodering.get(i)]= toReorder.get(i);
}
return (List<E>) Arrays.asList(arr);
}
public static <E> List<E> reorder(List<E> toReorder, int subjectNumber, int numGroups) throws SizeLimitExceededException, NotEnoughPermutations{
if(containsFile(toReorder.size(), numGroups))
try{
InputStream input = new FileInputStream( getOrdFile(toReorder.size(), numGroups));
Yaml yaml = new Yaml();
List data = (List) yaml.load(input);
List arr = (List) data.get( subjectNumber % numGroups);
List<Integer> newarr = new ArrayList<Integer>();
for (Object object : arr) {
newarr.add(new Integer((int) object));
}
return reorderWith(newarr, toReorder);
}catch(FileNotFoundException ex){
//don't do anything continue on with rest (non IO based solution
}
if(numGroups > fact(toReorder.size()))
throw new NotEnoughPermutations("Given the amount of elements in the list given enough permutations of the elements are not available for" + Integer.toString(numGroups));
CounterBalancedOrdering ord = new CounterBalancedOrdering();
ord.setGroups(numGroups);
ord.setNumOrderables(toReorder.size());
return ord.reorder(toReorder, subjectNumber);
}
/**
* Swaps the position of two element within a list
* @param <E>
* @param li
* @param oldindex
* @param newindex
* @return
*/
private static <E> List<E> swap(List<E> li, int oldindex,int newindex){
E val = li.get(oldindex);
li.set(oldindex, li.get(newindex));
li.set(newindex, val);
return li;
}
private static int fact(int n){
int temp = 1;
for(int i = n; n > 0;n--){
temp*= i;
}
return temp;
}
public static class NotEnoughPermutations extends Exception {
public NotEnoughPermutations(String string) {
super(string);
}
}
private static String pathToOrdFile(int size, int numGroups){
return foldPath + File.separatorChar + "ord_groups_" + Integer.toString(numGroups) + "_orderables_" + Integer.toString(size) + ".conf";
}
private static File getOrdFile(int size, int numGroups){
return new File(pathToOrdFile(size, numGroups));
}
private static boolean containsFile(int size, int numGroups) {
File file = new File(foldPath);
if (file.exists()){
file = new File(pathToOrdFile(size, numGroups));
return file.exists();}
else{
file.mkdir();
}
return false;
}
public static void main(String[] args){
List<RoundDesign> li = new ArrayList<RoundDesign>();
li.add(new RoundDesign());
RoundDesign rnd = new RoundDesign();
rnd.setPoints(1000);
li.add(rnd);
try {
List<RoundDesign> frst = CounterBalancedOrdering.reorder(li, 0, 2);
List<RoundDesign> snd = CounterBalancedOrdering.reorder(li, 1, 2);
snd.size();
} catch (SizeLimitExceededException ex) {
Logger.getLogger(CounterBalancedOrdering.class.getName()).log(Level.SEVERE, null, ex);
} catch (NotEnoughPermutations ex) {
Logger.getLogger(CounterBalancedOrdering.class.getName()).log(Level.SEVERE, null, ex);
}
}
}