var async = require("async");
var dbCollections = require('../../../config/db/dbCollections');
var DateUtility = require('../../../helpers/DateUtility');
var paramInterface = {
username: 'String',
fromDate: 'Number',
toDate: 'Number',
templates: 'Array'
};
/**
* Get all the habit & calendar items that repeats more than once
* @param {Object} DB Database object
* @param {Date} date Get items starting from this date
* @return {Array} List of habit & calendar items that repeats
*/
function getAllRepeatingItems(DB, params, callback) {
params.toDate = new Date().getTime();
var timestampQuery = {};
var username = params.username;
var end = params.toDate;
var query = [
{
$match: {
'user.username': username,
'type': { $in: ['HABT','CLDR'] },
'data.repetition.repeats': {
$in: ['DALY', 'WEEK', 'MTLY', 'ANLY']
},
'isLatest': true
}
},
{
$project: {
_id: 0,
document: "$$ROOT"
}
}
];
console.log('Template query:');
console.dir(JSON.stringify(query));
var templates = [];
function done(err, result) {
if (result !== null) {
templates.push(result.document);
} else {
params.repetitions = templates;
console.log('No. of repeating templates: ' + templates.length);
createAllRepetingItems(DB, params, templates, callback);
}
}
if(DB) {
DB.TemplateClln.aggregate(query).each(done);
}
}
/**
* Create all the habit & calendar items entries till today
* @param {Array} items List of habit and calendar items
* @return {[type]} Update database
*/
function createAllRepetingItems(DB, params, items, callback) {
console.log('No of items being processed: ' + items.length);
var toDate = params.toDate;
var username = params.username;
var templates = [];
var updates = [];
for(var index in items) {
var item = items[index];
var repeats = item.data.repetition.repeats;
var timestamp = item.timestamp;
var isLatest = false;
// CREATE REPETITIONS FOR CURRENT ITEM
var next = {};
/**
* Create next day date incrementing only date,
* keeping the time part untouched
*/
timestamp = getNextDate(repeats, timestamp);
if(timestamp === null) continue;
// Is repetition to be created for this item
if(isRepetitionApplicable(timestamp, toDate)) {
var id = item._id;
// using IIFE to pass correct id
(function(id) {
// Build an array of updates for document whose 'isLatest' is to be updated
updates.push(
function (_callback) {
setLatestRepetitionItem(DB, id, _callback);
}
);
})(id);
}
/**
* Check if repetition being created is till today(toDate).
* Since the toDate changes as per time of the day,
* check day without time.
*/
while(isRepetitionApplicable(timestamp, toDate)) {
// clone item details
next = JSON.parse(JSON.stringify(item));
next.timestamp = timestamp;
next.latertime = timestamp;
next.humantime = DateUtility.getTimeStr(timestamp);
next.humandate = DateUtility.getDateStr(timestamp);
next.user = {'username': params.username};
next.data.isChecked = false;
// Create next day date without time
timestamp = getNextDate(repeats, timestamp);
// Set 'isLatest' as true for the last repetition item
next.isLatest = isRepetitionApplicable(timestamp, toDate) ? false : true;
templates.push(next);
}
}
console.log('No of templates to be created: ' + templates.length);
if(templates.length > 0) {
// Update 'isLatest' to false for all original item used
async.parallel(updates, function(){
console.log('Inserting all templates: ');
insertAllRepetition(DB, templates, callback);
});
}
else {
// COMPLETED PROCESSING
callback();
}
}
/**
* Get next date based upon the repepition interval
* @param {[type]} repetitionType [description]
* @param {[type]} timestamp [description]
* @return {[type]} [description]
*/
function getNextDate(repetitionType, timestamp) {
/**
* Timestamp of next date
* @type {Number}
*/
var nextdate = null;
switch (repetitionType) {
case 'DALY':
nextdate = DateUtility.addDays(timestamp, 1).getTime();
break;
case 'WEEK':
nextdate = DateUtility.addDays(timestamp, 7).getTime();
break;
case 'MTLY':
nextdate = DateUtility.addMonths(timestamp, 1).getTime();
break;
case 'ANLY':
nextdate = DateUtility.addYears(timestamp, 1).getTime();
}
return nextdate;
}
/**
* Is repepition being created is for day till today
* @param {Number} timestamp timestamp of current repetition
* @param {Number} toDate timestamp for current date object
* @return {Boolean} Is repetition falls till today
*/
function isRepetitionApplicable(timestamp, toDate) {
var firstDate = DateUtility.getDateOnly(timestamp).getTime();
var secondDate = DateUtility.getDateOnly(toDate).getTime();
var isApplicable = firstDate <= secondDate;
if(!isApplicable) {
console.log(firstDate + ' <= ' + secondDate + ': ' + false);
}
return isApplicable;
}
/**
* Update 'isLatest' to false for original item used
* for creating the repetition
* @param {Object} DB Database object
* @param {Number} id Unique id of the repetition document
* @return {[type]} Update database
*/
function setLatestRepetitionItem(DB, id, _callback) {
DB.TemplateClln.update({_id: id}, {$set: {isLatest: false, modifiedAt: new Date().getTime()}},
function(err, result) {
if(err) {
console.error(err);
}
else {
console.log("Updated item in TemplateClln for: " + id);
_callback();
}
});
}
/**
* Insert all types of repetitions [DALY, WEEK, MTLY, ANLY] to DB
* @param {Object} DB Database object
* @param {Array} templates Database object array
* @return {[type]} Update database
*/
function insertAllRepetition(DB, templates, callback) {
if(templates.length === 0) {
// COMPLETED PROCESSING
callback();
return;
}
// remove all the id before deletion,
// else the current id would be used by mongodb
// and would result into error
var newtemplates = [];
for(var index in templates) {
var item = templates[index];
// Save parent id, else if new save id
item.parentid = item.parentid ? item.parentid : item._id;
delete item._id;
newtemplates.push(item);
}
DB.TemplateClln.insert(newtemplates, function (err, data) {
if (err) {
console.error(err);
} else {
console.log(data);
// COMPLETED PROCESSING
callback();
}
});
}
/**
* Build repetition based templates
* @return {[type]} Update database based on repetition of templates
*/
function createRepetitionTemplates(DB, params, callback) {
// BUILD HABIT & CALENDAR TILL DATE BEFORE RETRIEVING TEMPLATES
// Get all the habit & calendar items that repeats more than 'ONCE'
getAllRepeatingItems(DB, params, callback);
}
module.exports = {
createRepetitionTemplates: createRepetitionTemplates
};