<commit_before>var resources = require('jest'),
    util = require('util'),
    models = require('../models'),
    async = require('async'),
    common = require('./common'),
    _ = require('underscore'),
    Suggestion = require('./suggestionResource');
notifications = require('./notifications');

//Authorization
var Authoriztion = function () {
};
util.inherits(Authoriztion, resources.Authorization);

Authoriztion.prototype.edit_object = function (req, object, callback) {

    if (req.method == 'POST') {
        models.GradeSuggestion.findOne({suggestion_id:object.suggestion_id + "", user_id:req.user._id}, function (err, obj) {
            if (err) {
                callback(err, null);
            } else {
                if (obj) {
                    callback({message:"user already grade this discussion", code:401}, null);
                } else {
                    object.user_id = req.user._id;
                    callback(null, object);
                }
            }
        })
    } else {
        if (req.method == 'PUT') {
            if (!(object.user_id + "" == req.user._id + ""))
                callback({message:"its not your garde!", code:401}, null);
            else
                callback(null, object);
        } else {
            callback(null, object);
        }
    }
};

var GradeSuggestionResource = module.exports = common.GamificationMongooseResource.extend({
    init:function () {
        this._super(models.GradeSuggestion, 'grade_suggestion', null);
//        GradeResource.super_.call(this,models.Grade);
        this.allowed_methods = ['get', 'put', 'post'];
        this.authorization = new Authoriztion();
        this.authentication = new common.SessionAuthentication();
        this.filtering = {discussion_id:{
            exact:null,
            in:null
        },
            suggestion_id:null
        };
        this.fields = {
            _id:null,

            //just for debuging!!!
            user_id:null,
            suggestion_id:null,
            evaluation_grade:null,
            creation_date:null,
            does_support_the_suggestion:null,
            /////////////////////////////////

            new_grade:null,
            evaluate_counter:null,
//            already_graded: null,
            agrees:null,
            not_agrees:null,
            grade_id:null,

//            wanted_amount_of_tokens: null,
            curr_amount_of_tokens:null,
            is_approved: null
        }
    },

    create_obj:function (req, fields, callback) {
        var self = this;
        var base = this._super;
        var new_grade = null;
        var counter = 0;
        var g_suggestion_obj;
        var is_agree;
        var is_approved;
        var approve_date;
        var replaced_text;
        var discussion_evaluation_grade;
        var agrees;
        var not_agrees;
        //this is agrees - not_agrees, for now...
        var curr_tokens_amout;
        var discussion_id = fields.discussion_id;
        var real_threshold;
        var grade_id;
        var proxy_power = req.user.num_of_given_mandates ? 1 + req.user.num_of_given_mandates * 1 / 9 : 1;
        var discussion_obj;

        async.waterfall([

            //find discussion
            function(cbk){
                models.Discussion.findById(discussion_id, cbk);
            },

            //user can grade suggestion only if he grade the discussion
            function (disc_obj, cbk) {
                discussion_obj = disc_obj;
                models.Grade.findOne({user_id:req.user._id, discussion_id:fields.discussion_id}, cbk);
            },

            function (grade_discussion, cbk) {
                //check if user has graded the discussion first
                //if not - check if the creator of the discussion is the user that is trying to grade
                // (if so - instead of the user discussion_grade we take the evaluated discussion.grade)
                if (!grade_discussion) {

                        //if the creator of the discussion grade the suggestion without grdein the discussion - its ok
                        // otherwise unauthorise
                        if (req.user._id + "" != discussion_obj.creator_id + "")
                            cbk({code:401, message:"must grade discussion first"}, null);
                        else {
                            discussion_evaluation_grade = discussion_obj.grade;
                            is_agree = fields.evaluation_grade >= discussion_evaluation_grade;

                            //check if suggestion is approved (al haderech)

                            //i think there is no need for that, threshold is in suggestion
//                                real_threshold = Number(obj.admin_threshold_for_accepting_change_suggestions) || obj.threshold_for_accepting_change_suggestions;

                            fields.does_support_the_suggestion = is_agree;
                            fields.proxy_power = proxy_power;
                            base.call(self, req, fields, cbk);
                        }

                }
                else {
                    discussion_evaluation_grade = grade_discussion.evaluation_grade;
                    is_agree = fields.evaluation_grade >= discussion_evaluation_grade;
                    fields.does_support_the_suggestion = is_agree;
                    fields.proxy_power = proxy_power;
                    base.call(self, req, fields, cbk);
                }
            },

            function (grade_suggestion_obj, cbk) {
//                is_agree = grade_suggestion_obj.evaluation_grade >= discussion_evaluation_grade;
                grade_id = grade_suggestion_obj._id;

                //update grade suggstoin "does_support_the_suggestion"
                //find suggestion

                models.Suggestion.findById(grade_suggestion_obj.suggestion_id, function (err, sugg) {
                    cbk(err, sugg)
                });
            },

            function (suggestion_obj, cbk) {
                agrees = suggestion_obj.agrees + (Number(is_agree) * proxy_power);
                not_agrees = suggestion_obj.not_agrees + (Number(!is_agree) * proxy_power);

                curr_tokens_amout = Math.round(agrees) - Math.round(not_agrees);

                async.parallel([
                    function (cbk1) {
                        calculateSuggestionGrade(suggestion_obj._id, suggestion_obj.discussion_id, is_agree, null, null, proxy_power, null, function (err, _new_grade, _evaluate_counter) {
                            if (!err) {
                                new_grade = _new_grade;
                                counter = _evaluate_counter;
                            }
                            cbk1(err)
                        });
                    },

                    function (cbk1) {
                        //if there is an admin threshokd specified for the suggestion - it wins

                        real_threshold = Number(suggestion_obj.admin_threshold_for_accepting_the_suggestion) || suggestion_obj.threshold_for_accepting_the_suggestion;

                        if (curr_tokens_amout >= real_threshold) {
                            Suggestion.approveSuggestion(suggestion_obj._id, function (err, obj1, suggestion_object) {
                                if (!err) {
                                    is_approved = true;
                                    replaced_text = suggestion_object.replaced_text;
                                    approve_date = suggestion_object.approve_date;
                                }
                                cbk1(err, obj1);
                            })
                        } else {
                            cbk1();
                        }
                    },
                    //set notification for suggestion creator ("user agree/disagree your suggestion")
                    function (cbk1) {
                        var method;
                        if (is_agree)
                            method = "add";
                        else
                            method = "remove";
                        notifications.create_user_vote_or_grade_notification("user_gave_my_suggestion_tokens",
                            suggestion_obj._id, suggestion_obj.creator_id, req.user._id, discussion_id, method, false, true, '/discussions/' +  discussion_id, function (err, result) {
                                cbk1(err, result);
                            })
                    },

                    //set notifications for all users of proxy
                    function(cbk1){
                        models.User.find({"proxy.user_id": req.user._id}, function(err, slaves_users){
                            async.forEach(slaves_users, function(slave, itr_cbk){
                                notifications.create_user_proxy_vote_or_grade_notification("proxy_graded_change_suggestion", suggestion_obj._id, slave._id, req.user._id, discussion_id, is_agree, null, function(err){
                                    itr_cbk(err);
                                })
                            }, function(err){
                                cbk1(err);
                            })
                        })
                    },

                    //add user to be part of the discussion
                    function(cbk1){
                        if (! _.any(discussion_obj.users, function(user){ return user.user_id + "" == req.user.id})){
                            var new_user = {user_id: req.user._id, join_date: Date.now()};
                            models.Discussion.update({_id: discussion_obj._id}, {$addToSet:{users: new_user}}, function(err, num){cbk1(err, num)});
                        }else{
                            cbk1(null, null);
                        }
                    },

                    // update actions done by user
                    function(cbk1){
                        models.User.update({_id:req.user.id},{$set: {"actions_done_by_user.grade_object": true}}, function(err){
                            cbk1(err);
                        });
                    }
                ], function (err, args) {
                    cbk(err, args);
                })
            }

        ], function (err, obj) {
            if (!err) {
                req.gamification_type = "grade_suggestion";
                req.token_price = common.getGamificationTokenPrice('grade_suggestion') > -1 ? common.getGamificationTokenPrice('grade_suggestion') : 0;
            }
            callback(err, {
                grade_id:grade_id,
                new_grade:new_grade,
                evaluate_counter:counter,
//                    already_graded: true,
                agrees: agrees,
                not_agrees:not_agrees,
//                    wanted_amount_of_tokens: real_threshold,
                curr_amount_of_tokens:curr_tokens_amout,
                is_approved: is_approved,
                replaced_text: replaced_text,
                approve_date: approve_date
            });
        })
    },

    update_obj:function (req, object, callback) {
        console.log('in update grade suggestion');
        var self = this;
        var base = this._super;
        var g_grade;
        var discussion_id = req.body.discussion_id;
        var is_agree;
        var discussion_evaluation_grade;
        var did_user_change_his_agree;
        var new_grade, evaluate_counter;
        var grade_id = object._id;
        var agrees;
        var not_agrees;
        var curr_tokens_amout;
        var real_threshold;
        var g_sugg_obj;
        var proxy_power = req.user.num_of_given_mandates ? 1 + req.user.num_of_given_mandates * 1 / 9 : 1;
        var previous_proxy_power = object.proxy_power || proxy_power;

        async.waterfall([

            //find the limit of between agree and not agree
            function (cbk) {
                models.Discussion.findById(discussion_id, cbk);
            },

            function (discussion_obj, cbk) {
                real_threshold = Number(discussion_obj.admin_threshold_for_accepting_change_suggestions) || discussion_obj.threshold_for_accepting_change_suggestions;

                if (discussion_obj.creator_id + "" == req.user._id + "") {
                    discussion_evaluation_grade = discussion_obj.grade;
                    is_agree = object.evaluation_grade >= discussion_evaluation_grade;
                    models.Suggestion.findById(object.suggestion_id, cbk);
                }
                else
                    models.Grade.findOne({discussion_id:discussion_id, user_id:req.user._id || object.user_id}, function (err, grade_discussion) {
                        if (!err && grade_discussion) {
                            discussion_evaluation_grade = grade_discussion.evaluation_grade;
                            is_agree = object.evaluation_grade >= discussion_evaluation_grade;
                            models.Suggestion.findById(object.suggestion_id, cbk);
                        }else{
                            cbk({message: "please grade the discussion", code: 401});
                        }
                    });
            },

            function (sugg_obj, cbk) {
                var method;
                g_sugg_obj = sugg_obj;



                agrees = sugg_obj.agrees;
                not_agrees = sugg_obj.not_agrees;

                curr_tokens_amout = Math.round(agrees) - Math.round(not_agrees);

                did_user_change_his_agree = object.does_support_the_suggestion != is_agree;
                object.does_support_the_suggestion = is_agree;
                if (did_user_change_his_agree) {
                    if (is_agree)
                        method = "add";
                    else
                        method = "remove"
                }
                async.parallel([

                    function (cbk1) {
                        if(did_user_change_his_agree){
                            if(sugg_obj.creator_id){
                                notifications.create_user_vote_or_grade_notification("user_gave_my_suggestion_tokens",
                                    sugg_obj._id, sugg_obj.creator_id, req.user._id, discussion_id, method, did_user_change_his_agree, true, '/discussions/' +  discussion_id, function (err, result) {
                                        cbk1(err, result);
                                    })
                            }else{
                                console.log('this suggestion - id number ' +  sugg_obj.creator_id + 'doesnt have creator id!!!')
                                cbk1(null, 0);
                            }

                        }else{
                            cbk1(null, 0);
                        }
                    },

                    function (cbk1) {
                        object.proxy_power = proxy_power;

                        if(object.agrees < 0){
                            object.agrees = 0;
                            console.log("error - suggestion agrees < 0");
                        }

                        if(object.not_agrees < 0){
                            object.not_agrees = 0;
                            console.log("error - suggestion agrees < 0");
                        }

                        base.call(self, req, object, cbk1);
                    },

                    //set notifications for all users of proxy
                    function(cbk1){
                        if (did_user_change_his_agree) {
                            models.User.find({"proxy.user_id": req.user._id}, function(err, slaves_users){
                                async.forEach(slaves_users, function(slave, itr_cbk){
                                    notifications.create_user_proxy_vote_or_grade_notification("proxy_graded_change_suggestion",  sugg_obj._id, slave._id, req.user._id, discussion_id, is_agree, null, function(err){
                                        itr_cbk(err);
                                    })
                                }, function(err){
                                    cbk1(err);
                                })
                            })
                        }else{
                            cbk1(null, null);
                        }
                    }
                ], function (err, args) {
                    cbk(err, args[1]);
                })
            },

            function (grade_sugg_object, cbk) {
//                g_grade = grade_sugg_object;

                calculateSuggestionGrade(object.suggestion_id, discussion_id, is_agree, did_user_change_his_agree, null, proxy_power, previous_proxy_power, function (err, _new_grade, _evaluate_counter) {
                    if (!err) {
                        new_grade = _new_grade;
                        evaluate_counter = _evaluate_counter;

                        if (did_user_change_his_agree) {
                            if (is_agree) {
                                agrees = g_sugg_obj.agrees + (1 * proxy_power);
                                not_agrees = g_sugg_obj.not_agrees - (1 * previous_proxy_power);
                                curr_tokens_amout = Math.round(agrees) - Math.round(not_agrees);

                            }
                            else {
                                agrees = g_sugg_obj.agrees - (1 * previous_proxy_power);
                                not_agrees = g_sugg_obj.not_agrees + (1 * proxy_power);
                                curr_tokens_amout = Math.round(agrees) - Math.round(not_agrees);
                            }

                            //if there is an admin threshokd specified for the suggestion - it wins

                            real_threshold = Number(g_sugg_obj.admin_threshold_for_accepting_the_suggestion) || g_sugg_obj.threshold_for_accepting_the_suggestion;

                            if (curr_tokens_amout >= real_threshold) {
                                Suggestion.approveSuggestion(g_sugg_obj._id, function (err, obj1) {
                                    cbk(err, obj1);
                                })
                            } else {<commit_msg>check if sugg threshold is bigger then participants of discussion when grading sugg<commit_after>var resources = require('jest'),
    util = require('util'),
    models = require('../models'),
    async = require('async'),
    common = require('./common'),
    _ = require('underscore'),
    Suggestion = require('./suggestionResource');
notifications = require('./notifications');

//Authorization
var Authoriztion = function () {
};
util.inherits(Authoriztion, resources.Authorization);

Authoriztion.prototype.edit_object = function (req, object, callback) {

    if (req.method == 'POST') {
        models.GradeSuggestion.findOne({suggestion_id:object.suggestion_id + "", user_id:req.user._id}, function (err, obj) {
            if (err) {
                callback(err, null);
            } else {
                if (obj) {
                    callback({message:"user already grade this discussion", code:401}, null);
                } else {
                    object.user_id = req.user._id;
                    callback(null, object);
                }
            }
        })
    } else {
        if (req.method == 'PUT') {
            if (!(object.user_id + "" == req.user._id + ""))
                callback({message:"its not your garde!", code:401}, null);
            else
                callback(null, object);
        } else {
            callback(null, object);
        }
    }
};

var GradeSuggestionResource = module.exports = common.GamificationMongooseResource.extend({
    init:function () {
        this._super(models.GradeSuggestion, 'grade_suggestion', null);
//        GradeResource.super_.call(this,models.Grade);
        this.allowed_methods = ['get', 'put', 'post'];
        this.authorization = new Authoriztion();
        this.authentication = new common.SessionAuthentication();
        this.filtering = {discussion_id:{
            exact:null,
            in:null
        },
            suggestion_id:null
        };
        this.fields = {
            _id:null,

            //just for debuging!!!
            user_id:null,
            suggestion_id:null,
            evaluation_grade:null,
            creation_date:null,
            does_support_the_suggestion:null,
            /////////////////////////////////

            new_grade:null,
            evaluate_counter:null,
//            already_graded: null,
            agrees:null,
            not_agrees:null,
            grade_id:null,

//            wanted_amount_of_tokens: null,
            curr_amount_of_tokens:null,
            is_approved: null
        }
    },

    create_obj:function (req, fields, callback) {
        var self = this;
        var base = this._super;
        var new_grade = null;
        var counter = 0;
        var g_suggestion_obj;
        var is_agree;
        var is_approved;
        var approve_date;
        var replaced_text;
        var discussion_evaluation_grade;
        var agrees;
        var not_agrees;
        //this is agrees - not_agrees, for now...
        var curr_tokens_amout;
        var discussion_id = fields.discussion_id;
        var real_threshold;
        var grade_id;
        var proxy_power = req.user.num_of_given_mandates ? 1 + req.user.num_of_given_mandates * 1 / 9 : 1;
        var discussion_obj;
        var discussion_participants_count;

        async.waterfall([

            //find discussion
            function(cbk){
                models.Discussion.findById(discussion_id, cbk);
            },

            //user can grade suggestion only if he grade the discussion
            function (disc_obj, cbk) {
                discussion_participants_count = discussion_obj.users.length;
                discussion_obj = disc_obj;
                models.Grade.findOne({user_id:req.user._id, discussion_id:fields.discussion_id}, cbk);
            },

            function (grade_discussion, cbk) {
                //check if user has graded the discussion first
                //if not - check if the creator of the discussion is the user that is trying to grade
                // (if so - instead of the user discussion_grade we take the evaluated discussion.grade)
                if (!grade_discussion) {

                        //if the creator of the discussion grade the suggestion without grdein the discussion - its ok
                        // otherwise unauthorise
                        if (req.user._id + "" != discussion_obj.creator_id + "")
                            cbk({code:401, message:"must grade discussion first"}, null);
                        else {
                            discussion_evaluation_grade = discussion_obj.grade;
                            is_agree = fields.evaluation_grade >= discussion_evaluation_grade;

                            //check if suggestion is approved (al haderech)

                            //i think there is no need for that, threshold is in suggestion
//                                real_threshold = Number(obj.admin_threshold_for_accepting_change_suggestions) || obj.threshold_for_accepting_change_suggestions;

                            fields.does_support_the_suggestion = is_agree;
                            fields.proxy_power = proxy_power;
                            base.call(self, req, fields, cbk);
                        }

                }
                else {
                    discussion_evaluation_grade = grade_discussion.evaluation_grade;
                    is_agree = fields.evaluation_grade >= discussion_evaluation_grade;
                    fields.does_support_the_suggestion = is_agree;
                    fields.proxy_power = proxy_power;
                    base.call(self, req, fields, cbk);
                }
            },

            function (grade_suggestion_obj, cbk) {
//                is_agree = grade_suggestion_obj.evaluation_grade >= discussion_evaluation_grade;
                grade_id = grade_suggestion_obj._id;

                //update grade suggstoin "does_support_the_suggestion"
                //find suggestion

                models.Suggestion.findById(grade_suggestion_obj.suggestion_id, function (err, sugg) {
                    cbk(err, sugg)
                });
            },

            function (suggestion_obj, cbk) {
                agrees = suggestion_obj.agrees + (Number(is_agree) * proxy_power);
                not_agrees = suggestion_obj.not_agrees + (Number(!is_agree) * proxy_power);

                curr_tokens_amout = Math.round(agrees) - Math.round(not_agrees);

                async.parallel([
                    function (cbk1) {
                        calculateSuggestionGrade(suggestion_obj._id, suggestion_obj.discussion_id, is_agree, null, null, proxy_power, null, function (err, _new_grade, _evaluate_counter) {
                            if (!err) {
                                new_grade = _new_grade;
                                counter = _evaluate_counter;
                            }
                            cbk1(err)
                        });
                    },

                    function (cbk1) {
                        //if there is an admin threshokd specified for the suggestion - it wins

                        real_threshold = Number(suggestion_obj.admin_threshold_for_accepting_the_suggestion) || suggestion_obj.threshold_for_accepting_the_suggestion;
                        if (Number(suggestion_obj.wanted_amount_of_tokens) > discussion_participants_count)
                            real_threshold = discussion_participants_count - 1;

                        if (curr_tokens_amout >= real_threshold) {
                            Suggestion.approveSuggestion(suggestion_obj._id, function (err, obj1, suggestion_object) {
                                if (!err) {
                                    is_approved = true;
                                    replaced_text = suggestion_object.replaced_text;
                                    approve_date = suggestion_object.approve_date;
                                }
                                cbk1(err, obj1);
                            })
                        } else {
                            cbk1();
                        }
                    },
                    //set notification for suggestion creator ("user agree/disagree your suggestion")
                    function (cbk1) {
                        var method;
                        if (is_agree)
                            method = "add";
                        else
                            method = "remove";
                        notifications.create_user_vote_or_grade_notification("user_gave_my_suggestion_tokens",
                            suggestion_obj._id, suggestion_obj.creator_id, req.user._id, discussion_id, method, false, true, '/discussions/' +  discussion_id, function (err, result) {
                                cbk1(err, result);
                            })
                    },

                    //set notifications for all users of proxy
                    function(cbk1){
                        models.User.find({"proxy.user_id": req.user._id}, function(err, slaves_users){
                            async.forEach(slaves_users, function(slave, itr_cbk){
                                notifications.create_user_proxy_vote_or_grade_notification("proxy_graded_change_suggestion", suggestion_obj._id, slave._id, req.user._id, discussion_id, is_agree, null, function(err){
                                    itr_cbk(err);
                                })
                            }, function(err){
                                cbk1(err);
                            })
                        })
                    },

                    //add user to be part of the discussion
                    function(cbk1){
                        if (! _.any(discussion_obj.users, function(user){ return user.user_id + "" == req.user.id})){
                            var new_user = {user_id: req.user._id, join_date: Date.now()};
                            models.Discussion.update({_id: discussion_obj._id}, {$addToSet:{users: new_user}}, function(err, num){cbk1(err, num)});
                        }else{
                            cbk1(null, null);
                        }
                    },

                    // update actions done by user
                    function(cbk1){
                        models.User.update({_id:req.user.id},{$set: {"actions_done_by_user.grade_object": true}}, function(err){
                            cbk1(err);
                        });
                    }
                ], function (err, args) {
                    cbk(err, args);
                })
            }

        ], function (err, obj) {
            if (!err) {
                req.gamification_type = "grade_suggestion";
                req.token_price = common.getGamificationTokenPrice('grade_suggestion') > -1 ? common.getGamificationTokenPrice('grade_suggestion') : 0;
            }
            callback(err, {
                grade_id:grade_id,
                new_grade:new_grade,
                evaluate_counter:counter,
//                    already_graded: true,
                agrees: agrees,
                not_agrees:not_agrees,
//                    wanted_amount_of_tokens: real_threshold,
                curr_amount_of_tokens:curr_tokens_amout,
                is_approved: is_approved,
                replaced_text: replaced_text,
                approve_date: approve_date
            });
        })
    },

    update_obj:function (req, object, callback) {
        console.log('in update grade suggestion');
        var self = this;
        var base = this._super;
        var g_grade;
        var discussion_id = req.body.discussion_id;
        var is_agree;
        var discussion_evaluation_grade;
        var did_user_change_his_agree;
        var new_grade, evaluate_counter;
        var grade_id = object._id;
        var agrees;
        var not_agrees;
        var curr_tokens_amout;
        var real_threshold;
        var g_sugg_obj;
        var proxy_power = req.user.num_of_given_mandates ? 1 + req.user.num_of_given_mandates * 1 / 9 : 1;
        var previous_proxy_power = object.proxy_power || proxy_power;
        var discussion_participants_count;

        async.waterfall([

            //find the limit of between agree and not agree
            function (cbk) {
                models.Discussion.findById(discussion_id, cbk);
            },

            function (discussion_obj, cbk) {
                discussion_participants_count = discussion_obj.users.length;
                real_threshold = Number(discussion_obj.admin_threshold_for_accepting_change_suggestions) || discussion_obj.threshold_for_accepting_change_suggestions;

                if (discussion_obj.creator_id + "" == req.user._id + "") {
                    discussion_evaluation_grade = discussion_obj.grade;
                    is_agree = object.evaluation_grade >= discussion_evaluation_grade;
                    models.Suggestion.findById(object.suggestion_id, cbk);
                }
                else
                    models.Grade.findOne({discussion_id:discussion_id, user_id:req.user._id || object.user_id}, function (err, grade_discussion) {
                        if (!err && grade_discussion) {
                            discussion_evaluation_grade = grade_discussion.evaluation_grade;
                            is_agree = object.evaluation_grade >= discussion_evaluation_grade;
                            models.Suggestion.findById(object.suggestion_id, cbk);
                        }else{
                            cbk({message: "please grade the discussion", code: 401});
                        }
                    });
            },

            function (sugg_obj, cbk) {
                var method;
                g_sugg_obj = sugg_obj;



                agrees = sugg_obj.agrees;
                not_agrees = sugg_obj.not_agrees;

                curr_tokens_amout = Math.round(agrees) - Math.round(not_agrees);

                did_user_change_his_agree = object.does_support_the_suggestion != is_agree;
                object.does_support_the_suggestion = is_agree;
                if (did_user_change_his_agree) {
                    if (is_agree)
                        method = "add";
                    else
                        method = "remove"
                }
                async.parallel([

                    function (cbk1) {
                        if(did_user_change_his_agree){
                            if(sugg_obj.creator_id){
                                notifications.create_user_vote_or_grade_notification("user_gave_my_suggestion_tokens",
                                    sugg_obj._id, sugg_obj.creator_id, req.user._id, discussion_id, method, did_user_change_his_agree, true, '/discussions/' +  discussion_id, function (err, result) {
                                        cbk1(err, result);
                                    })
                            }else{
                                console.log('this suggestion - id number ' +  sugg_obj.creator_id + 'doesnt have creator id!!!')
                                cbk1(null, 0);
                            }

                        }else{
                            cbk1(null, 0);
                        }
                    },

                    function (cbk1) {
                        object.proxy_power = proxy_power;

                        if(object.agrees < 0){
                            object.agrees = 0;
                            console.log("error - suggestion agrees < 0");
                        }

                        if(object.not_agrees < 0){
                            object.not_agrees = 0;
                            console.log("error - suggestion agrees < 0");
                        }

                        base.call(self, req, object, cbk1);
                    },

                    //set notifications for all users of proxy
                    function(cbk1){
                        if (did_user_change_his_agree) {
                            models.User.find({"proxy.user_id": req.user._id}, function(err, slaves_users){
                                async.forEach(slaves_users, function(slave, itr_cbk){
                                    notifications.create_user_proxy_vote_or_grade_notification("proxy_graded_change_suggestion",  sugg_obj._id, slave._id, req.user._id, discussion_id, is_agree, null, function(err){
                                        itr_cbk(err);
                                    })
                                }, function(err){
                                    cbk1(err);
                                })
                            })
                        }else{
                            cbk1(null, null);
                        }
                    }
                ], function (err, args) {
                    cbk(err, args[1]);
                })
            },

            function (grade_sugg_object, cbk) {
//                g_grade = grade_sugg_object;

                calculateSuggestionGrade(object.suggestion_id, discussion_id, is_agree, did_user_change_his_agree, null, proxy_power, previous_proxy_power, function (err, _new_grade, _evaluate_counter) {
                    if (!err) {
                        new_grade = _new_grade;
                        evaluate_counter = _evaluate_counter;

                        if (did_user_change_his_agree) {
                            if (is_agree) {
                                agrees = g_sugg_obj.agrees + (1 * proxy_power);
                                not_agrees = g_sugg_obj.not_agrees - (1 * previous_proxy_power);
                                curr_tokens_amout = Math.round(agrees) - Math.round(not_agrees);

                            }
                            else {
                                agrees = g_sugg_obj.agrees - (1 * previous_proxy_power);
                                not_agrees = g_sugg_obj.not_agrees + (1 * proxy_power);
                                curr_tokens_amout = Math.round(agrees) - Math.round(not_agrees);
                            }

                            //if there is an admin threshokd specified for the suggestion - it wins

                            real_threshold = Number(g_sugg_obj.admin_threshold_for_accepting_the_suggestion) || g_sugg_obj.threshold_for_accepting_the_suggestion;
                            if (Number(g_sugg_obj.wanted_amount_of_tokens) > discussion_participants_count)
                                real_threshold = discussion_participants_count - 1;
                            if (s >= real_threshold) {
                                Suggestion.approveSuggestion(g_sugg_obj._id, function (err, obj1) {
                                    cbk(err, obj1);
                                })
                            } else {
{'fraction_non_alphanumeric': 0.08428974600188147, 'fraction_numerical': 0.003440397795995162, 'mean_word_length': 1.2870666338824686, 'pattern_counts': {'":': 6, '<': 11, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 28, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6486659', 'n_tokens_mistral': 9800, 'n_tokens_neox': 9034, 'n_words': 1738}