public static Bin[] buildBins(long lifetime, double[] weights) {

		//@todo -- find the correct lambda threshold for this approximation
		double ERROR_LIMIT = 2.0 / (double) lifetime;
		//System.out.println("ERROR_LIMIT :: " + ERROR_LIMIT);

		//ensure all weights are > 0
		for (int i = 0; i < weights.length; i++) {
			if (weights[i] < 0) {
				throw new IllegalArgumentException("Negative Weights not allowed");
			}
		}
		double wSum = Utility.sum(weights);

		//do inital sorting WHILE KEEPING TRACK OF INITAL ORDER
		Sorter[] sortMe = new Sorter[weights.length];
		for (int i = 0; i < sortMe.length; i++) {
			sortMe[i] = new Sorter(weights[i] / wSum, (short) i);
		}
		Arrays.sort(sortMe);

		double[] pValues = new double[sortMe.length];
		short[] entries = new short[sortMe.length];
		for (int i = 0; i < sortMe.length; i++) {
			pValues[i] = sortMe[i].pValue;
			entries[i] = sortMe[i].entry;
		}
		Bin initalBin = new Bin(pValues, entries);
		LinkedList<Bin> binList = new LinkedList<Bin>();
		binList.add(initalBin);

		double totalError = initalBin.inBinLambda;

		while (totalError > ERROR_LIMIT) {

			Collections.sort(binList);
			Bin highErrorBin = binList.removeFirst();

			Bin[] children = highErrorBin.split();

			for (int i = 0; i < children.length; i++) {
				binList.addLast(children[i]);
			}

			totalError = 0;
			double totalSize = 0;
			for (Bin bin : binList) {
				totalError += bin.inBinLambda;
				totalSize += bin.pSum;
			}

//			System.out.println("totalError :: " + totalError + "\n");
//			System.out.println("totalSize :: " + totalSize);
		}

		//output the bins
		Bin[] bins = binList.toArray(new Bin[0]);

		//remove the unnecessary information to save memory
		for (int i = 0; i < bins.length; i++) {
			bins[i].flatten();
		}
//		System.out.println("Final Bin Count :: " + bins.length);

		return bins;
	}