// (C) Copyright 2020 Hewlett-Packard Enterprise Company, L.P.
/* This is a mockup file used to generated mockup data for HPSUM.
 * This will be removed once HPSUM UI is integrated with complete RESTful APIs or HAPI 
 * IndexService is populated with the mockup data for baseline and other HSPUM resources.
 * When HAPI is integrated with HPSUM UI, then this file will not be used.
 */
define(['hp/services/IndexService',
    'hp/services/Log',
    'hpsum/model/node/NodeResource',
    'hp/lib/date'],
function(indexService, log, nodeResource) { "use strict";

    var HpsumMock = (function() {
      
      	//Number of baseline records needs to be simulated to generate mockup data
        var NUM_BASELINES = 5; 
		var NUM_ENCLOSURES = 4;
        var NUM_SERVERS = 100;
        var NUM_SWITCHES = 4;
		var NUM_HOSTS = 10; ///500;
		var NUM_VOLUMES = 8;
		var NUM_RACKS = 2;
		var MAX_ALERTS_PER_NODE = 4;
        var MAX_TASKS_PER_NODE = 1;
		var TRIM_FOR_LINK_TESTING = false;	
		  var ALERT_TEXTS = [
          'The Power Supply is Degraded on Chassis [chassis 1], Status Major, Model %s, Serial Num %s, Firmware %s.',
          'Memory Board or Cartridge Bus Errors Detected in Slot 3, Cpu 1, Riser 1.',
          'Accelerator lost battery power.  Data Loss possible.',
          'Temperature out of range on Chassis [chassis 1], Location 3. Shutdown may occur.',
          'Onboard Administrator or other mangement processor has taken the role of primary, in enclosure enc-001, in rack rack-1.',
          'Correctable \ uncorrectable memory errors require a replacement of the memory module in slot 14, cpu 4, riser 1,socket 1.'
          ];
        var TEST_NAMES = [
          'iLO', 'CPU_Clock_Speed', 'phys_drive', 'App_rpm', 'p700_ctrl-fwt',
          'CPU_Count', 'Phys_Mem', 'OSVer', 'hp_cpq_cciss_ver'
          ];
          
        var NO_ACTIVITY_URI = '/server/item5';
	
		var NUM_NODES = 12;
		var MAX_COMPLIANCE_TESTS_PER_NODE = 1;
		function HpsumMock() {
          
            var alertIndex = 0;
            var taskIndex = 0;
            var complianceTestIndex = 0;
          
            function associate(name, parentType, childType, countPer, reuse) {
                var parents = indexService.getSimulatedItems(parentType).slice(0);
                var children = indexService.getSimulatedItems(childType).slice(0);
                var parent, child, i;
                while (parent = parents.shift()) {
                    for (i=0; i<countPer; i+= 1) {
                        child = children.shift();
                        if (! child) {
                            break;
                        }
                        indexService.addAssociation(name, parent, child);
                        if (reuse) {
                          children.push(child);
                        }
                    }
                }
            }
			
			function generateTasks(item, taskCount) {
                var j, date, noteDate, status, state, progress, step, name, task;
                
                if (item.changing) taskCount += 1;
                date = new Date();
                for (j = 1; j <= taskCount; j += 1) {
                    date = new Date(date.getTime() - (1000 * 60 * (taskIndex * 17))
                        - (1000 * taskIndex));
                    noteDate = new Date(date.getTime() + (1000 * 60 * 5));
                    state = ((j == 0 && item.changing) ? 'running' :
                          ['pending', 'running', 'finished'][taskIndex % 3]);
                    switch (state) {
                      case 'pending':
                        progress = 0;
                        status = 'unknown';
                        step = "(pending)";
                        name = ['add', 'update', 'reset', 'delete'][taskIndex % 4];
                        break;
                      case 'running':
                        progress = (taskIndex % 80) + 10;
                        status = 'unknown';
                        step = 'step ' + Math.ceil(progress / 10);
                        name = ['adding', 'updating', 'resetting', 'deleting'][taskIndex % 4];
                        break;
                      case 'finished':
                        progress = 100;
                        status = ['ok', 'warning', 'error'][taskIndex % 4]
                        step = "(finished)";
                        if ('ok' === status) {
                            name = ['added', 'updated', 'reset', 'deleted'][taskIndex % 4];
                        } else {
                            name = ['add', 'update', 'reset', 'delete'][taskIndex % 4];
                        }
                        break;
                    }
                    
                    
                    task = {
                        category: 'task',
                        name: name,
                        uri: '/task/' + taskIndex,
                        status: status,
                        changing: ('running' === state),
                        sourceUri: item.uri,
                        sourceName: item.name,
                        date: date.toISOString(),
                        state: state,
                        progress: progress,
                        progressStep: step,
                        owner: ['Sam', 'Wilma', 'Fred'][taskIndex % 3],
                        notes: (taskIndex % 2 ? [{user: 'Sam',
                            text: 'Installing cp0011010.exe',
							textDetails: ['Memory Board or Cartridge Bus Errors Detected in Slot 3, Cpu 1, Riser 1.','Temperature out of range on Chassis [chassis 1], Location 3. Shutdown may occur.'],
                            date: noteDate.toISOString()},{user: 'Sam',
                            text: 'Discovery Done',
							textDetails: ['Memory Board or Cartridge Bus Errors Detected in Slot 3, Cpu 1, Riser 1.','Temperature out of range on Chassis [chassis 1], Location 3. Shutdown may occur.'],
                            date: noteDate.toISOString()},{user: 'Sam',
                            text: 'Schedule created',
							textDetails: item.uri,
                            date: date.toISOString()}] : []),
						history: ('finished' !== state ? null :
                            [{date: date.toISOString(), step: 'step 1'},
                             {date: date.toISOString(), step: 'step 2'}])
                    };
                    task.taskStatus = task.status;
                    task.taskState = task.state;
                    task.modified = task.date;
                    task.percentComplete = task.progress;
                    indexService.addItem('task', task);
                    //indexService.addItem('activity', task);
                    taskIndex += 1;
                }
            }
        
        	//This function iteratively populate IndexService with different types of data
        	//such as Baseline, nodes etc    
			function generateType(prefix, type, count, physical,
                alertCount, taskCount, complianceTestCount , attr) {
                
                var i, status, name, item,state;
                indexService.addCategory(type);
                                
                for (i = 1; i <= count; i += 1) {
                    name = prefix + type + ' ' + i;
                    // make most 'ok'
                    if (i % 2 === 0) {
                        status = ['all', 'scanning', 'scan-complete', 'scheduled','web','error'][i % 6];
                        state ='idle';
                    } else {
                      //name += ' make it much longer to see what happens'; /// !!!
                        status = 'ok';
                        state = 'inventory';
                    }
                    //Adding an entry of a particular type of resource (defined in type variable) into IndexService
                    item = indexService.addItem(type, {
                        category: type,
                        name: name,
                        location: 'C:\\spp',
                        uri: '/' + type + '/item' + i,
                        status: status,
                        changing: ((i % 3) === 0),
                        updatedAt: (new Date()).toISOString(),
                        state :state,
                        stateDetails: ('error' !== status ? '' :
                            {summary: 'Need Credentials ',
                             details:
                              '<p>' + name + ' has an ' + status + '.</p>' + '<a href="#/node/edit/credentials"> Need Credentials</a>'+
                              '<p>We have no idea why.</p>'}),
                        index: i,
                        attributes: attr
                    });
                    if (physical) {
                        item.attributes.model = type[0] + 'M-800' + (i % 3);
                    }
					
					var alertTemplate = {
                        category: 'alert',
                        sourceUri: item.uri,
                        sourceName: item.name,
                        notes: []
                    };
				
					var alert = $.extend({name: 'Added Service Pack for Proliant baseline 1.',
                        uri: '/alert/alert-t1',
                        status: 'info', owner: 'Swamy', state: 'active',
                        date: hoursAgo(36).toISOString()}, alertTemplate);
                    addAlert(alert);
				
                    generateAlerts(item, alertCount);
                
					generateTasks(item, taskCount);
                }
            }
             function generateAlerts(item, alertCount) {
                var j, date, noteDate, status, state, name, alert, count;
                alertCount = (TRIM_FOR_LINK_TESTING ? 2 :
                    ((item.index % alertCount) + 1));
                date = new Date();
                for (j = 1; j <= alertCount; j += 1) {
                    date = new Date(date.getTime() - (1000 * 60 * (alertIndex * 7))
                        - (1000 * alertIndex));
                    noteDate = new Date(date.getTime() + (1000 * 60 * 5));
                    status = (0 === j ? item.status :
                        ['ok', 'warning', 'error'][alertIndex % 3]);
                    state = ('ok' === item.status ? 'cleared' : 'active');
                    name = ALERT_TEXTS[alertIndex % 6];
                    if ('ok' === status) {
                        name = 'Health status is OK';
                    }
                        
                    alert = {
                        category: 'alert',
                        name: name,
                        uri: '/alert/' + alertIndex,
                        status: status,
                        sourceUri: item.uri,
                        sourceName: item.name,
                        date: date.toISOString(),
                        state: state,
                        alertCategory: ['CPU', 'Chassis'][alertIndex % 2],
                        owner: [null, 'Sam', 'Wilma', 'Fred'][alertIndex % 4],
                        notes: (alertIndex % 2 ? [{user: 'Sam',
                            text: 'Can someone look into this?',
                            date: noteDate.toISOString()}] : [])
                    };
                    indexService.addItem('alert', alert);
                    //indexService.addItem('activity', alert);
                    alertIndex += 1;
                }
            }
            //Add alerts into indexservice
            function addAlert(alert) {
                indexService.addItem('alert', alert);
            }
            
            //Add tasks into indexservice
            function addTask(task) {
                indexService.addItem('task', task);
                //indexService.addItem('activity', task);
            }
            
            function hoursAgo(hours) {
                var now = new Date();
                return new Date(now.getTime() - (1000 * 60 * 60 * hours));
            }
            
            function update() {
                var item = indexService.getSimulatedItem('/host/item1');
                if (item) {
                    item.attributes.model = (new Date()).toISOString();
                }
            }
			// For specific testing scenarios
            function customize() {
                var item = indexService.getSimulatedItem('/server/item5');
                if (item) {
                    item.status = 'warning';
                    item.changing = true;
                    var alertTemplate = {
                        category: 'alert',
                        sourceUri: item.uri,
                        sourceName: item.name,
                        notes: []
                    };
                    var taskTemplate = {
                        category: 'task',
                        sourceUri: item.uri,
                        sourceName: item.name,
                        notes: [],
                        history: []
                    };
                    var alert, task;
                    task = $.extend({name: 'Updating firmware', uri: '/task/task-t1',
                        status: 'unknown', changing: true, owner: 'Sam', state: 'running',
                        date: hoursAgo(0.2).toISOString(),
                        progress: 1, progressStep: 'step 1'}, taskTemplate);
                    var activeTask = task;
                    addTask(task);
                    task = $.extend({name: 'Reapply profile', uri: '/task/task-t2',
                        status: 'error', changing: false, owner: null, state: 'finished',
                        date: hoursAgo(24).toISOString()}, taskTemplate);
                    addTask(task);
                    alert = $.extend({name: 'Connectivity lost for adapter in slot 1, port 1.',
                        uri: '/alert/alert-t1',
                        status: 'warning', owner: 'Sarah', state: 'active',
                        date: hoursAgo(36).toISOString()}, alertTemplate);
                    addAlert(alert);
                    alert = $.extend({name: 'Health status is OK',
                        uri: '/alert/alert-t2',
                        status: 'ok', owner: null, state: 'active',
                        date: hoursAgo(96).toISOString()}, alertTemplate);
                    addAlert(alert);
                    task = $.extend({name: 'Powered on', uri: '/task/task-t3',
                        status: 'ok', changing: false, owner: 'Sam', state: 'finished',
                        date: hoursAgo(96.1).toISOString()}, taskTemplate);
                    addTask(task);
                    alert = $.extend({name: 'The server could not be powered on',
                        uri: '/alert/alert-t3',
                        status: 'error', owner: null, state: 'cleared',
                        date: hoursAgo(97).toISOString()}, alertTemplate);
                    addAlert(alert);
                    task = $.extend({name: 'Power on', uri: '/task/task-t4',
                        status: 'error', changing: false, owner: 'Sam', state: 'finished',
                        date: hoursAgo(97.1).toISOString()}, taskTemplate);
                    addTask(task);
                    task = $.extend({name: 'Powered off', uri: '/task/task-t5',
                        status: 'ok', changing: false, owner: 'Sam', state: 'finished',
                        date: hoursAgo(120).toISOString()}, taskTemplate);
                    addTask(task);
                    alert = $.extend({name: 'Correctable memory errors require a replacement of the memory module in slot 1, socket 1.',
                        uri: '/alert/alert-t4',
                        status: 'warning', owner: 'Sam', state: 'cleared',
                        date: hoursAgo(144).toISOString()}, alertTemplate);
                    addAlert(alert);
                    task = $.extend({name: 'Added', uri: '/task/task-t6',
                        status: 'ok', changing: false, owner: 'Sarah', state: 'finished',
                        date: hoursAgo(312).toISOString()}, taskTemplate);
                    addTask(task);
                
                    var timer = setInterval(function () {
                        activeTask.progress += 1;
                        activeTask.progressStep = "step " + activeTask.progress;
                        if (activeTask.progress >= 100) {
                            clearInterval(timer);
                            item.changing = false;
                            activeTask.status = 'ok';
                            activeTask.changing = false;
                            activeTask.progressStep = undefined;
                        }
                    }, 3000);
                }
            }
			//This is the initialization function for this mock object
            this.init = function() {
                generateType('Service Pack for Proliant ', 'baseline',
                    NUM_BASELINES, false, 0 , 0,0,{version:'2012.10.07', size:'2.3 GB'});
				nodeResource.init(0);	
				generateType('', 'enclosure', NUM_ENCLOSURES, true, 0, 0, 0, {});
				generateType('', 'switch', NUM_SWITCHES, true,
                    MAX_ALERTS_PER_NODE, 0, 0, {});
                generateType('', 'fc_switch', NUM_SWITCHES, true,
                    MAX_ALERTS_PER_NODE, 0, 0, {});
                generateType('', 'windows', NUM_SERVERS/2, true,
                    MAX_ALERTS_PER_NODE, MAX_TASKS_PER_NODE, 0, {});
                generateType('', 'linux', NUM_SERVERS/2, true,
                    MAX_ALERTS_PER_NODE, MAX_TASKS_PER_NODE, 0, {});
                generateType('', 'hpux', NUM_SERVERS/2, true,
                    MAX_ALERTS_PER_NODE, MAX_TASKS_PER_NODE, 0, {});
                
				generateType('', 'host', NUM_HOSTS, false, MAX_ALERTS_PER_NODE, 0, 0, {});
				generateType('', 'volume', NUM_VOLUMES, false, 0, 0, 0, {});
				generateType('', 'rack', NUM_RACKS, true, 0, 0, 0, {});
				
				associate('ENCLOSURE_TO_SERVER', 'enclosure', 'windows', 4);
                associate('ENCLOSURE_TO_SWITCH', 'enclosure', 'switch', 2);
                associate('ENCLOSURE_TO_SWITCH', 'enclosure', 'fc_switch', 1);
                associate('SERVER_TO_SWITCH', 'windows', 'switch', 3, true);
                associate('SERVER_TO_SWITCH', 'linux', 'fc_switch', 1, true);
				associate('BUNDLE_TO_ENCLOSURE', 'baseline', 'enclosure', 2);
                associate('BUNDLE_TO_SERVER', 'baseline', 'windows', 2);
				customize();
			};
            
            this.generate = function (type, count) {
                generateType('', type, count, true, 0);
            };
            
            //This function establish association between two resources
            //For example, Baseline associated with nodes, OA is associated with iLO, VC etc.
            this.associate = function (name, parentType, childType, count, reuse) {
                associate(name, parentType, childType, count, reuse);
            };
        }

        return new HpsumMock();
    }());
    
    return HpsumMock;
});
