/**
 * job.js
 * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
 *
 * Contact:
 * DongHee Yang <donghee.yang@samsung.com>
 * Sungmin Kim <sm.art.kim@samsung.com>
 * Jiil Hyoun <jiil.hyoun@samsung.com>
 * Jonghwan Park <iwin100.park@samsung.com>
 * Kitae Kim <kt920.kim@samsung.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Contributors:
 * - S-Core Co., Ltd
**/

var async = require('async');
var _ = require('underscore');
var util = require('util');
var DError = require('../../core/exception.js');
var utils = require('../../lib/utils.js');
var dibs = require('../../core/dibs.js');
var Project = require('./project.js');
var QueryParser = require('./query-parser.js');

/**
 * @module models/job
 */

/**
 * @callback callback_err_jobid
 * @param {error|undefined} error
 * @param {string} job_id - job id
 * @memberOf module:models/job
 */

/**
 * @function insert
 * @param {string} conn - db connection
 * @param {module:models/job~Job} job - job
 * @param {module:models/job.callback_err_jobid} callback - callback
 * @memberOf module:models/job
 */


/**
 * @function transaction
 * @private
 * @param {string} conn - db connection
 * @param {function} func - user anonymous function(callback) : callback(err, data);
 * @param {module:models/job.callback_err_jobid} callback - callback
 * @memberOf module:models/job
 */

function transaction(conn, func, callback) {
    var result = null;
    async.waterfall([
        function (wcb) {
            conn.query('START TRANSACTION', function (err) {
                wcb(err);
            });
        },
        function (wcb) {
            func(wcb);
        },
        function (res, wcb) {
            result = res;
            conn.query('COMMIT', wcb);
        }
    ], function (err) {
        if (err) {
            conn.query('ROOLBACK', function () {});
        }
        callback(err, result);
    });
}

function updateInfo(conn, job, callback) {
    var insert = _.clone(job.options);
    var update = {};
    async.waterfall([
        function (wcb) {
            var sql = 'SELECT job_info.property, job_info.value, job_info.type FROM job_info WHERE job_id = ' + job.id + ';';
            conn.query(sql, function (err, data) {
                wcb(err, data);
            });
        },
        function (jobInfos, wcb) {
            // 1. fill insert options and update options
            _.each(jobInfos, function (info) {
                // if option has job_info.property then option.property is candidate of update
                if (insert[info.property] !== undefined) {
                    var strNtype = utils.objectToStringAndType(insert[info.property]);
                    // if option.property not same as job_info.property then that must be update
                    if (strNtype.string != info.value || strNtype.type != info.type) {
                        update[info.property] = insert[info.property];
                    }
                    insert = _.omit(insert, info.property);
                }
            });
            wcb(null);
        },
        function (wcb) {
            //2. run update options
            var updateSql = [];
            _.each(update, function (value, property) {
                var strNtype = utils.objectToStringAndType(value);
                updateSql.push('UPDATE job_info SET  value =' + utils.DBStr(strNtype.string) + ', type = ' + utils.DBStr(strNtype.type) + ' WHERE job_id = ' + job.id + ' and property = ' + utils.DBStr(property) + ';');
            });
            async.eachSeries(updateSql, function (sql, ecb) {
                conn.query(sql, function (err) {
                    ecb(err);
                });
            }, function (err) {
                wcb(err);
            });
        },
        function (wcb) {
            //2. run insert options
            var insertSql = [];
            _.each(insert, function (value, property) {
                var strNtype = utils.objectToStringAndType(value);
                insertSql.push('INSERT INTO job_info SET job_id =' + job.id + ', property =' + utils.DBStr(property) + ', value =' + utils.DBStr(strNtype.string) + ', type = ' + utils.DBStr(strNtype.type) + ';');
            });
            async.eachSeries(insertSql, function (sql, ecb) {
                conn.query(sql, function (err) {
                    ecb(err);
                });
            }, function (err) {
                wcb(err);
            });
        }
    ], callback);
}

