/**
 * test-statistics.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 dibs = require('../../core/dibs.js');
var utils = require('../../lib/utils.js');
var DError = require('../../core/exception');
var Job = require('../../plugins/dibs.model.common/job');


module.exports.create = create;


function TestStatistics(parent) {
    this.server = parent;

    this.queryStatistics = function (opts, callback) {
        var queryCond = {};
        var err = null;

        // parsing querying options
        err = checkQueryingDate(opts, queryCond);
        if (err) {
            return callback(err, null);
        }

        if (opts.distName) {
            queryCond.distName = opts.distName;
        }
        if (opts.userEmail) {
            queryCond.user_email = opts.userEmail;
        }
        //if ( opts.projectName ) { queryCond.project_name = opts.projectName; }
        //if ( opts.groupName ) { queryCond.groupName = opts.groupName; }
        //if ( opts.serverName ) { queryCond.serverName = opts.serverName; }

        // generate statistics result
        generateStatisticsForQueryingTests(queryCond, callback);
    };


    function checkQueryingDate(opts, queryCond) {
        queryCond.project_type = 'Tizen-Testsuite';

        if (opts.dateFrom) {
            var startTime = null;
            if (_.isDate(opts.dateFrom) || typeof (opts.dateFrom) === 'string' || opts.dateFrom instanceof String) {
                startTime = new Date(opts.dateFrom);
            } else {
                return new DError('DATEMGR015', {
                    str: opts.dateFrom
                });
            }
            startTime.setHours(0);
            queryCond.start_time = utils.getTimeString(startTime);
        }

        if (opts.dateTo) {
            var endTime = null;
            if (_.isDate(opts.dateTo) || typeof (opts.dateTo) === 'string' || opts.dateTo instanceof String) {
                endTime = new Date(opts.dateTo);
            } else {
                return new DError('DATEMGR015', {
                    str: opts.dateTo
                });
            }
            endTime.setHours(23);
            endTime.setMinutes(59);
            endTime.setSeconds(59);
            queryCond.end_time = utils.getTimeString(endTime);
        }

        return null;
    }


    function generateStatisticsForQueryingTests(queryCond, callback) {
        var result = null;
        var connection = null;

        async.waterfall([
            function (cb) {
                server.getDBHandle().getConnection(cb);
            },
            function (conn, cb) {
                connection = conn;
                Job.select(conn, queryCond, cb);
            },
            function (jobs, cb) {
                result = {
                    totalTestsuites: 0,
                    totalTestcases: 0,
                    successTestcases: 0,
                    successRate: 0,
                    errorTestsuites: 0,
                    errorRate: 0,
                    coverage: 0,
                    trends: {},
                    testsuites: {}
                };

                for (var i = 0; i < jobs.length; i++) {
                    var job = jobs[i];

                    if (job.status !== 'FINISHED' && job.status !== 'ERROR' &&
                        job.status !== 'CANCELED') {
                        continue;
                    }

                    if (job.status !== 'FINISHED') {
                        result.errorExecutions++;
                    }

                    accumulateTrendData(job, result.trends);
                    accumulateTestsuitesData(job, result.testsuites);
                }
                calculateOverall(result);
                calculateTestsuiteData(result.testsuites);

                cb(null, result);
            }
        ], function (err, result) {
            if (connection) {
                connection.release();
            }
            callback(err, result);
        });
    }


    function accumulateTrendData(job, trends) {

        // for trend
        var dateTime = new Date(job.startTime);
        var date = dateTime.format('YYYY-MM-DD');
        var week = new Date(dateTime.setDate(dateTime.getDate() - dateTime.getDay())).format('YYYY-MM-DD');
        var month = new Date(job.startTime).format('YYYY-MM');

        if (!trends.daily) {
            trends.daily = {};
            trends.weekly = {};
            trends.monthly = {};
        }

        var testsuiteName = job.options.TESTSUITE_NAME;
        if (!trends.daily[date]) {
            trends.daily[date] = {
                totalTestsuites: 0,
                totalTestcases: 0,
                successTestcases: 0,
                successRate: 0,
                errorTestsuites: 0,
                errorRate: 0,
                coverage: 0,
                testsuites: {}
            };
        }
        setTestsuiteToTrend(job, trends.daily[date]);

        if (!trends.weekly[week]) {
            trends.weekly[week] = {
                totalTestsuites: 0,
                totalTestcases: 0,
                successTestcases: 0,
                successRate: 0,
                errorTestsuites: 0,
                errorRate: 0,
                coverage: 0,
                testsuites: {}
            };
        }
        setTestsuiteToTrend(job, trends.weekly[week]);

        if (!trends.monthly[month]) {
            trends.monthly[month] = {
                totalTestsuites: 0,
                totalTestcases: 0,
                successTestcases: 0,
                successRate: 0,
                errorTestsuites: 0,
                errorRate: 0,
                coverage: 0,
                testsuites: {}
            };
        }
        setTestsuiteToTrend(job, trends.monthly[month]);
    }


    function accumulateTestsuitesData(job, testsuites) {
        var testsuiteName = job.options.TESTSUITE_NAME;
        var envName = job.environmentName;

        if (!testsuites[testsuiteName]) {
            testsuites[testsuiteName] = {
                totalTestcases: 0,
                totalEnvironments: 0,
                successTestcases: 0,
                successRate: 0,
                errorEnvironments: 0,
                errorRate: 0,
                trends: {}
            };
        }

        accumulateTrendDataByTestsuite(job, testsuites[testsuiteName].trends);
    }


    function accumulateTrendDataByTestsuite(job, trends) {

        // for trend
        var dateTime = new Date(job.startTime);
        var date = dateTime.format('YYYY-MM-DD');
        var week = new Date(dateTime.setDate(dateTime.getDate() - dateTime.getDay())).format('YYYY-MM-DD');
        var month = new Date(job.startTime).format('YYYY-MM');

        if (!trends.daily) {
            trends.daily = {};
            trends.weekly = {};
            trends.monthly = {};
        }

        if (!trends.daily[date]) {
            trends.daily[date] = {
                totalEnvironments: 0,
                totalTestcases: 0,
                successTestcases: 0,
                successRate: 0,
                errorEnvironments: 0,
                errorRate: 0,
                testsuites: {}
            };
        }
        setTestsuiteToTrend(job, trends.daily[date]);

        if (!trends.weekly[week]) {
            trends.weekly[week] = {
                totalEnvironments: 0,
                totalTestcases: 0,
                successTestcases: 0,
                successRate: 0,
                errorEnvironments: 0,
                errorRate: 0,
                testsuites: {}
            };
        }
        setTestsuiteToTrend(job, trends.weekly[week]);

        if (!trends.monthly[month]) {
            trends.monthly[month] = {
                totalEnvironments: 0,
                totalTestcases: 0,
                successTestcases: 0,
                successRate: 0,
                errorEnvironments: 0,
                errorRate: 0,
                testsuites: {}
            };
        }
        setTestsuiteToTrend(job, trends.monthly[month]);
    }


    function setTestsuiteToTrend(job, trend) {
        var testsuiteName = job.options.TESTSUITE_NAME;
        var envName = job.environmentName;
        if (!trend.testsuites[testsuiteName]) {
            trend.testsuites[testsuiteName] = {};
        }
        if (trend.testsuites[testsuiteName] &&
            !trend.testsuites[testsuiteName][envName]) {
            trend.testsuites[testsuiteName][envName] = {};
        }

        var testsuite = trend.testsuites[testsuiteName][envName];
        if (job.status === 'FINISHED') {
            testsuite.testStatus = (job.options.TEST_RESULT.failures === 0) ?
                'SUCCESS' : 'FAIL';
            testsuite.totalTestcases = job.options.TEST_RESULT.tests;
            testsuite.successTestcases = job.options.TEST_RESULT.tests - job.options.TEST_RESULT.failures;
            testsuite.successRate = Math.round(
                    testsuite.successTestcases * 100 / testsuite.totalTestcases * 10) / 10;
        } else {
            trend.testsuites[testsuiteName][envName].testStatus = 'ERROR';
        }
    }


    function calculateTestsuiteData(testsuites) {
        for (var testsuiteName in testsuites) {
            var testsuite = testsuites[testsuiteName];

            var trends = testsuite.trends;
            var lastDate = null;
            for (var date in trends.daily) {
                summarizeForTestsuite(trends.daily[date], trends.daily[date].testsuites);
                lastDate = date;
            }
            for (var week in trends.weekly) {
                summarizeForTestsuite(trends.weekly[week], trends.weekly[week].testsuites);
            }
            for (var month in trends.monthly) {
                summarizeForTestsuite(trends.monthly[month], trends.monthly[month].testsuites);
            }

            if (lastDate) {
                summarizeForTestsuite(testsuite, trends.daily[lastDate].testsuites);
            }
        }
    }


    function summarizeForOverallTrend(result, testsuites) {
        result.totalTestsuites = Object.keys(testsuites).length;
        for (var tName in testsuites) {
            var testsuite = testsuites[tName];
            for (var envName in testsuite) {
                var testEnv = testsuite[envName];
                if (testEnv.testStatus !== 'ERROR') {
                    result.totalTestcases += testEnv.totalTestcases;
                    result.successTestcases += testEnv.successTestcases;
                } else {
                    result.errorTestsuites++;
                }
            }
        }
        result.successRate = Math.round(
                result.successTestcases * 100 / result.totalTestcases * 10) / 10;
        result.errorRate = Math.round(
                result.errorTestsuites * 100 / result.totalTestsuites * 10) / 10;
    }


    function summarizeForTestsuite(result, testsuites) {
        var tName = Object.keys(testsuites)[0];
        var testsuite = testsuites[tName];
        result.totalEnvironments = Object.keys(testsuite).length;

        for (var envName in testsuite) {
            var testEnv = testsuite[envName];
            if (testEnv.testStatus !== 'ERROR') {
                result.totalTestcases += testEnv.totalTestcases;
                result.successTestcases += testEnv.successTestcases;
            } else {
                result.errorEnvironments++;
            }
        }
        result.successRate = Math.round(
                result.successTestcases * 100 / result.totalTestcases * 10) / 10;
        result.errorRate = Math.round(
                result.errorEnvironments * 100 / result.totalEnvironments * 10) / 10;
    }


    function calculateOverall(result) {
        var trends = result.trends;
        var lastDate = null;

        for (var date in trends.daily) {
            summarizeForOverallTrend(trends.daily[date], trends.daily[date].testsuites);
            lastDate = date;
        }
        for (var week in trends.weekly) {
            summarizeForOverallTrend(trends.weekly[week], trends.weekly[week].testsuites);
        }
        for (var month in trends.monthly) {
            summarizeForOverallTrend(trends.monthly[month], trends.monthly[month].testsuites);
        }

        if (lastDate) {
            summarizeForOverallTrend(result, trends.daily[lastDate].testsuites);
        }
    }
}


function create(parent) {
    parent.log.info('Creating job statics...');
    return new TestStatistics(parent);
}
