# Source: RallyLogger.js

    /**
     * Created by 212392192 on 7/22/16.
     *
     * A util to help query and update rally using rally-node
     */

    (function(){

        var rally = require('rally');
        queryUtils = rally.util.query;
        refUtils = rally.util.ref;
        logger = require('./Logger.js');
        rallylog = require("./RallyLog.js");
        var apiKey;
        if (process.env.apiKey != undefined) {
            apiKey = process.env.apiKey;
            rallylog.info('apikey is ' + "\'" + apiKey + "\'");
        }
        else {
            rallylog.info('no apiKey defined');
            return;
        }

        if (process.env.method != undefined)
            var method = process.env.method;
        else
            var method = "Automated";   // default workspace
        var project = process.env.project;
        var ws = process.env.rallyworkspace
        var proxy = process.env.rallyProxy;
        var baseUrl = 'https://rally1.rallydev.com/slm/webservice/v2.0/';
        var type;
        if(process.env.type != undefined){
            type = process.env.type.trim();
            if( ((type != 'Acceptance') && (type != 'Functional') && (type != 'Performance') && (type != 'Regression') &&
                (type != 'Usability') && (type != 'User Interface'))){
                console.log('Typo in the .env file type= : setting Type to default value "Acceptance"');
                rallylog.info('Typo in the .env file type= ' + "\'" + type + "\'" + ' setting Type to default value "Acceptance"');
                type = "Acceptance"
            }
        } else {
            type = 'Acceptance'
        }

        restApi = rally({
            apiKey: apiKey, //preferred, required if no user/pass, defaults to process.env.RALLY_API_KEY
            apiVersion: 'v2.0', //this is the default and may be omitted
            server: 'https://rally1.rallydev.com',  //this is the default and may be omitted
            requestOptions: {
                headers: {
                    'X-RallyIntegrationName': 'Rally Result Logger for ProUI',  //while optional, it is good practice to
                    'X-RallyIntegrationVendor': 'GE Digital',             //provide this header information
                    'X-RallyIntegrationVersion': '1.0'
                },
                proxy: proxy
            }
        });
        /**
         * RallyLogger
         */
        var RallyLogger = function () {
            return {
                /**
                 * Get the rally object ref in form of '/[Object]/12345678', e.g. '/testfolder/59651570691'
                 * @param objType     The object type.  e.g. 'project', 'testfodler', 'testcase' etc.
                 * @param objName     The name of the object, e.g. 'QE Automation Engineering'
                 * @param project/ws  The project/workspace specified in .env  i.e. 'GE Digital'/'QE Automation Engineering'
                 * @param callback  The object reference of the requested object if found or 'NOT_FOUND' otherwise.
                 */
                getObjectRef: function(objType, objName, project, ws, callback) {
                    //by object name
                    if(objName == '') {
                        console.log('No workspace/project provided - using default');
                        logger.info('No workspace/project provided - using default');
                        callback('');
                    } else {
                        var qr = queryUtils.where('name', '=', objName);
                        restApi.query({
                            type: objType, //the type to query
                            start: 1, //the 1-based start index, defaults to 1
                            pageSize: 200, //the page size (1-200, defaults to 200)
                            limit: Infinity, //the maximum number of results to return- enables auto paging
                            fetch: ['FormattedID', 'Name', 'TestCases', 'ObjectID', 'LastResult', 'RevisionHistory', 'Steps'],
                            query: qr,
                            scope: {
                                workspace: ws,
                                project: project
                            }
                        }, function (error, result) {
                            if (error) {
                                console.log(error);
                                throw error;
                            } else {
                                //console.log(result.Results);
                                var last_run = false;
                                var test_case_result_id = 0;
                                var revision_history_ref = '';
                                var obj = JSON.parse(JSON.stringify(result.Results));
                                if (obj.length > 0) {
                                    if (obj[0].LastResult != undefined) {
                                        if (obj[0].LastResult == null) {
                                            last_run = false;
                                        } else {
                                            last_run = true;
                                            test_case_result_id = obj[0].LastResult._ref;
                                            test_case_result_id = test_case_result_id.split('/');
                                            test_case_result_id = test_case_result_id[7];
                                        }
                                    } else {
                                        last_run = false;
                                    }
                                    if (obj[0].RevisionHistory != undefined) {
                                        revision_history_ref = obj[0].RevisionHistory._ref;
                                    }
                                    // if(obj[0].Steps != undefined) {
                                    //     if (obj[0].Steps.Count > 0){
                                    //         //console.log('test case has ' + obj[0].Steps.Count + ' steps');
                                    //     } else {
                                    //         //console.log('test case has no steps');
                                    //     }
                                    // }
                                    var myref = obj[0]._ref; var id = result.Results[0].ObjectID; var ref = refUtils.getRelative(myref)
                                    callback({ref:ref, id:id, last_run:last_run, test_case_result_id:test_case_result_id, revision_history_ref:revision_history_ref});
                                } else {
                                    callback('NOT_FOUND');
                                }
                            }
                        });
                    }
                },
                /**
                 * Get the rally User permissions (workspace/projects able to edit), and owner ID information
                 * @param type     The object type - only 2 used: 'workspace' and 'project'
                 * @param object   The name of the object, e.g. 'QE Automation Engineering'
                 * @param callback  The object reference of the requested object if found or 'NOT_FOUND' otherwise.
                 */
                UserPermissions: function(type, object, callback) {
                    var proj_ref='';
                    var ws_ref = '';
                    restApi.query({
                        type: 'userpermission', //the type to query
                        start: 1, //the 1-based start index, defaults to 1
                        pageSize: 200, //the page size (1-200, defaults to 200)
                        limit: Infinity, //the maximum number of results to return- enables auto paging
                        fetch: ['Workspace', 'Name', 'Project', 'ObjectID', 'User'], //the fields to retrieve
                        scope: {
                        }
                    }, function (error, result) {
                        if (error) {
                            console.error(error);
                            callback(error);
                        } else {
                            var obj = JSON.parse(JSON.stringify(result.Results));
                            if (obj.length > 0) {
                                var myref = obj[0].User._ref;
                                var ref = refUtils.getRelative(myref);
                                var owner_id = obj[0].User.ObjectID;
                                for(var i=0; i < obj.length; i++) {
                                    if(type == 'workspace') {
                                        if(obj[i].Workspace.Name == object){
                                            //console.log('found workspace - user has permissions');
                                            ws_ref = obj[i].Workspace._ref;
                                            ws_ref = refUtils.getRelative(ws_ref);
                                            break;
                                        }
                                    } else if(type == 'project') {
                                        if(obj[i].Project != undefined) {
                                            if (obj[i].Project.Name == object) {
                                                //console.log('found project - user has permissions');
                                                proj_ref = obj[i].Project._ref;
                                                proj_ref = refUtils.getRelative(proj_ref);
                                                break;
                                            }
                                        }
                                    }
                                }
                                if((i == obj.length) && (object != '')) {
                                    callback('NOT_FOUND');
                                } else {
                                    callback({owner_id:owner_id, wsRef:ws_ref, projRef:proj_ref});
                                }
                            } else {
                                callback('NOT_FOUND');
                            }
                        }
                    });
                },
                /**
                 * Get a rally user story and test set reference
                 * @param USTS   the user story. e.g. 'US6400' or testset e.g. 'TS20'
                 * @param ws/proj          the workspace and project the user story belongs to
                 * @param callback    the user story ref in the form of '/hierarchicalrequirement/1234567889'
                 */
                getUSTSRef: function (USTS, ws, proj, type, callback) {
                    if(USTS == '') {
                        callback({id: ''});
                    } else {
                        var qr = queryUtils.where('FormattedID', '=', USTS);
                        restApi.query({
                            type: type,
                            start: 1, //the 1-based start index, defaults to 1
                            pageSize: 200, //the page size (1-200, defaults to 200)
                            limit: Infinity, //the maximum number of results to return- enables auto paging
                            fetch: ['Name', 'ObjectID'],//, 'ScheduleState', 'PlanEstimate', 'Iteration'],
                            query: qr,
                            scope: {
                                workspace: ws,
                                project: proj
                            }
                        }, function (error, result) {
                            if (error) {
                                console.log(error);
                                throw error;
                            } else {
                                //console.log('query USTS' + result.Results);
                                var obj = JSON.parse(JSON.stringify(result.Results));
                                if(obj.length > 0) {
                                    var myref = obj[0]._ref;
                                    var ref = refUtils.getRelative(myref);
                                    var id = obj[0].ObjectID;
                                    //console.log('USTS ref: ' + refUtils.getRelative(myref));
                                    callback({ref: ref, id: id});
                                } else {
                                    ref = ''; id='';
                                    callback({ref: ref, id: id});
                                }

                            }
                        });
                    }
                },
                /**
                 * Create a test folder
                 * @param name test folder name from feature file
                 * @param ws   the workspace
                 * @param proj the project
                 * @param callback  returns the objectID of the newly created test folder
                 */
                createTestPlan: function (name, ws, proj, callback) {
                    restApi.create({
                        type: 'testfolder', //the type to create
                        data: {
                            Name: name,
                        },
                        fetch: ['FormattedID', 'ObjectID'],  //the fields to be returned on the created object
                        scope: {
                            workspace: ws,
                            project: proj
                        },
                        requestOptions: {} //optional additional options to pass through to request
                    }, function (error, result) {
                        if (error) {
                            console.log(error);
                            throw error;
                        } else {
                            //console.log('created test plan: ' + result.Results);
                            var testfolderRef = refUtils.getRelative(JSON.parse(JSON.stringify(result.Object)));
                            var id = result.Object.ObjectID
                            //console.log("new test folder ref" + testfolderRef);
                            callback({id: id});

                        }
                    });
                },
                /**
                 * Create a testcase
                 * @param opts - contains kObject (duration),
                 * and tcObject (parent folder id, description, name, user story, owner), and error
                 * @param ws/project workspace and project of the test case
                 * @param callback  returns the testcase ObjectID
                 */
                createTestcase: function (opts, ws, project, callback) {
                    //console.log('inside create test case function');
                    if (opts.kObj.duration == undefined) {
                        opts.kObj.duration = 0;
                    }
                    if (opts.tcObj.glb_folder_id == null) {
                        opts.tcObj.glb_folder_id = 0;
                    }
                    if (opts.tcObj.test_case_description == "") {
                        opts.tcObj.stepsArray = opts.tcObj.stepsArray.toString().split('"').join('');
                        opts.tcObj.test_case_description = "N/A<br>" + opts.tcObj.stepsArray;
                    } else {
                        opts.tcObj.stepsArray = opts.tcObj.stepsArray.toString().split('"').join('');
                        opts.tcObj.test_case_description = opts.tcObj.test_case_description + "<br>" + opts.tcObj.stepsArray;
                    }
                    restApi.create({
                        type: 'testcase', //the type to create
                        data: {
                            Name: opts.tcObj.test_case_name,
                            Description: opts.tcObj.test_case_description,
                            Method: method,
                            TestFolder: opts.tcObj.glb_folder_id,
                            WorkProduct: opts.tcObj.User_Story,
                            Owner: opts.tcObj.owner,
                            Notes: opts.error,
                            Type: type
                        },
                        fetch: ['FormattedID', 'ObjectID'],
                        scope: {
                            workspace: ws,
                            project: project
                        }
                    }, function (error, result) {
                        if (error) {
                            console.log('error: ' + error);
                            //throw error;
                            callback({id: ''});
                        } else {
                            //console.log("created test case: " + JSON.parse(JSON.stringify(result.Object)));
                            var testcaseRef = refUtils.getRelative(JSON.parse(JSON.stringify(result.Object)));
                            opts.tcObj.glb_test_case_id = result.Object.ObjectID;
                            //console.log("new testcase ref" + testcaseRef);
                            callback({id: opts.tcObj.glb_test_case_id});
                        }
                    });
                },
                /**
                 * Create a testcase result of a given testcase.
                 * @param opts     - contains duration, status, testcase ID, buildnumber
                 * @param ws/proj  - workspace and project IDs
                 * @param callback - returns id off the test case result created
                 */
                createTestcaseResult: function (opts, ws, proj, callback) {
                    if((opts.resp.duration == undefined) || (opts.resp.duration == 'undefined')
                        || (opts.resp.duration == null) || (opts.resp.duration == NaN) || (opts.resp.duration == 'NaN')) {
                        opts.resp.duration = 0;
                    } else if (opts.resp.duration > 9999999999) {
                        opts.resp.duration = 9999999999;
                    }
                    if (opts.resp.status == 'passed') {
                        opts.resp.status = 'Pass';
                    } else if (opts.resp.status == "failed") {
                        opts.resp.status = 'Fail';
                    } else if (opts.resp.status == "skipped") {
                        opts.resp.status = 'Inconclusive';
                        duration = 0;
                    }
                    restApi.create({
                        type: 'testcaseresult', //the type to create
                        data: {
                            TestCase: opts.tcObj.glb_test_case_id,
                            Build: opts.tcObj.build_num,
                            Duration: opts.resp.duration,
                            Verdict: opts.resp.status,
                            Date: (new Date).toISOString(),
                            TestSet: opts.resp.id
                        },
                        fetch: ['ObjectID'],  //the fields to be returned on the created object
                        scope: {
                            workspace: ws,
                            project: proj
                        }
                    }, function (error, result) {
                        if (error) {
                            console.log(error);
                            throw error;
                        } else {
                            //console.log(result.Object);
                            var id = result.Object.ObjectID;
                            callback({id:id});
                        }
                    });
                },
                /**
                 * Update the result of a given testcase.
                 * @param opts
                 * @param ws
                 * @param callback
                 */
                updateTestCaseResult: function(opts, ws, proj, callback) {
                    if (opts.resp.duration == undefined) {
                        opts.resp.duration = 0;
                    }
                    if ((opts.resp.duration != undefined) && (opts.resp.duration > 9999999999)) {
                        opts.resp.duration = 9999999999;
                    }
                    if (opts.resp.status == 'passed') {
                        opts.resp.status = 'Pass';
                    } else if (opts.resp.status == "failed") {
                        opts.resp.status = 'Fail';
                    } else if (opts.resp.status == "skipped") {
                        opts.resp.status = 'Inconclusive';
                        opts.resp.duration = 0;
                    }
                    restApi.update({
                        ref: '/testcaseresult/' + opts.tcObj.glb_test_result_id,
                        data: {
                            Build: opts.tcObj.build_num,
                            Duration: opts.resp.duration,
                            Verdict: opts.resp.status,
                            Date: (new Date).toISOString(),
                            TestCase:opts.tcObj.resp.ref,
                            TestSet: opts.resp.id
                        },
                        fetch: [],  //the fields to be returned on the created object
                        scope: {
                            workspace: ws,
                            project: proj
                        },
                        requestOptions: {} //optional additional options to pass through to request
                    }, function (error, result) {
                        if (error) {
                            console.log(error);
                        } else {
                            //console.log(result.Object);
                            callback();
                        }
                    });
                },
                /**
                 * Update the testcase of a given testcase.
                 * @param opts
                 * @param ws
                 * @param callback
                 */
                updateTestCase: function (opts, ws, proj, callback) {
                    if (opts.tcObj.test_case_description == "") {
                        opts.tcObj.stepsArray = opts.tcObj.stepsArray.toString().split('"').join('');
                        opts.tcObj.test_case_description = "N/A<br>" + opts.tcObj.stepsArray;
                    } else {
                        opts.tcObj.stepsArray = opts.tcObj.stepsArray.toString().split('"').join('');
                        opts.tcObj.test_case_description = opts.tcObj.test_case_description + "<br>" + opts.tcObj.stepsArray;
                    }
                    var request = require('request-promise');
                    restApi.update({
                        ref: opts.tcObj.resp.ref, //the type to create
                        data: {
                            WorkProduct: opts.resp.id,
                            Method: method,
                            Owner: opts.owner,
                            Notes: opts.error,
                            Type: type,
                            Description: opts.tcObj.test_case_description
                        },
                        fetch: ['FormattedID', 'Project'],  //the fields to be returned on the created object
                        scope: {
                            workspace: ws,
                            project: proj
                        }
                    }, function (error, result) {
                        if (error) {
                            console.log(error);
                            callback( error );
                        } else {
                            //console.log(result.Object);
                            callback();
                        }
                    });
                },
                /**
                 * Update Test Set to add test case
                 * @param tcObj             object w/  User_Story, resp, j, test_case_name, test_case_description, glb_folder_id,
                 * build_num, testset, glb_test_case_id, glb_test_result_id, last_run, glb_i_length, glb_j_length
                 * @param resp              resonse from query TestSet
                 * @param callback          callback on error and http response
                 */
                updateTestSet: function(tcObj, resp, callbck){
                    var request = require('request-promise');
                    var to_return;
                    if(resp.id == ''){
                        to_return = {
                            id:'', status:resp.status, duration:resp.duration, glb_test_case_id:resp.glb_test_case_id,
                            glb_folder_id:tcObj.glb_folder_id, json:resp.json, i:resp.i, j:resp.j, k:k
                        };
                        callbck(to_return);
                    } else {
                        to_return = {
                            id: resp.id, status: resp.status, duration: resp.duration,
                            glb_test_case_id: resp.glb_test_case_id, glb_folder_id: tcObj.glb_folder_id, json: resp.json,
                            i: resp.i, j: resp.j, k: k
                        };
                        var options = {
                            method: 'POST',
                            url: 'https://rally1.rallydev.com/slm/webservice/v2.x/TestSet/' + resp.id + '/TestCases/add?fetch=true',
                            headers: {zsessionid: apiKey},
                            proxy: proxy,
                            body: '{"CollectionItems":[{"_ref":"/testcase/' + tcObj.glb_test_case_id + '"}]}'
                        };
                        request(options)
                            .then(function (body, error) {
                                //console.log('updated test set: ' + body);
                                callbck(to_return);
                            });
                    }
                }
            }
        };
        module.exports = new RallyLogger();
    })();