// callback( err, insertId )
module.exports.insert = function (conn, job, callback) {
    var id = null;
    async.waterfall([
        function (wcb) {
            conn.query('START TRANSACTION', function (err) {
                wcb(err);
            });
        },
        function (wcb) {
            var sql = 'SELECT * FROM distributions WHERE name = ' + utils.DBStr(job.distName);
            conn.query(sql, function (err, result) {
                if (err) {
                    wcb(err, null);
                } else if (result.length === 0) {
                    //TO-DO
                    wcb(new DError('JOB001', {
                        dist: job.distName
                    }), null);
                } else {
                    wcb(err, result[0].type);
                }
            });
        },
        function (distType, wcb) {
            var statusInfo = util.isString(job.statusInfo) ? job.statusInfo.toString().substring(0, 1023) : util.inspect(job.statusInfo);
            var sql = 'INSERT INTO jobs SET ' +
                'user_email =' + utils.DBStr(job.userEmail) + ', ' +
                'distribution_name =' + utils.DBStr(job.distName) + ', ' +
                'distribution_type =' + utils.DBStr(distType) + ', ' +
                (job.projectName ?
                    ('project_name =' + utils.DBStr(job.projectName) + ', ') :
                    ('project_name = NULL, ')) +
                'project_type =' + utils.DBStr(job.projectType) + ', ' +
                (job.environmentName ?
                    ('environment_name =' + utils.DBStr(job.environmentName) + ', ') :
                    ('environment_name = NULL, ')) +
                'parent_id =' + job.parentId + ', ' +
                'type =' + utils.DBStr(job.type) + ', ' +
                'status =' + utils.DBStr(job.status) + ',' +
                'status_info =' + utils.DBStr(statusInfo) + ',' +
                'start_time = ' + utils.DBStr(job.startTime) + ';';
            conn.query(sql, function (err, result) {
                wcb(err, result);
            });
        },
        // query user group for adding to job-info
        function (result1, wcb) {
            queryUserGroups(conn, job, function (err, groups) {
                if (!err) {
                    job.options.USER_GROUPS = groups;
                }
                wcb(err, result1);
            });
        },
        function (result1, wcb) {
            id = result1.insertId;
            if (_.size(job.options) !== 0) {
                async.map(_.keys(job.options),
                    function (index, mcb) {
                        var strNtype = utils.objectToStringAndType(job.options[index]);
                        var sql = 'INSERT INTO job_info SET ' +
                            'job_id =' + id +
                            ', property = ' + utils.DBStr(index) +
                            ', value = ' + utils.DBStr(strNtype.string) +
                            ', type = ' + utils.DBStr(strNtype.type);
                        conn.query(sql, mcb);
                    }, function (err, result) {
                        wcb(err);
                    });
            } else {
                wcb(null);
            }
        },
        function (wcb) {
            conn.query('COMMIT', wcb);
        }
    ], function (err) {
        if (err) {
            conn.query('ROLLBACK', function () {});
        }
        callback(err, id);
    });
};


function queryUserGroups(conn, job, callback) {
    var sql = 'SELECT groups.name FROM users,groups,user_group  WHERE users.email = ' +
        utils.DBStr(job.userEmail) +
        ' AND users.id = user_group.user_id AND groups.id = user_group.group_id';

    conn.query(sql, function (err, result) {
        if (err) {
            callback(err, null);
        } else {
            callback(err, result.map(function (e) {
                return e.name;
            }));
        }
    });
}


/**
 * @function updateStatus
 * @param {object} conn - db connection object
 * @param {module:models/job~Job} job - job object
 * @param {module:lib/utils.callback_error} callback - callback
 * @memberOf module:models/job
 */

