Source: lib/models/comment.js

const 
		/**
		 * mongoose module
		 * @const
		 */
		mongoose		= require("mongoose"),
		/**
		* errors class module
		*/
		errors				= require("../../bin/errors/errors");

/**
@const
@default
*/
const staticProperties = {
	COLLECTION_NAME: "Comment",
	PRIMARY_KEY: "_id",
};

/** 
* Schema representing a Comment resource.
* @module lib/models/comment
* @require mongoose
* @requires bin/errors/errors
* @requires lib/middleware/mongoose/global-pre-hooks
* @requires lib/middleware/mongoose/mongoose-middleware
* @param {Schema} - The Comment resource schema.
* @param {Object=} - The schema static properties.
* @author Jose Nicolas Mora
*/
var commentSchema = Object.assign(new mongoose.Schema({
	text: String,
	createdAt: { type: Date, default: Date.now},
	author: {
		type: mongoose.Schema.Types.ObjectId,
		ref: "User"
	},
	// parent can be anything
	parent: {
		onModel: String,
		on: {
			type: mongoose.Schema.Types.ObjectId,
			refPath: 'parent.onModel'
		}
	},
	// replies
	comments: [
		{
			type: mongoose.Schema.Types.ObjectId,
			ref: "Comment"
		}
	]
}), staticProperties);

commentSchema.plugin(require("../middleware/mongoose/global-pre-hooks"));

commentSchema.plugin(require("../middleware/mongoose/mongoose-middleware"));

/**
* Removes the Comment resources of a Campground resource.
* @param {Array} The array of Mongoose functions for which this middleware is called.
* @param {Function} The callback function containing the logic of this prehook middleware.
*/
commentSchema.pre(["remove", "deleteOne"], async function() {
	try {
		await this.parent.populate("on").execPopulate(); // populate the parent
		
		const query = {};
		query[this.constructor.schema.PRIMARY_KEY] = this._id;
		await this.parent.on.comments.pull(query);
		await this.parent.on.save();
		
	}
	catch(err) {
		const newError = new Error("There was a problem deleting the campground comment");
		throw new errors.ExtendedError({error: newError, errorCause: err});
	}
});

/**
* Removes the Comment resources of a Campground resource.
* @param {Array} The array of Mongoose functions for which this middleware is called.
* @param {Function} The callback function containing the logic of this prehook middleware.
*/
commentSchema.post(["findOneAndDelete", "findOneAndRemove"], async function(doc, next) {
	try {
		await doc.parent.populate("on").execPopulate(); // populate the parent
		
		const query = {};
		query[doc.constructor.schema.PRIMARY_KEY] = doc._id
		await doc.parent.on.comments.pull(query);
		await doc.parent.on.save();
		
		next();
	}
	catch(err) {
		const newError = new Error("There was a problem deleting the campground comment");
		throw new errors.ExtendedError({error: newError, errorCause: err});
	}
});

/**
* Recursively populate comments.
* @param {module:lib/models/comment[]} The array of comments to be recursively populated.
*/
commentSchema.statics.populateAll = async function (comments) {
	try{			
		for(let comment of comments) {
			await comment.populate("author").execPopulate();
			await comment.populate("comments").execPopulate();
			await comment.constructor.populateAll(	comment.comments);
		}
	}
	catch(err) {
		console.log(err);
		const newError = new Error("There was a problem retreiving comments");
		throw new errors.ExtendedError({error: newError, errorCause: err});
	}
}

module.exports = mongoose.model(commentSchema.COLLECTION_NAME, commentSchema);