magick = function (currData,history) {
if (!history || history.length==0)
return;
const keys = Object.keys(history[0]);
let currentKey = null;
const currDataMap = currData.reduce((a,x) => {
a[x.sFieldID] = x;
if (x.bHasFocus==true)
currentKey = x.sFieldID;
return a;
},{});
const currentlySetData = currData.reduce( (a,x) => {
if (x.value != undefined && x.value.val != undefined)
a[x.sFieldID] = x.value.val;
return a;
},{});
const currentlySetKeys = Object.keys(currentlySetData);
const currentlySetKeysWithoutCurrentKey = currentlySetKeys.filter(x=>x!=currentKey);
const currentlyNotSetKeys = keys.filter(x=>!currentlySetKeys.includes(x));
const bShowCaseCalcAlsoForSetFields = false;
const _incCounter = function(m,key,p) {
if (p==true || p==undefined) p=1;
if (key===null)
{
if (m.empty) m.empty = m.empty+p;
else m.empty=p;
return;
}
if (m.d.hasOwnProperty(key)) m.d[key] = m.d[key]+p;
else m.d[key]=p;
}
const _getCounter = function(m,key) {
if (key===null)
{
if (m.empty) return m.empty;
return 0;
}
if (m.d.hasOwnProperty(key)) return m.d[key];
else return 0;
}
//console.log("start for ");
//console.log(currentlySetData);
let nMatchingHistory = 0;
let nHistory = history.length;
// do the over all counting (at first excluding the current key to append
// complex testing only if the other values matches history)
// this is done in a separate loop to store/cach/flag each history with macht or not match
// to make it faster to go throug relevant history entires for each key later
history.forEach(hd=> {
if (currentKey!=null && currentlySetKeysWithoutCurrentKey.every(curKey => currentlySetData[curKey]==hd[curKey]))
{ // special case for current input:
const a = currentlySetData[currentKey];
const b = hd[currentKey];
let sim = 0;
if (a==null) sim=1;
else if (b!=null) sim = stringSimilarity.compareTwoStrings(String(currentlySetData[currentKey]),String(hd[currentKey]));
//console.log(sim);
const th = 0.1
if (sim>th) {
nMatchingHistory += sim;
hd["___MATCHED"] = sim;
} else {
nMatchingHistory += th/2;
hd["___MATCHED"] = th/2;
}
} else if (currentKey==null && currentlySetKeys.every(curKey => currentlySetData[curKey]==hd[curKey])) {
nMatchingHistory++;
hd["___MATCHED"] = true;
} else {
hd["___MATCHED"] = false;
}
});
/*history.forEach(hd=> {
if (currentlySetKeys.every(curKey => currentlySetData[curKey]==hd[curKey]))
{
nMatchingHistory++;
hd["___MATCHED"] = true;
} else {
// special case for current input:
if (currentKey!=null && currentlySetKeysWithoutCurrentKey.every(curKey => currentlySetData[curKey]==hd[curKey]))
{
const sim = stringSimilarity.compareTwoStrings(currentlySetData[currentKey],hd[currentKey]);
//console.log(sim);
const th = 0.1
if (sim>th) {
nMatchingHistory += sim;
hd["___MATCHED"] = sim;
} else {
nMatchingHistory += th/2;
hd["___MATCHED"] = th/2;
}
}
else
hd["___MATCHED"] = false;
}
});*/
let schemaUpdate = [];
if (!bShowCaseCalcAlsoForSetFields)
schemaUpdate = currentlySetKeysWithoutCurrentKey.reduce((a,key) => {
a.push({sFieldID:key,aOptions:[]});
return a;
},[]);
/* if (nMatchingHistory==0) {
console.log("no matches found");
if (currentKey!=null)
schemaUpdate.push({sFieldID:currentKey,aOptions:[]});
currentlyNotSetKeys.forEach( key => {
schemaUpdate.push({sFieldID:key,aOptions:[]});
});
} else */
{
let keysToCalc = currentlyNotSetKeys;
if (currentKey!=null)
keysToCalc = keysToCalc.concat([currentKey]);
if (bShowCaseCalcAlsoForSetFields) // this is usually not required but for demonstratino purpose its nice to see these resutls aswell
keysToCalc = keys;
keysToCalc.forEach( key => {
if (key=="___MATCHED") return;
// loop all not set fields to figure out how probable it is that they will be selected.
let oOptionChoosenForMatchingHistory = {d:{},empty:0};
let oOptionChoosenInHistoryAtAll = {d:{},empty:0};
history.forEach(hd=> {
// loop complete history
// and check how often each option has been coosen in case of matching precondition ..
if (hd["___MATCHED"]!=false)
{
_incCounter(oOptionChoosenForMatchingHistory,hd[key],hd["___MATCHED"]);
}
// and at all.
_incCounter(oOptionChoosenInHistoryAtAll,hd[key]);
});
/*console.log("key: "+key);
console.log(aOptionsChoosenInHistoryButNotMatching);*/
let aOptionsGreater0 = _getCounter(oOptionChoosenForMatchingHistory,null)>0 ? [{val:null,text:null,prop:_getCounter(oOptionChoosenForMatchingHistory,null)/nMatchingHistory}] : [];
// here in theory one should sort the oOptionChoosenForMatchingHistory to start with options of higher probability.
aOptionsGreater0 = Object.keys(oOptionChoosenForMatchingHistory.d).reduce((a,option) =>
{
if (false) {
console.log("Option: "+option);
console.log("Joined Probability for given data and option: " + oOptionChoosenForMatchingHistory.d[option]/nHistory+"\nProbability for given data: " + nMatchingHistory/nHistory+"\nProbability for that option: " + oOptionChoosenInHistoryAtAll.d[option]/nHistory);
}
a.push({val:option,prop:_getCounter(oOptionChoosenForMatchingHistory,option)/nMatchingHistory});
return a;
/*console.log(nMatchingHistory);
console.log(oOptionChoosenForMatchingHistory[option]);
console.log(oOptionChoosenInHistoryAtAll[option]);*/
},aOptionsGreater0);
aOptionsGreater0.sort((a,b) => b.prop-a.prop);
//let currData.find(
let currFieldSchema = currDataMap[key];
//console.log("key: "+key);
console.log(currFieldSchema);
aOptionsGreater0.forEach(x=>x.text=val2text(currFieldSchema,x.val).text);
console.log(aOptionsGreater0);
let aOptionsChoosenInHistoryButNotMatching = Object.keys(oOptionChoosenInHistoryAtAll.d).filter(x=>!Object.keys(oOptionChoosenForMatchingHistory.d).includes(x));
//console.log(aOptionsChoosenInHistoryButNotMatching);
let aOptionsWith0 = aOptionsChoosenInHistoryButNotMatching.reduce(
(a,x) =>{
a.push({val:x,_p:_getCounter(oOptionChoosenInHistoryAtAll,x),prop:0});
return a
},[]);
aOptionsWith0.sort((a,b) => b._p-a._p);
//console.log(aOptionsWith0);
aOptionsWith0.forEach(x=>x.text=val2text(currFieldSchema,x.val).text);
console.log(aOptionsWith0);
schemaUpdate.push({sFieldID:key,aOptions:aOptionsGreater0.concat(aOptionsWith0)});
});
}
//exampleForm.myUpdateSchema(schemaUpdate)
return schemaUpdate;
}