// callback( err)
module.exports.updateStatus = function (conn, job, callback) {
    var statusInfo = util.isString(job.statusInfo) ? job.statusInfo.toString().substring(0, 1023) : util.inspect(job.statusInfo);

    conn.query('START TRANSACTION', function (err) {
        if (err) {
            callback(new DError('MODEL001', err), null);
            return;
        }

        async.series([
            function (cb) {
                conn.query('UPDATE jobs SET ' +
                'status =' + utils.DBStr(job.status) +
                ', status_info =' + utils.DBStr(statusInfo) +
                ', error_code =' + utils.DBStr(job.error_code) +
                ', start_time = ' + utils.DBStr(job.startTime) +
                ', end_time = ' + utils.DBStr(job.endTime) +
                ', snapshot_name = ' + utils.DBStr(job.snapshotName) +
                ', init_server_id = ' +
                (job.initServerId ? utils.DBStr(job.initServerId) : 'NULL') +
                ', exec_server_id = ' +
                (job.execServerId ? utils.DBStr(job.execServerId) : 'NULL') +
                ', approval_id = ' +
                (job.approvalId ? job.approvalId : 'NULL') +
                ', description = ' + utils.DBStr(job.description) +
                ' WHERE ' + 'id = ' + job.id,
                    function (err) {
                        cb(err);
                    }
                );
            },
            function (cb) {
                updateInfo(conn, job, function (err) {
                    cb(err);
                });
            },
            function (cb) {
                async.eachSeries(job.board, function (board, ecb) {
                    conn.query('INSERT INTO job_board (job_id, time, type, name)' +
                    'VALUES (' + job.id + ', ' + utils.DBStr(board.time) + ', ' + utils.DBStr(board.type) + ', ' + utils.DBStr(board.name) + ')',
                        function (err) {
                            ecb(err);
                        });
                }, cb);
            },
            // commit sql
            function (cb) {
                conn.query('COMMIT', function (err) {
                    if (err) {
                        callback(new DError('MODEL002', err), null);
                        return;
                    }
                    cb(err);
                });
            }
        ],
            function (err, result) {
                if (err) {
                    conn.query('ROLLBACK', function () {});
                    callback(new DError('MODEL002', err), null);
                    return;
                }
                callback(err, result);
            });
    });
};


/**
 * Overwrite source job to destination job
 * @function copy
 * @param {module:models/job~Job} dst - destination job
 * @param {module:models/job~Job} src - source job
 * @returns {undefined}
 * @memberOf module:models/job
 */


module.exports.copy = function (dst, src) {
    dst.id = src.id;
    dst.userEmail = src.userEmail;
    dst.distName = src.distName;
    dst.distType = src.distType;
    dst.projectName = src.projectName;
    dst.projectType = src.projectType;
    dst.environmentName = src.environmentName;
    dst.initEnvironments = src.initEnvironments;
    dst.execEnvironments = src.execEnvironments;
    dst.parentId = src.parentId;
    dst.type = src.type;
    dst.status = src.status;
    dst.statusInfo = src.statusInfo;
    dst.startTime = src.startTime;
    dst.endTime = src.endTime;
    dst.errorCode = src.errorCode;
    dst.snapshotName = src.snapshotName;
    dst.initServerId = src.initServerId;
    dst.execServerId = src.execServerId;
    dst.description = src.description;
    dst.children = src.children;
    dst.depJobs = src.depJobs;
    dst.subJobs = src.subJobs;
    if (dst.options) {
        dst.options = _.extend(src.options, dst.options);
    } else {
        dst.options = src.options;
    }
    dst.board = src.board;
};

/**
 * @typedef {object} options
 * @property {string} key - key : value format Hash object for job option
 * @memberOf module:models/job
 */

/**
 *
 * @constructor
 * @param {string} project_name - project name
 * @param {string} project_type - project type
 * @param {string} distName - distribution name
 * @param {module:models/job.options} options - job options
 */

// NOTE. TO add new fields, you must add them to above copy operation
function Job(userEmail, distName, distType, projectName, projectType, environmentName, parentId, type, options) {
    /** @type {number} */
    this.id = null;
    /** @type {string} */
    this.userEmail = userEmail;
    /** @type {string} */
    this.distName = distName;
    /** @type {string} */
    this.distType = distType;
    /** @type {string} */
    this.projectName = projectName;
    /** @type {string} */
    this.projectType = projectType;
    /** @type {string} */
    this.environmentName = environmentName;
    /** @type {object} */
    this.initEnvironments = null;
    /** @type {object} */
    this.execEnvironments = null;
    /** @type {number} */
    this.parentId = parentId || null;
    /** @type {string} */
    this.type = type || '';
    /**
     * job status: (JUST_CREATE/WORKING/FINISHED/ERROR/CANCELED)
     * @type {string}
     */
    this.status = 'JUST_CREATED';
    /** @statusInfo {string} */
    this.statusInfo = '';
    /** @startTime {string} */
    this.startTime = '';
    /** @endTime {string} */
    this.endTime = '';
    /** @errorCode {string} */
    this.errorCode = '';
    /** @snapshotName {string} */
    this.snapshotName = '';
    /** @initServerId {string} */
    this.initServerId = null;
    /** @execServerId {string} */
    this.execServerId = null;
    /** @approvalId {number} */
    this.approvalId = null;
    /** @description {string} */
    this.description = '';
    /** @type {object} */
    this.children = [];
    /** @type {object} */
    this.subJobs = [];
    /** @type {object} */
    this.depJobs = [];
    /** @type {string} */
    this.board = [];
    /** @type {string} */
    this.options = options;
}


