/**
 * serverConfig.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 expressio = require('express.io');
var session = require('./session');
var dibs = require('../../../core/dibs.js');
var DError = require('../../../core/exception.js');

var router = new expressio.Router();

module.exports.router = router;

router.get('/serverconfig', session.checkSession, function (req, res) {
    var privilege = req.query.privilege;
    var queryPrivilege = req.query.queryPrivilege;
    var condition = {
        email: req.session.email
    };

    // set status option
    if (privilege) {
        condition.privilege = privilege;
    }
    if (queryPrivilege) {
        condition.queryPrivilege = queryPrivilege;
    }

    dibs.rpc.datamgr.searchAllServers(function (err, servers) {
        if (err) {
            dibs.log.error(JSON.stringify(err));
            res.status(503).send(JSON.stringify(err.message));
        } else {
            res.send(servers);
        }
    });
});

router.put('/serverconfig/:serverId', session.checkSession, function (req, res) {
    var serverId = req.param('serverId');
    var email = req.session.email;

    async.waterfall([
        function (cb) {
            // check privilege
            cb(null);
        }], function (err) {
        if (err) {
            dibs.log.error(JSON.stringify(err));
            res.status(503).send(JSON.stringify(err.message));
        } else {
            updateServer(serverId, req, res);
        }
    });
});


router.delete('/serverconfig/:serverId', session.checkSession, function (req, res) {
    var serverId = req.param('serverId');
    var email = req.session.email;

    async.waterfall([
        function (cb) {
            // check privilege
            cb(null);
        },
        function (cb) {
            dibs.rpc.datamgr.searchServers({
                id: serverId
            }, function (err, results) {
                if (!err && results[0]) {
                    cb(null, results[0]);
                } else {
                    dibs.log.error(err);
                    cb(new Error('Fail to find the server!'), null);
                }
            });
        },
        function (server, cb) {
            if (server.type === 'host') {
                dibs.rpc.datamgr.deleteServer(server.id, cb);
            } else {
                dibs.rpc.master.removeServer(server.id, {cleanResource: false}, cb);
            }
        }], function (err) {
        if (err) {
            dibs.log.error(err);
            res.status(503).send(JSON.stringify(err.message));
        } else {
            res.send();
        }
    });
});

function updateServer(serverId, req, res) {
    dibs.log.info('Received a request for server update...' + serverId);

    var serverData = convertDataType(req.body);

    async.waterfall([
        function (cb) {
            dibs.rpc.datamgr.searchServers({
                id: serverId
            }, function (err, results) {
                if (err || results.lentth === 0) {
                    cb(new Error('cannot find server:' + serverId));
                } else {
                    cb(null);
                }
            });
        },
        function (cb) {
            if (serverData.type === 'host') {
                dibs.rpc.datamgr.updateServer(serverData, cb);
            } else if (serverData.type === 'builder') {
                var server = serverData.information;
                server.id = serverData.id;
                server.host = serverData.host;
                server.port = serverData.port;
                server.type = serverData.type;
                server.os_type = serverData.os_type;
                server.parent_id = serverData.parent_id;
                server.domain_name = serverData.domain_name;
                server.description = serverData.description;
                dibs.rpc.master.updateServer(server, cb);
            } else {
                cb(new Error('Not allowed'));
            }
        }], function (err) {
            if (err) {
                dibs.log.error(JSON.stringify(err));
                res.status(503).send(JSON.stringify(err.message));
            } else {
                res.send(serverData);
            }
        });
}

router.post('/serverconfig', session.checkSession, function (req, res) {
    var email = req.session.email;

    var serverData = convertDataType(req.body);

    async.waterfall([
        function (cb) {
            // check privilege
            cb(null);
        },
        function (cb) {
            if (serverData.type === 'host') {
                dibs.rpc.datamgr.addServer(serverData.id, serverData.type, serverData.parent_id,
                        serverData.os_type, serverData.host, serverData.port, serverData.domain_name,
                        serverData.description, serverData.information, cb);
            } else {
                var server = {
                    id: serverData.id,
                    host: serverData.host,
                    port: serverData.port,
                    type: serverData.type
                };
                var config = {
                    os_type: serverData.os_type,
                    parent_id: serverData.parent_id,
                    domain_name: serverData.domain_name,
                    description: serverData.description
                };
                if (serverData.information.agent) {
                    server.agent = serverData.information.agent;
                    config.agent = serverData.information.agent;
                }

                dibs.rpc.master.addServer(serverData.type, server, config, cb);
            }
        }], function (err) {
        if (err) {
            dibs.log.error(JSON.stringify(err));
            res.status(503).send(JSON.stringify(err.message));
        } else {
            res.send();
        }
    });
});

function convertDataType(server) {
    // get base-server's config
    var baseConfig = _.find(dibs.plugin.getExtensions('dibs.server.config'), function (config) {
        return config.attributes.serverType === 'base-server';
    }).property;

    // get server's config
    var serverConfig = [];
    if (server.type !== 'host') {
        var serverTypeConfig = _.find(dibs.plugin.getExtensions('dibs.server.config'), function (config) {
            return config.attributes.serverType === server.type;
        });
        if (serverTypeConfig && serverTypeConfig.property) {
            serverConfig = serverTypeConfig.property;
        }
    }

    var configProperty = baseConfig.concat(serverConfig);

    // generate server object
    var output = { information: {} };
    _.each(server, function (value, key) {
        if (key === 'information') {
            _.each(value, function (value1, key1) {
                output['information'][key1] = getData(configProperty, key1, value1);
            });
        } else {
            output[key] = getData(configProperty, key, value);
        }
    });

    return output;
}

function getData(list, property, data) {
    // find property's data type
    var output = _.find(list, function (i) { return i.key === property; });

    if (!output || output.dataType === typeof data) {
        return data;
    } else if (output.dataType === 'number') {
    // string -> number
        return Number(data);
    } else if (output.dataType === 'boolean') {
    // string -> boolean
        var truth = /^true$/i;
        if (truth.test(data)) {
            return true;
        } else {
            return false;
        }
    } else if (output.dataType === 'string') {
    // other -> string
        return JSON.stringify(data);
    } else {
        return data;
    }
}
