/**
 * session.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 dibs = require('../../../core/dibs');
var DError = require('../../../core/exception');
var utils = require('../../../lib/utils');
var bcrypt = require('bcrypt-nodejs');
var async = require('async');
var _ = require('underscore');

exports.createAccount = createAccount;
exports.createSession = createSession;
exports.deleteSession = deleteSession;
exports.checkSession = checkSession;
exports.checkAdmin = checkAdmin;
exports.isAdmin = isAdmin;
exports.genPasswordHash = genPasswordHash;
exports.isValidPassword = isValidPassword;

function createAccount(req, res, callback) {
    var email = req.body.email;
    var name = req.body.name;
    var password = req.body.password;
    var passwordConfirm = req.body.passwordConfirm;

    if (utils.validateEmail(email) !== true) {
        callback(new DError('SESSION004', {
            email: email
        }), 401);
        return;
    }

    if (password !== passwordConfirm) {
        callback(new DError('SESSION005'), 401);
        return;
    }

    dibs.rpc.datamgr.searchUsers({
        email: email
    }, function (err, users) {
        if (err) {
            callback(err, 500);
        } else {
            if (users.length > 0) {
                callback(new DError('SESSION001', {
                    email: users[0].email
                }), 401);
                return;
            }

            async.waterfall([
                async.apply(genPasswordHash, password),
                function(hash, salt, cb) {
                    dibs.rpc.datamgr.addUser( email, name, hash, salt, {}, function( err, user) {
                        cb(err, user);
                    });
                }],
                function (err, result) {
                    if (err) {
                        callback(err, 500);
                    } else {
                        callback(null, 200);
                    }
                });
        }
    });
}

function genPasswordHash(password, callback) {
    var passSalt = null;
    var passHash = null;
    async.series([
        function (cb) {
            bcrypt.genSalt(10, function (err, salt) {
                var error = null;
                passSalt = salt;
                if (err) {
                    error = new DError('SESSION002', err);
                }
                cb(error);
            });
        },
        function (cb) {
            bcrypt.hash(password, passSalt, null, function (err, hash) {
                passHash = hash;
                var error = null;
                if (err) {
                    error = new DError('SESSION003', err);
                }
                cb(error);
            });
        }
    ], function (err) {
        callback(err, passHash, passSalt);
    });
}

function isValidPassword(password, passwordSalt, passwordHash, callback) {
    bcrypt.hash(password, passwordSalt, null, function (err, hash) {
        if (err) {
            callback(false);
        } else {
            callback(passwordHash === hash);
        }
    });
}

function createSession(req, res, callback)
{
    var email = req.body.email;
    var password = req.body.password;

    dibs.rpc.datamgr.searchUsers({email: email }, function (err, users) {
        if (err) {
            callback(err, 503);
        } else {
            if (users.length === 0) {
                //404 Not found
                callback(null, 404);
            } else {
                var user = users[0];
                isValidPassword(password, user.password_salt, user.password_hash, function (truth) {
                    if (truth) {
                        //200 OK
                        req.session.email = email;
                        req.session.status = user.status;
                        isAdmin(email, function (err, admin) {
                            if (err) {
                                callback(err, 500);
                                return res.status(500).send(JSON.stringify(err.message));
                            }
                            if (admin) {
                                req.session.admin = 'true';
                            }
                            callback(null, 200);
                        });
                    } else {
                        //401 Unauthorized
                        callback(null, 401);
                    }
                });
            }
        }
    });
}

function deleteSession(req, res, callback) {
    if (req.session) {
        req.session.destroy(function () {});
    }
    callback(null, null);
}

function checkSession(req, res, next) {
    var store = dibs.thisServer.sessionStore;

    store.get(req.sessionID, function (err, session) {
        if (err) {
            dibs.log.error(err);
            return res.status(500).send(JSON.stringify(err.message));
        } else {
            if (session && req && session.email && req.session && session.email === req.session.email) {
                next();
            } else {
                return res.status(403).send('Session is expired.');
            }
        }
    });
}

function checkAdmin(req, res, next) {
    var email = req.body.email;
    if (email) {
        isAdmin(email, function (err, admin) {
            if (err) {
                return res.status(500).send(JSON.stringify(err.message));
            }
            if (admin) {
                next();
            } else {
                return res.status(401).send('Need admin session.');
            }
        });
    } else {
        return res.status(403).send('Session is expired.');
    }
}

function isAdmin(email, callback) {
    dibs.rpc.datamgr.searchUserGroupsInfo(email, function (err, user) {
        if (err) {
            callback(err, false);
        } else {
            var group_id_list = _.pluck(user.groups, 'id');
            if (_.contains(group_id_list, 1) === true) {
                callback(null, true);
            } else {
                callback(null, false);
            }
        }
    });
}
