/**
 * trigger.js
 * Copyright (c) 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 dibs = require('../../core/dibs.js');
var DError = require('../../core/exception.js');
var utils = require('../../lib/utils.js');


module.exports.create = create;
module.exports.insert = insert;
module.exports.select = select;
module.exports.update = update;
module.exports.delete = deleteTrigger;


/**
 * @module models/trigger
 */


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

/**
 * @constructor
 * @param {string} id - trigger id
 * @param {string} name - trigger name
 * @param {string} type - trigger type
 * @param {string} status - trigger status
 * @param {string} server type - trigger server type
 * @param {object} data - trigger data
 */
function Trigger(id, name, type, status, serverType, data) {
    /** @type {module:models/trigger~Project} */
    var self = this;
    /** @type {number} */
    this.id = id;
    /** @type {string} */
    this.name = name;
    /** @type {string} */
    this.type = type;
    /** @type {string} */
    this.status = status || 'OPEN';
    /** @type {string} */
    this.serverType = serverType;
    /** @type {} */
    this.data = data || {};
}


/**
 * @callback callback_err_trigger
 * @param {error|undefined} error
 * @param {module:models/trigger~Trigger} trigger
 * @memberOf module:models/trigger
 */

/**
 * @function create
 * @param {string} id - trigger id
 * @param {string} name - trigger name
 * @param {string} type - trigger type
 * @param {string} status - trigger status - OPEN | CLOSE
 * @param {string} serverType - server type
 * @param {} data
 * @memberOf module:models/trigger
 */

function create(id, name, type, status, serverType, data, callback) {
    var err;
    if (!name) {
        err = new DError('TRGR001', {
            field: 'name'
        });
    }
    if (!type) {
        err = new DError('TRGR001', {
            field: 'type'
        });
    }
    if (!serverType) {
        err = new DError('TRGR001', {
            field: 'serverType'
        });
    }
    callback(err, new Trigger(id, name, type, status, serverType, data));
}


/**
 * @callback callback_err_triggerId
 * @param {error|undefined} error
 * @param {string} trigger id - trigger id
 * @memberOf module:models/trigger
 */

/**
 * @function insert
 * @param {object} conn - db connection object
 * @param {module:models/trigger~Project} trigger - trigger
 * @param {module:models/trigger.callback_err_triggerid} callback - callback
 * @memberOf module:models/trigger
 */

function insert(conn, trigger, callback) {
    var id = null;

    async.waterfall([
        function (cb) {
            conn.query('START TRANSACTION', function (err) {
                cb(err);
            });
        },
        function (cb) {
            var triggerData = utils.objectToStringAndType(trigger.data);

            var sql = 'INSERT INTO triggers SET ' +
                '  name = ' + utils.DBStr(trigger.name) +
                ', type = ' + utils.DBStr(trigger.type) +
                ', status = ' + utils.DBStr(trigger.status) +
                ', server_type = ' + utils.DBStr(trigger.serverType) +
                ', data = ' + utils.DBStr(triggerData.string) +
                ', data_type = ' + utils.DBStr(triggerData.type);
            conn.query(sql, function (err, result) {
                if (err) {
                    cb(new DError('MODEL003', sql, err));
                } else {
                    cb(err, result.insertId);
                }
            });
        },
        function (triggerId, cb) {
            conn.query('COMMIT', function (err) {
                if (err) {
                    cb(err, null);
                } else {
                    cb(err, triggerId);
                }
            });
        }
    ],
        function (err, triggerId) {
            if (err) {
                conn.query('ROLLBACK', function () {});
                callback(err, null);
            } else {
                callback(err, triggerId);
            }
        });
}

/**
 * @callback callback_err_triggerid
 * @param {error|undefined} error
 * @param {string} trigger id - trigger id
 * @memberOf module:models/trigger
 */

/**
 * @function update
 * @param {object} conn - db connection object
 * @param {module:models/trigger~Project} trigger - trigger
 * @param {module:models/trigger.callback_err_triggerid} callback - callback
 * @memberOf module:models/trigger
 */