/**
 * @function create
 * @param {string} project_name - project name
 * @param {string} project_type - project type
 * @param {module:models/job.options} options - job options
 * @returns {module:models/job~Job}
 * @memberOf module:models/job
 */

function create(userEmail, distName, distType, projectName, projectType, environmentName, parentId, type, options, callback) {
    callback(null, new Job(userEmail, distName, distType, projectName, projectType, environmentName, parentId, type, options));
}

module.exports.create = create;

/**
 * @callback callback_err_joblist
 * @param {error|undefined} error
 * @param {Array.<module:models/job~Job>} jobList
 * @memberOf module:models/job
 */

/**
 * @typedef {object} jobQuerySql
 * @property {string} id
 * @property {string} project_name
 * @property {string} project_type
 * @property {string} user_email
 * @property {string} status
 * @property {string} count
 * @property {string} offset
 * @memberOf module:models/job
 */

/**
 * @function select
 * @param {object} conn - db connection object
 * @param {module:models/job.jobQuerySql} cond - db sql query hash include id|project_name|user_email|status|count|offset
 * @param {module:models/job.callback_err_joblist} callback - callback
 * @memberOf module:models/job
 */

function select(conn, cond, callback) {
    var where = '';
    var whereCount = 0;
    var order = ' ORDER BY ';
    var arrange = 'ASC';
    var children = false;

    if (cond.children) {
        children = true;
    }

    var availableKeyList = _.select(['id', 'user_email', 'distribution_name', 'distribution_type', 'project_name', 'project_type', 'environment_name', 'status', 'status_info', 'parent_id', 'snapshot_name', 'description'],
        function (key) {
            return (cond[key] !== undefined);
        });

    var whereList = _.map(availableKeyList, function (key) {
        var query = '';
        var value = cond[key];
        if (value === 'NULL') {
            query = (key + ' is NULL ');
        } else if ((new RegExp('^[=><]+')).test(value)) {
            query = (key + ' ' + value + ' ');
        } else if (_.isArray(value)) {
            query = (key + ' in (' + _.map(value, function (val) {
                    return utils.DBStr(val);
                }).join(',') + ') ');
        } else {
            query = (key + ' = ' + utils.DBStr(cond[key]));
        }
        return query;
    });

    if (cond.distName !== undefined) {
        whereList.push('distribution_name = ' + utils.DBStr(cond.distName));
    }
    if (cond.distType !== undefined) {
        whereList.push('distribution_type = ' + utils.DBStr(cond.distType));
    }

    if (cond.start_time !== undefined) {
        whereList.push('start_time >= ' + utils.DBStr(cond.start_time));
    }

    if (cond.end_time !== undefined) {
        whereList.push('end_time <= ' + utils.DBStr(cond.end_time));
    }

    if (cond.start_snapshot_name !== undefined) {
        whereList.push('snapshot_name >= ' + utils.DBStr(cond.start_snapshot_name));
    }

    if (cond.end_snapshot_name !== undefined) {
        whereList.push('snapshot_name <= ' + utils.DBStr(cond.end_snapshot_name));
    }

    // order by info
    if (cond.arrange !== undefined) {
        arrange = cond.arrange;
    }

    if (cond.order === undefined) {
        order = order + ' id ' + arrange;
    } else {
        order = order + cond.order + ' ' + arrange;
    }

    // start option
    if (cond.start !== undefined) {
        if (arrange === 'ASC') {
            whereList.push('id >= ' + cond.start);
        } else {
            whereList.push('id <= ' + cond.start);
        }
    }

    // limit info
    var limit = '';
    if (cond.count !== undefined) {
        if (cond.offset !== undefined) {
            limit += (' LIMIT ' + cond.offset + ' , ' + cond.count);
        } else {
            limit += (' LIMIT ' + cond.count);
        }
    }

    if (whereList.length > 0) {
        where = ' WHERE ' + whereList.join(' AND ');
    }

    var sql = 'SELECT * FROM jobs ' + where + ' ' + order + ' ' + limit;
    async.waterfall([
        function (wcb) {
            conn.query(sql, function (err, rows) {
                wcb(err, rows);
            });
        },
        function (jobList, wcb) {
            async.map(jobList, function (job, mcb) {
                sql = 'SELECT users.name ' +
                    'FROM users ' +
                    'WHERE users.email= ' + utils.DBStr(job.user_email);
                conn.query(sql,
                    function (err, results) {
                        if (results && results[0] && results[0].name) {
                            job.user_name = results[0].name;
                        } else {
                            job.user_name = job.user_email;
                        }
                        mcb(err, job);
                    }
                );
            }, wcb);
        },
        function (jobList, wcb) {
            async.map(jobList, function (job, mcb) {
                sql = 'SELECT job_info.property,job_info.value,job_info.type ' +
                    'FROM job_info ' +
                    'WHERE job_id = ' + utils.DBStr(job.id);
                conn.query(sql,
                    function (err, results) {
                        var options = {};
                        if (results) {
                            _.each(results, function (option) {
                                options[option.property] = utils.stringAndTypeToObj(option.value, option.type);
                            });
                        }
                        job.options = options;
                        mcb(err, job);
                    }
                );
            }, wcb);
        },
        function (jobList, wcb) {
            async.map(jobList, function (job, mcb) {
                sql = 'SELECT id, time, type, name ' +
                    'FROM job_board ' +
                    'WHERE job_id = ' + utils.DBStr(job.id);
                conn.query(sql,
                    function (err, results) {
                        if (results) {
                            job.board = results;
                        } else {
                            job.board = [];
                        }
                        mcb(err, job);
                    }
                );
            }, wcb);
        },
        function (jobList, wcb) {
            async.map(jobList, function (job, mcb) {
                var whereList = [];
                if (cond['$child']) {
                    whereList.push(QueryParser.select(cond['$child']));
                }
                whereList.push('parent_id = ' + job.id);
                sql = 'SELECT count(*) as count ' +
                    'FROM jobs ' +
                    'WHERE ' + whereList.join(' AND ');
                conn.query(sql,
                    function (err, results) {
                        if (results) {
                            job.childCount = results[0].count;
                        } else {
                            job.child_count = 0;
                        }
                        mcb(err, job);
                    }
                );
            }, wcb);
        },
        function (jobList, wcb) {
            async.map(jobList, function (job, mcb) {
                Project.select(conn, {
                    distName: job.distribution_name,
                    name: job.project_name
                },
                    function (err, results) {
                        if (results) {
                            job.project = results[0];
                        } else {
                            job.project = null;
                        }
                        mcb(err, job);
                    }
                );
            }, wcb);
        },
        function (jobList, wcb) {
            async.map(jobList, function (job, mcb) {
                if (children === false) {
                    mcb(null, job);
                    return;
                } else {
                    select(conn, {
                        parent_id: job.id
                    }, function (err, data) {
                        job.children = data;
                        mcb(err, job);
                    });
                }
            }, wcb);
        }],
        function (err, jobList) {
            if (err) {
                var error = new DError('MODEL003', {
                    sql: sql
                }, err);
                callback(error, null);
            } else {
                async.map(jobList,
                    function (job, cb) {
                        async.waterfall([
                            function (cb1) {
                                if (job.project && dibs.projectTypes[job.project.type]) {
                                    dibs.projectTypes[job.project.type].module.createJob(
                                        job.user_email,
                                        job.distribution_name,
                                        job.project_name,
                                        job.project_type,
                                        job.environment_name,
                                        job.parent_id,
                                        job.distribution_type,
                                        job.options,
                                        function (err, newJob) {
                                            cb1(null, newJob);
                                        });
                                } else {
                                    create(
                                        job.user_email,
                                        job.distribution_name,
                                        job.distribution_type,
                                        job.project_name,
                                        job.project_type,
                                        job.environment_name,
                                        job.parent_id,
                                        job.type,
                                        job.options,
                                        cb1);
                                }
                            },
                            function (newJob, cb1) {
                                newJob.id = job.id;
                                newJob.userName = job.user_name;
                                newJob.status = job.status;
                                newJob.statusInfo = job.status_info;
                                newJob.board = job.board;
                                newJob.childCount = job.childCount;
                                newJob.children = job.children;
                                newJob.startTime = job.start_time;
                                newJob.endTime = job.end_time;
                                newJob.errorCode = job.error_code;
                                newJob.snapshotName = job.snapshot_name;
                                newJob.initServerId = job.init_server_id;
                                newJob.execServerId = job.exec_server_id;
                                newJob.approvalId = job.approval_id;
                                newJob.description = job.description;
                                cb1(null, newJob);
                            }
                        ],
                            function (err, newJob) {
                                cb(err, newJob);
                            });
                    },
                    function (err, newJobList) {
                        callback(err, newJobList);
                    });
            }
        }
    );
}
module.exports.select = select;

