/**
 Description: Switch Service
 Copyright (c) 2016 by Cisco Systems, Inc.
 All rights reserved.
 */

/**
 Description: Switch data service provides all the capabilities of the switch
 			  and the data required to render the switch view.
 Copyright (c) 2016 by Cisco Systems, Inc.
 All rights reserved.
 */
app.service("switchDataService4Stack",['$rootScope','requestRoutingService',function($rootScope,requestRoutingService){
	
	this.getSwitchViewData = function($scope){
		var switchViewData = {};
		$scope.showRestart = (location.hash.indexOf("troubleShoot") != -1);
		//set coap Status for selecon device
		
		if($rootScope.deviceInfo.type.indexOf("CDB")!=-1){		
			switchViewData.coapStatus = true;	
    		var coapStatus = requestRoutingService.getShowCmdOutput("show coap stats");
    		if(coapStatus.indexOf("COAP is disabled")!=-1){
    			switchViewData.coapDisabledStatus=true;
    			switchViewData.coapEnabledStatus=false;
    		}else{
    			switchViewData.coapEnabledStatus=true;
    			switchViewData.coapDisabledStatus=false;
    		}
        }else{
			switchViewData.coapEnabledStatus=false;
    		switchViewData.coapDisabledStatus=false;
		}
		
		//Set hostname
		var hname = requestRoutingService.getShowCmdOutput("show running-config | i hostname");
		var sn = "";
		sn = deviceCommunicator.getExecCmdOutput("show version | i System serial number").split("\n")[0];
		if(sn != ""){
                	sn = sn.split(":")[1];
                	console.log("serial number is "+sn);
		}
		switchViewData.hostname = hname.split(' ')[1].trim();
		
		//Set master swicth id and number of switches
		switchViewData.noOfSwitches = 1;
		switchViewData.masterSwitchId = 1;
		if($rootScope.deviceInfo.type == "WS-C3560CX-12PD-S" || $rootScope.deviceInfo.type == "WS-C3560CX-8XPD-S"){
                        switchViewData.masterSwitchId = $rootScope.deviceInfo.masterId;
                }	
		var stackDetails = [];
		if($rootScope.deviceInfo.isStackingSupported == true){
			switchViewData.masterSwitchId = deviceCommunicator.getExecCmdOutput("show switch | i Master ").split(" ")[0].replace("*","");
                        var result = requestRoutingService.getShowCmdOutput("show switch", "showSwitch");
                        stackDetails = result.Switch.SwitchStatus.entry;
                        var versionInfo = deviceCommunicator.getExecCmdOutput("show version | begin Switch Ports");
                        var tempArr = versionInfo.split("\n");                         
                        var switchesArray = tempArr.splice(2,tempArr.length-3);        
                        switchesArray = switchesArray.splice(0,stackDetails.length);
                        if(switchesArray.length > 1){
                                stackDetails = switchesArray;
                        }
		}	
		//Add the individual switches and the capabilities
		var powerStatus = null;
		if($rootScope.deviceInfo.isPoECapable){
			powerStatus = requestRoutingService.getShowCmdOutput("show power inline", "portsMonPower");
		}
		var ifStatus = requestRoutingService.getShowCmdOutput("show interface status", "portsMonStatus");

		//console.log("-----");
		//console.log(ifStatus);
		//console.log(powerStatus);
		//console.log("-----");
		
		var switchNoIndexInName = 0;
		var portNumberIndexInName = 1;
		
		//Identify the ports in each group
		var groupSize = 12;
		if(parseInt($rootScope.deviceInfo.numberOfPorts) === 8 || parseInt($rootScope.deviceInfo.numberOfPorts) === 16){
			groupSize = 8;
		} else if(parseInt($rootScope.deviceInfo.numberOfPorts) === 12){
                        groupSize = 4;
                }
                //var totalNumberOfGroups = Math.floor(ifStatus.Port.InterfaceStatus.entry.length / groupSize);
                var totalNumberOfGroups = Math.floor(parseInt($rootScope.deviceInfo.numberOfPorts) / groupSize);
		
		//for (var p in powerStatus.ShowPowerInline.PowerTable.entry){ console.log(powerStatus.ShowPowerInline.PowerTable.entry[p]);}
		//for (var p in ifStatus.Port.InterfaceStatus.entry){ console.log(ifStatus.Port.InterfaceStatus.entry[p]);}
		//What position is port number at? in Gig0/0/1 as against Gig0/1
                portNumberIndexInName = ifStatus.Port.InterfaceStatus.entry[0].Port.split("/").length - 1;

		var totalPorts = switchViewData.noOfSwitches * parseInt($rootScope.deviceInfo.numberOfPorts);
		switchViewData.switches = [];
		
		var switchNo = 1;
		for(; switchNo <= switchViewData.noOfSwitches; switchNo++){
			var switchObject = {};
			switchObject.id = 1; //Hard code for now. Will be dynamic in 2960X with stacking
			switchObject.sn = sn;
			//TODO: in stacked switches, the MAC address has to be got for each switch from "show sw" o/p
			switchObject.macAdd =  $rootScope.deviceInfo.baseMacAdd; //TODO for stacks
			switchObject.showRestart = $scope.showRestart;
			switchObject.isPoECapable = $rootScope.deviceInfo.isPoECapable;
			switchObject.isStackConfigurable = $rootScope.deviceInfo.isStackingSupported;
			if(switchNo == 1) switchObject.iscoapVisible = true;
			switchObject.ports = [[[]]];
			switchObject.uplinkports = [];
			switchViewData.switches[switchNo-1] = switchObject;
		}
		
		if( parseInt($rootScope.deviceInfo.numberOfPorts) == 8 ){
			totalNumberOfGroups = 1;
		} else if(parseInt($rootScope.deviceInfo.numberOfPorts) == 12){
                        totalNumberOfGroups = 3;
                }
		//The subgroups can either be 4 or 6. When ports are 8 or 16, subgroups are 4, and for 24 or 48 ports subgroups are 6
		var totalNumberOfSubgroups = (parseInt($rootScope.deviceInfo.numberOfPorts)%6)==0?6:4;
		if(parseInt($rootScope.deviceInfo.numberOfPorts) == 12){
                        totalNumberOfSubgroups = 2;
                }
	
		var index1, index2;
		for(index1 = 0; index1 < totalNumberOfGroups; index1++ ){
			switchObject.ports[index1] = [];
			for(index2 = 0; index2 < totalNumberOfSubgroups; index2++ ){ 
				switchObject.ports[index1][index2] = [];
				switchObject.ports[index1][index2][0] = {};
				switchObject.ports[index1][index2][1] = {};
			}
		}
		
		//Update port/uplinkport data
		var tempArray = ifStatus.Port.InterfaceStatus.entry;
		if($rootScope.deviceInfo.isPoECapable){
			for (var powerEntryIndex in powerStatus.ShowPowerInline.PowerTable.entry ){
				var powerEntry = powerStatus.ShowPowerInline.PowerTable.entry[parseInt(powerEntryIndex)];
				var wattage = parseFloat(powerEntry.Power);
				if(wattage != 0 && !isNaN(wattage)){
					for(var index=0; index < tempArray.length; index++){
						if(tempArray[index].Port === powerEntry.Interface){
							tempArray[index].poe = true;
							tempArray[index].power = wattage;
						}
					}
				}	
			}
		}
		
		for (var p in tempArray){ 
			p = parseInt(p);
			//console.log(ifStatus.Port.InterfaceStatus.entry[p]);
			var uniqueId = ifStatus.Port.InterfaceStatus.entry[p].Port;

			//Ignore management port and logical ports
			if (uniqueId.substr(0,2) == "Po" || uniqueId === "Fa0"){
				continue;
			}
			var portNameParts = uniqueId.split('/');
			var switchID = parseInt(portNameParts[switchNoIndexInName].substr(2)) || 1;
                        if(switchID != switchViewData.masterSwitchId){
                                continue;  //Port does not belong to master switch. Ignore
                        }
			var switchNumber  = 1; //parseInt(portNameParts[switchNoIndexInName].substr(2)) || 1;
			var portNumber = parseInt(portNameParts[portNumberIndexInName]);
			var duplex = "auto";
			if(ifStatus.Port.InterfaceStatus.entry[p].Duplex.indexOf("full") >= 0){
				duplex = "full";
			} else if(ifStatus.Port.InterfaceStatus.entry[p].Duplex.indexOf("half") >= 0){
				duplex = "half";
			}
			var speed = 0;
			var status = 1;
			if(ifStatus.Port.InterfaceStatus.entry[p].Status === "disabled"){
				status = 2;
			} else if(ifStatus.Port.InterfaceStatus.entry[p].Status === "notconnect"){
				status= 0;
			} else if(ifStatus.Port.InterfaceStatus.entry[p].Status === "err-disabled"){
                                status= 3;
                        }
			if(status == 1){
				if(ifStatus.Port.InterfaceStatus.entry[p].Speed.indexOf('10000') >= 0 || 
					ifStatus.Port.InterfaceStatus.entry[p].Speed == "10G"){
                                        speed = 10000;
                                } else if (ifStatus.Port.InterfaceStatus.entry[p].Speed.indexOf('1000') >= 0){
					speed = 1000;
				} else if (ifStatus.Port.InterfaceStatus.entry[p].Speed.indexOf('100') >= 0){
					speed = 100;
				} else {
					speed = 10;
				}
			}
			
			var groupNoDiv = Math.floor(portNumber / groupSize);
			var groupNoMod = portNumber % groupSize;
			var groupNo = null;
			if(groupNoDiv == 0 && groupNoMod != 0){
				groupNo = groupNoDiv;
			} else if (groupNoDiv != 0 && groupNoMod == 0){
				groupNo = groupNoDiv-1; //last entry to go into the group
			} else{
				groupNo = groupNoDiv;
			}
			
			//Construct the port object
			var portObject = {};
			portObject.portNo = portNumber;
			portObject.uniqueId = uniqueId
			portObject.status = status;
			portObject.speed = speed;
			portObject.duplex = duplex;
			var isUplinkPort = (parseInt($rootScope.deviceInfo.numberOfPorts) % portNumber === parseInt($rootScope.deviceInfo.numberOfPorts));
			if( $rootScope.deviceInfo.type.indexOf("CDB-") != -1 || $rootScope.deviceInfo.type.indexOf("C2960+") != -1 || 
					($rootScope.deviceInfo.type.indexOf("C2960C") != -1 && $rootScope.deviceInfo.type.indexOf("C2960CX") == -1 
						&& $rootScope.deviceInfo.type.indexOf("C2960CG") == -1)){
				isUplinkPort = (uniqueId.indexOf("Gi") != -1);
			} else if($rootScope.deviceInfo.type.indexOf("3560CX") != -1 || $rootScope.deviceInfo.type.indexOf("2960X") != -1){
                                isUplinkPort = ((uniqueId.indexOf("Te") != -1) && portNumber <= 4 ) ||
                                                        (parseInt($rootScope.deviceInfo.numberOfPorts) % portNumber === parseInt($rootScope.deviceInfo.numberOfPorts));
                        }
			if(tempArray[p].poe == undefined && !isUplinkPort){ //No power on this port
				portObject.poe = false; //Set default, will be updated after fetching value
				portObject.power = 0; //Set default, will be updated after fetching value
			}else{
				portObject.poe = true; 
				portObject.power = tempArray[p].power;
			}
			
			if(isUplinkPort){
				//Entry goes into the uplink ports array
				switchViewData.switches[switchNumber-1].uplinkports.push(portObject);
			} else {
				//Entry goes into the ports array
				var subGroupNo = Math.ceil((portNumber % groupSize) /2);
				if(subGroupNo == 0){
					subGroupNo = groupSize/2;
				}
				var portPosition = (portNumber+1) % 2;
				
				//console.log("port"+groupNo+","+parseInt(subGroupNo-1)+","+portPosition+" is "+portObject);
				switchViewData.switches[switchNumber-1].ports[groupNo][subGroupNo-1][portPosition] = portObject;
			}
		
		}
		if($rootScope.deviceInfo.stackingInfo.type === "CLUSTER"){ //Add condition for cluster check
			var candidates = requestRoutingService.getShowCmdOutput("show cluster candidates", "showClusterCandidates"); 
			var members = requestRoutingService.getShowCmdOutput("show cluster members", "showClusterMembers"); 

			//Add Members
			try{
				if(Object.prototype.toString.call( members.ShowClusterMember.MemberTable.entry ) === '[object Array]'){
				var clusterCmdr = deviceCommunicator.getExecCmdOutput("show cluster members | i Cmdr").split(" ")[0];
				for (var memberIndex in members.ShowClusterMember.MemberTable.entry ){
					var member = members.ShowClusterMember.MemberTable.entry[memberIndex];
					var macAddress = member.macAddress;
                                        var hostname = member.Switch;
                                        var serialNo = member.snValue;
					if(serialNo === clusterCmdr){
						continue;//Its a self member, maagement switch. dont show as member. its commander
					}
                                        if(member.state === "Up"){
                                                var x = this.getClusterCandidateSwitch(24,macAddress,serialNo,!$scope.showRestart);
                                                switchViewData.switches.push(x);
                                        }else{
                                                //Add dummy member
                                                var x = this.getClusterCandidateSwitch(24,macAddress,serialNo,!$scope.showRestart);
                                                switchViewData.switches.push(x);
                                        }
				}
				}else{
					//Its a single member, self. So dont worry
				}
			} catch(e){
				console.log(e);
			}	

			//Add Candidates
			if( !$scope.showRestart){
			try{
				var id = 51;
				if(Object.prototype.toString.call( candidates.ShowClusterCandidates.CandidateTable.entry ) === '[object Array]'){
					for (var candidate in candidates.ShowClusterCandidates.CandidateTable.entry ){
						var x = this.getClusterCandidateSwitch(24,
								candidates.ShowClusterCandidates.CandidateTable.entry[candidate].macAddress,id,false);
						switchViewData.switches.push(x);
						id++;
					}
				} else if (Object.prototype.toString.call( candidates.ShowClusterCandidates.CandidateTable.entry )=== "[object Object]"){
					var x = this.getClusterCandidateSwitch(24,
								candidates.ShowClusterCandidates.CandidateTable.entry.macAddress,id,false);
						switchViewData.switches.push(x);
				} else {
					console.log("No candidates present");
				}
			} catch(e){
				console.log(e);
			}
			}
		} else if($rootScope.deviceInfo.stackingInfo.type === "STACK") {
			//Required to provide restart functionality
			if(stackDetails.length > 0){
                        for (var i=0; i < stackDetails.length; i++){
                                if(stackDetails[i].indexOf("*") != -1){
                                        continue; //Master has been already added. Ignore it.
                                }
                                var member = stackDetails[i].match(/\S+/g) || [];
                                if(member.length > 0){
                                        try{    
                                                var memberId = member[0];
                                                var noOfPorts = member[1];
                                                var type = member[2];
                                                var cli = "show switch " + memberId;
                                                var mac = deviceCommunicator.getExecCmdOutput(cli).split("\n")[4]. match(/\S+/g)[2];
                                                var slaveSwitch = this.getStackSlaveData(memberId,noOfPorts,type,mac);
                                                switchViewData.switches.push(slaveSwitch);
                                        } catch(e){
                                                console.log(e);
                                        }
                                }
                        }
                	}
		}	
		return switchViewData;
	};

	this.getClusterCandidateSwitch = function(noOfPorts,macAdd,id,isMember){
		var groupSize = 12;
                if(noOfPorts === 8 ||  noOfPorts === 16){
                        groupSize = 8;
                }
		var totalNumberOfGroups = noOfPorts / groupSize;
                if( noOfPorts == 8 ){
                        totalNumberOfGroups = 1;
                }
		//The subgroups can either be 4 or 6. When ports are 8 or 16, subgroups are 4, and for 24 or 48 ports subgroups are 6
                var totalNumberOfSubgroups = (noOfPorts%6)==0?6:4;

		
		var switchObject = {};
		switchObject.id = id; 
		switchObject.showRestart = (location.hash.indexOf("troubleShoot") != -1); 
		if(switchObject.showRestart == false){
			switchObject.isCandidate = !isMember; 
			switchObject.isMember = isMember; 
		}

		//This is a workaround for CSCvc17135
		switchObject.showRestart = false;//(location.hash.indexOf("troubleShoot") != -1); 

		switchObject.macAdd =  macAdd;
		switchObject.isPoECapable = false;
		switchObject.isStackConfigurable = false;
		switchObject.ports = [[[]]];
		switchObject.uplinkports = [];
		var index1, index2;
		var portNumber = 0;
		return switchObject;//Keep it dummy for now. There is nothing to show in cluster	
                for(index1 = 0; index1 < totalNumberOfGroups; index1++ ){
                        switchObject.ports[index1] = [];
                        for(index2 = 0; index2 < totalNumberOfSubgroups; index2++ ){
				var port1 = new Object();
				var port2 = new Object();
				port1.poe = false;
                		port1.portNo = "";
                		port1.uniqueId = "";
                		port1.status = "0";
                		port1.speed = "0";
                		port1.duplex = "auto";
                		port1.power = 0;
                		port1.portNo = ++portNumber;
				port2.poe = false;
                		port2.portNo = "";
                		port2.uniqueId = "";
                		port2.status = "0";
                		port2.speed = "0";
                		port2.duplex = "auto";
                		port2.power = 0;
                		port2.portNo = ++portNumber;

                                switchObject.ports[index1][index2] = [];
                                switchObject.ports[index1][index2][0] = port1;
                                switchObject.ports[index1][index2][1] = port2;
                        }
                }
		return switchObject;
	};

	this.getStackSlaveData = function(memberId,noOfPorts,type,mac){
                var groupSize = 12;
                if(noOfPorts === 8 ||  noOfPorts === 16){
                        groupSize = 8;
                }       
                var totalNumberOfGroups = Math.floor(noOfPorts / groupSize);
                if( noOfPorts == 8  || noOfPorts == 16){  
                        totalNumberOfGroups = 1;
                }
                //The subgroups can either be 4 or 6. When ports are 8 or 16, subgroups are 4, and for 24 or 48 ports subgroups are 6
		var totalNumberOfSubgroups = 4;
                if(noOfPorts >= 24){
                	totalNumberOfSubgroups = 6;
                }
                
                var switchObject = {};
                switchObject.id = memberId;  
                switchObject.macAdd =  mac; 
		switchObject.showRestart = (location.hash.indexOf("troubleShoot") != -1);
                switchObject.isPoECapable = (type.split('-')[2].indexOf('P') != -1);
		var poeData = [];	
		if(switchObject.isPoECapable){
			//Fetch power inline
			var powerStat = deviceCommunicator.getExecCmdOutput("show power inline module " + memberId);
			poeData = powerStat.split("\n");
			poeData = poeData.splice(7);
		}
		//Fetch interface info, ignore management interface
		var intStat = deviceCommunicator.getExecCmdOutput("show interface status module " + memberId); 
		var intData = intStat.split("\n");
		intData = intData.splice(1);
                switchObject.isStackConfigurable = false;
                switchObject.ports = [[[]]];
                switchObject.uplinkports = []; 
                var index1, index2;
                var portNumber = 0;
                for(index1 = 0; index1 < totalNumberOfGroups; index1++ ){
                        switchObject.ports[index1] = [];
                        for(index2 = 0; index2 < totalNumberOfSubgroups; index2++ ){
                                var port1 = new Object();
                                var port2 = new Object();
                                port1.poe = false;
				var power = "";
                                port1.power = 0;

				// interface will be of the format
                    		// "Gi1/0/48                     notconnect   148          auto   auto 10/100/1000BaseTX"
                    		// Extract various fields

				var interface = intData[portNumber]; 
				if(switchObject.isPoECapable){
					power = poeData[portNumber];
					power = power.match(/\S+/g)  || [];
                                	port1.power = parseFloat(power[3]);
					if(port1.power > 0){
						port1.poe = true;
					}
				}
                                port1.uniqueId = interface.substr(0,8).trim();
				var stat = interface.substr(29,12).trim();
                                port1.status = this.getStatus(stat);
                                port1.speed = (stat == "connected" ? this.getSpeed(interface.substr(60,7).trim()) : 0);
                                port1.duplex = interface.substr(52,8).trim();
                                port1.portNo = ++portNumber;

                                port2.poe = false;
                                port2.power = 0;
				interface = intData[portNumber]; 
				if(switchObject.isPoECapable){
					power = poeData[portNumber];
					power = power.match(/\S+/g)  || [];
					port2.power = parseFloat(power[3]);
					if(port2.power > 0){
						port2.poe = true;
					}
				}
                                port2.uniqueId = interface.substr(0,8).trim();
				stat = interface.substr(29,12).trim();
                                port2.status = this.getStatus(stat);
                                port2.speed = (stat == "connected" ? this.getSpeed(interface.substr(60,7).trim()) : 0);
                                port2.duplex = interface.substr(52,8).trim();
                                port2.portNo = ++portNumber;

                                switchObject.ports[index1][index2] = [];
                                switchObject.ports[index1][index2][0] = port1;
                                switchObject.ports[index1][index2][1] = port2;
                        }
                }
		while (portNumber < noOfPorts){
                    var uplinkObject = {};
		    var interface = intData[portNumber];
		    if(interface == undefined){
			++portNumber;
			continue;
		    }
		    // interface will be of the format
		    // "Gi1/0/48                     notconnect   148          auto   auto 10/100/1000BaseTX" 
		    // Extract various fields

                    uplinkObject.uniqueId = interface.substr(0,8).trim();
		    var stat = interface.substr(29,12).trim();
                    uplinkObject.status = this.getStatus(stat);
                    uplinkObject.speed = (stat == "connected" ? this.getSpeed(interface.substr(60,7).trim()) : 0);
                    uplinkObject.duplex = interface.substr(52,8).trim();
                    uplinkObject.portNo = uplinkObject.uniqueId.split("/")[2];
                    ++portNumber;
		    if(uplinkObject.uniqueId == "Fa0"){
			continue;
		    }
		    switchObject.uplinkports.push(uplinkObject);
                }
                return switchObject;
        };
	this.getStatus = function(statusStr){
		var status = 1;
                if(statusStr === "disabled"){
                         status = 2;
                } else if(statusStr === "notconnect"){
                         status= 0;
                } else if(statusStr === "err-disabled"){
                         status= 3;
                }
		return status;
	};
	this.getSpeed = function(speedStr){
		var speed = 0;
		if(speedStr.indexOf('10000') >= 0 || speedStr == "10G"){
                        speed = 10000;
                } else if (speedStr.indexOf('1000') >= 0){
                        speed = 1000;
                } else if (speedStr.indexOf('100') >= 0){
                        speed = 100;
                } else {
        		speed = 10;
        	}
		return speed;
	};
}]);