function update(connection, trigger, callback) {
    async.waterfall([
        function (cb) {
            connection.query('START TRANSACTION', function (err) {
                if (err) {
                    cb(new DError('MODEL001', err));
                } else {
                    cb(null);
                }
            });
        },
        function (cb) {
            var triggerData = utils.objectToStringAndType(trigger.data);

            var sql = 'UPDATE triggers SET' +
                '  name = ' + utils.DBStr(trigger.name) +
                ', type = ' + utils.DBStr(trigger.type) +
                ', status = ' + utils.DBStr(trigger.status) +
                ', server_type = ' + utils.DBStr(trigger.serverType) +
                ', data = ' + utils.DBStr(triggerData.string) +
                ', data_type = ' + utils.DBStr(triggerData.type) +
                ' WHERE id = ' + trigger.id;
            connection.query(sql, function (err) {
                if (err) {
                    cb(new DError('MODEL003', {
                        sql: sql
                    }, err), null);
                } else {
                    cb(err);
                }
            });
        },
        function (cb) {
            connection.query('COMMIT', function (err) {
                if (err) {
                    cb(new DError('MODEL002', err));
                } else {
                    cb(err);
                }
            });
        }
    ],
        function (err) {
            if (err) {
                connection.query('ROLLBACK', function () {});
            }
            callback(err);
        });
}

/**
 * @function select
 * @param {object} conn - db connection object
 * @param {module:models/user.jobQuerySql} condition - condition
 * @param {module:lib/utils.callback_error} callback - callback
 * @memberOf module:models/user
 */

function select(conn, condition, callback) {
    var where = '';
    var whereList = [];
    var order = '';

    if (condition.serverType !== undefined) {
        condition.server_type = condition.serverType;
    }

    var availableKeyList = _.select(['id', 'name', 'type', 'status', 'server_type'], function (key) {
        return (condition[key] !== undefined);
    });

    whereList = _.map(availableKeyList, function (key) {
        var value = condition[key];

        var query = '';
        if (value === null) {
            query = ('triggers.' + key + ' IS NULL ');
        } else if ((new RegExp('^[=><]+')).test(value)) {
            query = ('triggers.' + key + ' ' + value + ' ');
        } else if (_.isArray(value)) {
            query = ('triggers.' + key + ' IN (' + _.map(value, function (val) {
                    return utils.DBStr(val);
                }).join(',') + ') ');
        } else {
            query = ('triggers.' + key + ' = ' + utils.DBStr(condition[key]));
        }
        return query;
    });


    // order by info
    if (condition.order !== undefined) {
        order = ' ORDER BY ' + condition.order;

        if (condition.arrange !== undefined) {
            order = order + ' ' + condition.arrange;
        }
    }

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

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

    var sql = 'SELECT id, name, type, ' +
        'status, server_type AS serverType, ' +
        'data, data_type ' +
        'FROM triggers ' +
        where + order + limit;

    conn.query(sql, function (err, triggers) {
        if (err) {
            callback(new DError('MODEL003', {
                sql: sql
            }, err));
            return;
        }

        async.map(triggers, function (trigger, cb) {
            var data = utils.stringAndTypeToObj(trigger.data, trigger.data_type);
            create(trigger.id, trigger.name, trigger.type, trigger.status, trigger.serverType, data, cb);
        },
            function (err, results) {
                if (err) {
                    callback(new DError('MODEL004', {
                        condition: condition
                    }, err));
                    return;
                }
                callback(null, results);
            });
    });
}


function deleteTrigger(connection, triggerId, callback) {
    connection.query('START TRANSACTION', function (err) {
        if (err) {
            callback(new DError('MODEL001', err));
            return;
        }
        async.waterfall([
            function (cb) {
                // delete trigger
                var sql = 'DELETE FROM triggers WHERE id = ' + triggerId;
                connection.query(sql, function (err) {
                    if (err) {
                        cb(new DError('MODEL003', {
                            sql: sql
                        }, err), null);
                    } else {
                        cb(null);
                    }
                });
            },
            function (cb) {
                connection.query('COMMIT', function (err) {
                    if (err) {
                        cb(new DError('MODEL002', err));
                    } else {
                        cb(err);
                    }
                });
            }
        ],
            function (err) {
                if (err) {
                    connection.query('ROLLBACK', function () {
                        callback(err);
                    });
                } else {
                    callback(err);
                }
            });
    });
}
