var planout = require("planout");
var PlanOut = require("planout").Planout;

var salt = "salt";
var experiments = Object.create(null);
var logFunction = function() {};
var compatibleHash = false;

module.exports.UniformChoice = planout.Ops.Random.UniformChoice;
module.exports.WeightedChoice = planout.Ops.Random.WeightedChoice;
module.exports.PlanOutOpRandom = planout.Ops.Random.PlanOutOpRandom; 
module.exports.Sample = planout.Ops.Random.Sample; 
module.exports.BernoulliFilter = planout.Ops.Random.BernoulliFilter; 
module.exports.BernoulliTrial = planout.Ops.Random.BernoulliTrial; 
module.exports.RandomInteger = planout.Ops.Random.RandomInteger; 
module.exports.RandomFloat = planout.Ops.Random.RandomFloat; 

/**
 * Configure experiment defaults.
 * 
 * @param {Object} options
 * @param {Function} [options.logFunction]
 * @param {Function} [options.compatibleHash]
 */
module.exports.configure = function(options) {
    logFunction = options.logFunction || logFunction;
    experiments = options.experiments || experiments;
    if (options.compatibleHash != null)
        compatibleHash = options.compatibleHash;
    salt = options.salt || String(salt);
};

module.exports.getExperiments = function() {
    return experiments;
};

/**
 * Create a new experiment.
 * 
 * @param {String|Number} userId
 * @param {String} name
 * @param {String[]} choices
 * @param {Object} [option]
 *        Options for the experiment. This may also include
 *        arguments for the distribution operator, e.g. weight.
 * @param {Function} [options.operator]
 *        The distribution operator, e.g. outplan.WeightedChoice  
 */
module.exports.create = function(name, choices, options) {
    options = options || {};
    options.operator = options.operator || module.exports.UniformChoice;
    options.choices = choices;
    
    return experiments[name] = options;
};

module.exports.get = function(userId, name) {
    if (!name)
        throw new Error("Missing argument. Expected: userId, name");
        
    planout.ExperimentSetup.toggleCompatibleHash(compatibleHash);
    
    var experiment = experiments[name];
    if (!experiment)
        throw new Error("Experiment not defined: " + name);
    experiment.unit = String(userId);
    experiment.salt = salt;
    var operator = new experiment.operator(experiment);
    var assignment = new planout.Assignment(salt);
    return operator.execute(assignment);
};
@@ -1347,16 +1347,23 @@
 String%5B%5D
+%7CObject
 %7D choice
@@ -1364,16 +1364,149 @@
 choices%0A
+ *        A list of variations, e.g. %5B%22A%22, %22B%22%5D,%0A *        or variation objects, e.g. %7B A: %7B color: %22#AAA%22 %7D, B: %7B color: %22#BBB%22 %7D %7D%0A
  * @para
@@ -1929,34 +1929,181 @@
     
-options.choices = choices;
+if (Array.isArray(choices)) %7B%0A        options.choices = choices;%0A    %7D%0A    else %7B%0A        options.choices = Object.keys(choices);%0A        options.choiceData = choices;%0A    %7D
 %0A   
@@ -2286,128 +2286,8 @@
     
-    %0A    planout.ExperimentSetup.toggleCompatibleHash(compatibleHash);%0A    %0A    var experiment = experiments%5Bname%5D;%0A    
 if (
@@ -2297,16 +2297,23 @@
 periment
+s%5Bname%5D
 )%0A      
@@ -2366,16 +2366,65 @@
  name);%0A
+        %0A    var experiment = experiments%5Bname%5D;%0A
     expe
@@ -2481,16 +2481,21 @@
 = salt;%0A
+    %0A
     var 
@@ -2601,43 +2601,195 @@
     
-return operator.execute(assignment)
+%0A    planout.ExperimentSetup.toggleCompatibleHash(compatibleHash);%0A    var choice = operator.execute(assignment);%0A    return experiment.choiceData ? experiment.choiceData%5Bchoice%5D : choice
 ;%0A%7D;

Support complex values