/**
 * monitor.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 _ = require('underscore');
var kill = require('tree-kill');
var running = require('is-running');
// info structure
// {
//      logType: info / warn / err
//      log : "string"
//      progress: "integer"
// }
var ProgressMonitor = function (funcObj) {
    var active = true;
    var onProgress = funcObj.onProgress;
    var progress = 0;
    var procList = [];
    var cancelReq = false;
    var disablecancel = false;
    var cancelCallback = null;
    var self = this;
    this.progress = function () {
        return progress;
    };

    this.addProcess = function (process) {
        if (cancelReq) {
            self.updateProgress(' - Added new processs after CANCEL Req...' + process.pid);
            killMonitoringProcess(process);
        } else {
            procList.push(process);
            self.updateProgress(' - Added new working process...' + process.pid);
        }
    };

    this.disableCancel = function () {
        if (!cancelReq) {
            disablecancel = true;
        }
    };

    this.possibleCancel = function () {
        return !disablecancel;
    };

    this.isCancel = function () {
        return cancelReq;
    };

    this.updateProgress = function (info, callback) {
        var nInfo = null;
        if (typeof info === 'string') {
            nInfo = {
                log: info,
                logType: 'info'
            };
        } else {
            nInfo = info;
        }

        if (cancelReq) {
            if (callback) {
                if (cancelCallback) {
                    cancelCallback(null);
                }
                callback(new Error('cancel'));
            } else {
                callback = function () {};
                onProgress(nInfo, callback);
                onProgress({
                    log: '^cancel request received but cancel callback undefined\n cancel will process next callback',
                    logType: 'warn'
                }, callback);
            }
        } else {
            if (nInfo.progress) {
                progress = nInfo.progress;
            }
            if (!callback) {
                callback = function () {};
            }
            onProgress(nInfo, callback);
        }
    };


    this.cancel = function (callback) {
        self.updateProgress('Received CANCEL request!');
        if (cancelReq || disablecancel) {
            if (cancelReq) {
                self.updateProgress(' - CANCEL request is already received!');
            }
            if (disablecancel) {
                self.updateProgress(' - Processing CANCEL is disabled!');
            }
            callback(new Error('cancel failed'));
        } else {
            // kill all working processes monitored
            self.updateProgress(' - Number of processes to be killed: ' + procList.length);
            _.each(procList, function (proc) {
                killMonitoringProcess(proc);
            });
            self.updateProgress('all process are killed !');

            // set flags
            cancelReq = true;
            disablecancel = true;
            cancelCallback = callback;
            self.updateProgress('cancel callback is registed');
        }
    };

    this.monitor = function (func, callback) {
        if (active) {
            active = false;

            self.updateProgress({
                progress: 0
            });

            func(function () {
                var args = _.toArray(arguments);
                self.disableCancel();
                self.updateProgress({
                    progress: 100
                }, function () {
                    callback.apply(null, args);
                });
            });
        } else {
            callback(new Error('Monitor is already activated!'));
        }
    };


    function killMonitoringProcess(proc) {
        if (running(proc.pid)) {
            self.updateProgress(' - ' + proc.pid + ' process is running');
            kill(proc.pid, 'SIGKILL');
            self.updateProgress(' - Sent SIGKILL to process...' + proc.pid);
            setTimeout(function () {
                killMonitoringProcess(proc);
            }, 500);
        }
    }


    return this;
};
module.exports = ProgressMonitor;