function selectCount(conn, cond, callback) {
    var where = '';
    var whereCount = 0;

    var availableKeyList = _.select(['id', 'user_email', 'distribution_name', 'distribution_type', 'project_name', 'project_type', 'environment_name', 'status', 'status_info', 'parent_id', 'snapshot_name', 'description'],
        function (key) {
            return (cond[key] !== undefined);
        });

    var whereList = _.map(availableKeyList, function (key) {
        var query = '';
        var value = cond[key];
        if (value === 'NULL') {
            query = (key + ' is NULL ');
        } else if ((new RegExp('^[=><]+')).test(value)) {
            query = (key + ' ' + value + ' ');
        } else if (_.isArray(value)) {
            query = (key + ' in (' + _.map(value, function (val) {
                    return utils.DBStr(val);
                }).join(',') + ') ');
        } else {
            query = (key + ' = ' + utils.DBStr(cond[key]));
        }
        return query;
    });

    if (cond.distName !== undefined) {
        whereList.push('distribution_name = ' + utils.DBStr(cond.distName));
    }
    if (cond.distType !== undefined) {
        whereList.push('distribution_type = ' + utils.DBStr(cond.distType));
    }

    if (cond.start_time !== undefined) {
        whereList.push('start_time >= ' + utils.DBStr(cond.start_time));
    }

    if (cond.end_time !== undefined) {
        whereList.push('end_time <= ' + utils.DBStr(cond.end_time));
    }

    if (cond.start_snapshot_name !== undefined) {
        whereList.push('snapshot_name >= ' + utils.DBStr(cond.start_snapshot_name));
    }

    if (cond.end_snapshot_name !== undefined) {
        whereList.push('snapshot_name <= ' + utils.DBStr(cond.end_snapshot_name));
    }

    if (whereList.length > 0) {
        where = ' WHERE ' + whereList.join(' AND ');
    }

    var sql = 'SELECT count(*) as count FROM jobs ' + where;
    conn.query(sql, function (err, rows) {
        if (err) {
            var error = new DError('MODEL003', {
                sql: sql
            }, err);
            callback(error, null);
        } else {
            callback(null, rows[0].count);
        }
    });
}
module.exports.selectCount = selectCount;


function Privilege(user, groups, distribution, project, options) {
    var self = this;
    this.user = true;
    this.group = true;
    this.distribution = true;
    this.project = true;
    // check user
    if (user.status !== 'OPEN') {
        self.user = false;
    }
    // check group
    var validGroups = [];
    _.each(groups, function (group) {
        if (_.contains(group.projects, project.id)) {
            if (group.status === 'OPEN') {
                validGroups.push(group);
            }
        }
    });
    if (validGroups.length === 0) {
        self.group = false;
    }
    // owner is availabe
    if (user.email === distribution.email) {
        self.group = true;
    }
    // check distribution
    if (distribution.status !== 'OPEN') {
        self.distribution = false;
    }
    // check project
    if (project.status !== 'OPEN') {
        self.project = false;
    }
}

function privilege(user, groups, distribution, project, options) {
    return new Privilege(user, groups, distribution, project, options);
}

module.exports.privilege = privilege;
