"use strict";

var assert = require('assert');

var ensurePropertyExists = function(d,i) {
    if (!d[i]) d[i] = {};
    return d[i];
}

var createData = function(pc, tokens) {
    var data = {},
        n = tokens.length,
        win = pc - 1;

    for (var i=0;i<n-win;++i) {
	var obj = ensurePropertyExists(data,tokens[i]);

	for (var j=1;j<win;++j)
	    obj = ensurePropertyExists(obj, tokens[i+j]);

	if (!obj[tokens[i+win]])
	    obj[tokens[i+win]] = 0;

	obj[tokens[i+win]]++;
    }

    return data;
};

var Model = function(predictionContext, tokens) {

    var n = tokens.length;

    this._data = createData(predictionContext, tokens);

    this.entryCount = function() {
	return tokens.length;
    };

    this.frequencyOf = function() {
	var end = this._data;

	for (var i=0;i<arguments.length;++i)
	    end = end[arguments[i]];

	return end;
    };

    this.pickOne = function(soFar, upTo) {
	var n = soFar.length;

	var startIndex = n - (predictionContext - 1);
	var obj = this._data;
	for (var i = startIndex; i < upTo; i++) 
	    obj = obj[soFar[i]];

	return this.weightedChoice(obj);
    };

    var pushValuesNTimes = function(obj) {
	var words = [];

	for(var prop in obj) 
	    for (var i=0;i<obj[prop];++i) 
		words.push(prop);

	return words;
    };

    var randomElementFromArray = function(arr) {
	var n = Math.random() * arr.length | 0;
	return arr[n];
    };

    this.weightedChoice = function(obj) {
	var words = pushValuesNTimes(obj);
	return randomElementFromArray(words);
    };

    this.generate = function(startPhrase, len) {
	assert(startPhrase.length === (predictionContext - 1));

	var r = startPhrase;
	for (var i=startPhrase.length;i<len;++i)
	    r[i] = this.pickOne(r,i);

	return r;
    };

    return this;
};

var buildModel = function(predictionContext, source) { 
    return new Model(predictionContext, source); 
};

exports.buildModel = buildModel;

@@ -399,21 +399,16 @@
 +j%5D);%0A%0A%09
-if (!
 obj%5Btoke
@@ -417,23 +417,24 @@
 %5Bi+win%5D%5D
-)%0A%09    
+ = 1 + (
 obj%5Btoke
@@ -447,36 +447,11 @@
 in%5D%5D
- = 0;%0A%0A%09obj%5Btokens%5Bi+win%5D%5D++
+%7C0)
 ;%0A  

take advantage of the fact that {} coerces to 0