"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const _ = require("lodash");
const Rule_1 = require("./Rule");
const ValidationException_1 = require("../validation/ValidationException");
class VotersRule extends Rule_1.Rule {
    constructor(mode, usernames) {
        super();
        this.rule = Rule_1.Rule.Type.Voters;
        this.mode = mode;
        this.usernames = usernames;
    }
    type() {
        return Rule_1.Rule.Type.Voters;
    }
    validate(voteorder, context) {
        return __awaiter(this, void 0, void 0, function* () {
            this.validateRuleObject(this);
            let post;
            try {
                post = yield context.getPost();
            }
            catch (e) {
                if (e.notFoundException)
                    throw new ValidationException_1.ValidationException(e.message);
                else
                    throw e;
            }
            const voters = post.active_votes.map(vote => vote.voter);
            if (this.mode === VotersRule.Mode.ONE) { // "one of" mode (every post voter must be within this list)
                for (let i = 0; i < voters.length; i++) {
                    const voter = voters[i];
                    if (this.usernames.indexOf(voter) === -1)
                        throw new ValidationException_1.ValidationException("VotersRule: " + voter + " is not on the allowed voters list [" + this.usernames.join() + "].");
                }
            }
            else if (this.mode === VotersRule.Mode.NONE) { // "none of" aka blacklist mode (none of post voters can be on this list)
                for (let i = 0; i < voters.length; i++) {
                    const voter = voters[i];
                    if (this.usernames.indexOf(voter) !== -1)
                        throw new ValidationException_1.ValidationException("VotersRule: " + voter + " is on the denied voters list [" + this.usernames.join() + "].");
                }
            }
            else if (this.mode === VotersRule.Mode.ALL) { // the post should have all of the specified voters
                for (let i = 0; i < this.usernames.length; i++) {
                    const voter = this.usernames[i];
                    if (voters.indexOf(voter) === -1)
                        throw new ValidationException_1.ValidationException("VotersRule: The post voters [" + voters.join() + "] does not include " + voter + ".");
                }
            }
            else if (this.mode === VotersRule.Mode.ANY) { // the post should have at least one of the specified voters
                for (let i = 0; i < this.usernames.length; i++) {
                    const voter = this.usernames[i];
                    if (voters.indexOf(voter) !== -1) {
                        return;
                    }
                }
                throw new ValidationException_1.ValidationException("VotersRule: None of the voters [" + voters.join() + "] is on the \"any\" voters list [" + this.usernames.join() + "].");
            }
            else
                throw new ValidationException_1.ValidationException("VotersRule: Unknown mode");
        });
    }
    validateRuleObject(unprototypedObj) {
        ["usernames", "mode"].forEach(prop => {
            if (!_.has(unprototypedObj, prop))
                throw new ValidationException_1.ValidationException("VotersRule: property " + prop + " is missing");
        });
        if (!_.includes([VotersRule.Mode.ONE, VotersRule.Mode.NONE, VotersRule.Mode.ANY, VotersRule.Mode.ALL], unprototypedObj.mode))
            throw new ValidationException_1.ValidationException("VotersRule: unknown mode " + unprototypedObj.mode);
    }
    getDescription() {
        if (this.mode === VotersRule.Mode.ALL) {
            return this.usernames.join(", ") + " must all vote for the post";
        }
        else if (this.mode === VotersRule.Mode.NONE) {
            return "None of " + this.usernames.join(", ") + " can vote for the post";
        }
        else if (this.mode === VotersRule.Mode.ONE) {
            return "All voters must be on the list: " + this.usernames.join(", ");
        }
        else if (this.mode === VotersRule.Mode.ANY) {
            return "Any of " + this.usernames.join(", ") + " must vote for the post";
        }
        else {
            return "VotersRule: [Unknown mode " + this.mode + "] voters: " + this.usernames.join(", ");
        }
    }
}
exports.VotersRule = VotersRule;
(function (VotersRule) {
    let Mode;
    (function (Mode) {
        Mode["ONE"] = "one";
        Mode["NONE"] = "none";
        Mode["ANY"] = "any";
        Mode["ALL"] = "all"; // "all of" - all usernames from the list must vote on the post
    })(Mode = VotersRule.Mode || (VotersRule.Mode = {}));
})(VotersRule = exports.VotersRule || (exports.VotersRule = {}));
//# sourceMappingURL=VotersRule.js.map