'use strict';

app.directive('deviceBtnEdit', function () {
	return {
		restrict: 'EA',
		replace: true,
		scope: {
			selectedBtn: '=',
			deviceData: '=',
			roomId: '='
		},
		template: function(tElement, tAttrs) {
			var template;
			switch (tAttrs.content) {
				case 'add':
					template = '<button class="btn btn-menu" ng-click="showModal()">Add a button</button>';
					break;
				case 'add-from-navi':
					template = '<button class="btn btn-menu" ng-click="showModal()">Add from navigator</button>';
					break;
				case 'add-from-device':
					template = '<button class="btn btn-menu" ng-click="showModal()">Add from a device</button>';
					break;
				case 'edit':
				default:
					template = '<a title="Edit this button" ng-click="showModal()" ><i class="fa fa-fw fa-lg fa-pencil action-icon"></i></a>';
					break;
			}
			return template;
		},
		controller: function($scope, $element, $modal, $attrs, $q, toastr, Database, Systems, Devices) {
			///ip command DB로 setting된 Device라면.. ip command 편집을 위한 준비를 한다.
			$scope.ipCmd = {dispType:'none', dispType_prev:'none', dispString:''};

			var editModal = null;

			if('add-from-navi' == $attrs.content)
			{
				editModal = $modal({ scope: $scope, title: 'Function Navigator', placement: 'top', template:'views/modal-tpls/function-navi.html', show:false});

				$scope.device = {};
				$scope.type = {};

				 var getCategories = function() {
					var d = $q.defer();
					Database.retreiveDeviceTypes().then(
						function(data) {
							d.resolve(data);
						},
						function(error) {
							toastr.error(error, 'Error');
							d.reject(error);
						}
					);
					return d.promise;
				};

				if(null == $scope.types) {
					getCategories().then(	function(data) {
						//console.log('categories=', data);
						$scope.types = data;
						if (!$scope.device.type) {
							$scope.device.type = {id: $scope.types[0].id, name: $scope.types[0].name, device: $scope.types[0].device};  // 기본값 설정
							$scope.device.brand = null;
							$scope.device.model = null;
							$scope.device.func = null;
							$scope.brands = null;
							$scope.models = null;
							$scope.deviceinfo = null;
							$scope.popular_models = null;

							getDeviceBrands();
						}
					}).catch(toastr.error);
				}

				var getDeviceBrands = function() {
					Database.retrieveDeviceBrands($scope.device.type.name).then(function(data) {
						//console.log('brands=', data);
						$scope.brands = Database.getBrands();
					}).catch(toastr.error);
				};

				var getDevicePopularModels = function() {
					
					Database.searchPopularModels($scope.device.type.name, $scope.device.brand.name).then(function(data) {
						console.log('models=', data);
						$scope.popular_models = Database.getDevices();

					}).catch(toastr.error);
				};

				var getDeviceInfo = function() {
					Database.getDeviceInfo($scope.device.type.name, $scope.device.brand.name, $scope.device.model.id, $scope.deviceData.type, $scope.device.model.type).then(function(data) {
						//console.log('deviceinfo=', data);
						$scope.deviceInfo = data;
					}).catch(toastr.error);
				};


				$scope.selectCategory = function(category) {
					$scope.device.type = category;
					$scope.device.brand = null;
					$scope.device.model = null;
					$scope.device.func = null;
					$scope.brands = null;
					$scope.models = null;
					$scope.deviceinfo = null;
					getDeviceBrands();
				}

				$scope.selectBrand = function(brand) {
					$scope.device.brand = brand;
					//getDevicePopularModels();
				}

				$scope.selectModel = function(model) {
					$scope.device.model = model;
					getDeviceInfo();
				}				

				$scope.selectFunction = function(func) {
					$scope.device.func = func;
					//console.log('func=', func);
				}
			
			}
			else if('add-from-device' == $attrs.content)
			{
				editModal = $modal({ scope: $scope, title: 'Device Navigator', placement: 'top', template:'views/modal-tpls/device-navi.html', show:false});

				$scope.alias = {};
				$scope.buttons = [];

				if(!$scope.devices) {
					// room 정보 얻어와서 저장
					Systems.updateRoomDevices($scope.roomId).then(function(data) {
						var roomDevices = Systems.getRoomDevices();
						$scope.devices = roomDevices.devices;

						///dev_type이 twoway(1)인 device를 모두 제거.
						var item = null;
						while(item = _.where($scope.devices, {'dev_type': 1})[0]) {
							var idx = $scope.devices.indexOf(item);
							$scope.devices.splice(idx, 1);
						} 
						console.log('$scope.devices=', $scope.devices);

						console.log('$scope.alias.device=', $scope.alias.device);

						if (!$scope.alias.device) {
							$scope.alias.device = $scope.devices[0];  // 기본값 설정
						}

						$scope.alias.func = $scope.alias.device.funcs[0];
					})
					.catch(toastr.error);
				}


				$scope.selectDevice = function(device) {
					$scope.alias.device = device;
					$scope.alias.func = $scope.alias.device.funcs[0];
				}

				$scope.selectFunction = function(func) {
					$scope.alias.func = func;
					console.log('$scope.alias.func=', $scope.alias.func);
				}

			}
			else	{
				editModal = $modal({ scope: $scope, title: 'Edit this button', placement: 'top', template:'views/modal-tpls/device-edit-btn.html', show:false});
			}

			//Useful Functions
			function checkBin(n){return/^[01]{1,64}$/.test(n)}
			function checkDec(n){return/^[0-9]{1,64}$/.test(n)}
			function checkHex(n){return/^[0-9A-Fa-f]{1,64}$/.test(n)}
			function pad(s,z){s=""+s;return s.length<z?pad("0"+s,z):s}
			function unpad(s){s=""+s;return s.replace(/^0+/,'')}

			//Decimal operations
			function Dec2Bin(n){if(!checkDec(n)||n<0)return 0;return n.toString(2)}
			function Dec2Hex(n){if(!checkDec(n)||n<0)return 0;return n.toString(16)}

			//Binary Operations
			function Bin2Dec(n){if(!checkBin(n))return 0;return parseInt(n,2).toString(10)}
			function Bin2Hex(n){if(!checkBin(n))return 0;return parseInt(n,2).toString(16)}

			//Hexadecimal Operations
			function Hex2Bin(n){if(!checkHex(n))return 0;return parseInt(n,16).toString(2)}
			function Hex2Dec(n){if(!checkHex(n))return 0;return parseInt(n,16).toString(10)}		

			function transferFromAscii(strData)
			{
				var strLen = strData.length;
				var byteData = [];				
				var byteValue;
				var strHex;
				for(var i = 0; i < strLen; i++)
				{
					if(strData.charAt(i) == '\\')
					{
						if(strData.charAt(i+1) ==  'x' && i+3 < strLen)
						{
							strHex = strData.substr(i+2, 2);
							if(checkHex(strHex))
							{
								byteValue = parseInt(strHex, 16);
								//console.log('byteValue=', byteValue);
								byteData.push(byteValue);
							}
							else{
								//console.log('error data=', strHex);
							}

							i+=3;
						}
						else if(strData.charAt(i+1)  == '\\')
						{
							byteValue = '\\';
							//console.log('byteValue=', byteValue);
							byteData.push(byteValue);

							i++;
						}
					}
					else
					{
						byteValue = strData.charCodeAt(i);
						//console.log('byteValue=', byteValue);
						byteData.push(byteValue);
					}					
				}

				//console.log('byteData=', byteData);

				return byteData;
			}

			function transferFromLowHex(strData)
			{
				var byteData = [];				
				var byteValue;
				var strHex;
				//console.log('strData=', strData);
				for(var i = 0; i < strData.length; i+=2)
				{
					strHex = strData.substr(i, 2);

					if(checkHex(strHex))
					{
						byteValue = parseInt(strHex, 16);
						//console.log('byteValue=', byteValue);
						byteData.push(byteValue);
					}
					else{
						//console.log('error data=', strHex);
					}
				}

				//console.log('byteData=', byteData);

				return byteData;
			}

			function transferFromHex(strData)
			{
				var byteData = [];				
				var byteValue;
				var strHex;
				var arrHex = strData.split(',');
				for(var i = 0; i < arrHex.length; i++)
				{
					strHex = arrHex[i];
					strHex = strHex.trim();

					if(checkHex(strHex))
					{
						byteValue = parseInt(strHex, 16);
						//console.log('byteValue=', byteValue);
						byteData.push(byteValue);
					}
					else{
						//console.log('error data=', strHex);
					}
				}

				//console.log('byteData=', byteData);

				return byteData;
			}

			function transferFromDec(strData)
			{
				var byteData = [];				
				var byteValue;
				var strDec;
				var arrDec = strData.split(',');
				for(var i = 0; i < arrDec.length; i++)
				{
					strDec = arrDec[i];

					strDec = strDec.trim();
					if(checkHex(strDec))
					{
						byteValue = parseInt(strDec, 10);
						//console.log('byteValue=', byteValue);
						byteData.push(byteValue);
					}
					else{
						//console.log('error data=', strDec);
					}
				}

				//console.log('byteData=', byteData);

				return byteData;
			}

			function transferToAscii(byteData)
			{
				var dispString = '';
				var charValue;
				var byteValue;
				for(var i=0; i< byteData.length; i++)
				{
					byteValue = byteData[i];
					if( 0 != (charValue = String.fromCharCode(byteValue)) ) 
					{
						//console.log('charValue=', charValue);
						dispString += charValue;
					}
					else
					{
						//console.log('charValue=', charValue);
						dispString += '\\x' + pad(byteValue.toString(16), 2);
					}
				}

				//console.log('dispString=', dispString);

				return dispString;
			}

			function transferToHex(byteData)
			{
				var dispString = '';
				var strHex;
				var byteValue;
				for(var i=0; i< byteData.length; i++)
				{
					byteValue = byteData[i];
					strHex = byteValue.toString(16)

					//console.log('strHex=', strHex);
					dispString += strHex;
					if(i < byteData.length-1)
						dispString += ', ';
				}

				//console.log('dispString=', dispString);

				return dispString;
			}

			function transferToDec(byteData)
			{
				var dispString = '';
				var strDec;
				var byteValue;
				for(var i=0; i< byteData.length; i++)
				{
					byteValue = byteData[i];
					strDec = byteValue.toString(10)

					//console.log('strDec=', strDec);
					dispString += strDec ;
					if(i < byteData.length-1)
						dispString += ', ';
				}

				//console.log('dispString=', dispString);

				return dispString;
			}


			function transferToData(strData, type) {
				switch(type) {
					case 'ascii' :
						return transferFromAscii(strData);
						break;

					case 'hex' :
						return transferFromHex(strData);
						break;

					case 'dec' :
						return transferFromDec(strData);
						break;
				}
			}

			function toHexString(bytes) {
				return bytes.map(function(byte) {
					return pad((byte & 0xFF).toString(16), 2);
				}).join('');
			}			


			$scope.switchDispType = function(type) {
				var byteData ;
				$scope.ipCmd.dispType = type;
				//console.log('dispType_prev=', $scope.ipCmd.dispType_prev, 'dispType=', $scope.ipCmd.dispType);

				if($scope.ipCmd.dispString.length)
					byteData = angular.copy(transferToData($scope.ipCmd.dispString, $scope.ipCmd.dispType_prev));
				else
					byteData = angular.copy(transferFromLowHex($scope.newBtn.func.data));

				switch($scope.ipCmd.dispType) {
					case 'ascii' :
						$scope.ipCmd.dispString = transferToAscii(byteData);
						break;

					case 'hex' :
						$scope.ipCmd.dispString = transferToHex(byteData);
						break;

					case 'dec' :
						$scope.ipCmd.dispString = transferToDec(byteData);
						break;
				}

				$scope.ipCmd.dispType_prev = $scope.ipCmd.dispType;
			};

			$scope.changeFunction = function(func) {
				//console.log('changeFunction - func=', func);
				$scope.newBtn.func = func;

				if($scope.newBtn.func)
				{
					$scope.ipCmd.dispString = '';
					$scope.ipCmd.dispType = 'dec';
					$scope.ipCmd.dispType_prev = $scope.ipCmd.dispType;
					$scope.switchDispType($scope.ipCmd.dispType);
				}
			}



			function findAvailableId() {
				function filterLcdFuncs(id) {
					return id > 2048;
				}
				var db = $scope.deviceData.dbCon;
				var ids = _.pluck(db, 'id').filter(filterLcdFuncs); //ids is an empty array if no id is greater than 2048
				
				if (_.isEmpty(ids)) {
					return 2049;
				}

				ids = _.unique(ids).sort(function(a, b) {
					return a - b;
				});

				var min = _.min(ids) ;
				var counter = min;

				for (var i = 0; i < ids.length; i++) {
					if (ids[i] === counter) {
						counter++;
					} else {
						return counter;
					}
				}
				return counter;
			}

			function saveFromFunction() {
				_.assign($scope.newBtn, {display_text: $scope.device.func.caption});
				//console.log('$scope.newBtn=', $scope.newBtn);
				//console.log('$scope.device.func=', $scope.device.func);

				var func = { 
					id: $scope.newBtn.id < 8192 ? $scope.newBtn.id : findAvailableId(),
					name: $scope.device.func.caption, 
					data: $scope.device.func.cmd,
					type: 0,
					custom: 0,
					press_hold: 1,
					repeat_macro: $scope.deviceData.repeat.macro,
					repeat_min: $scope.deviceData.repeat.min,
					room_id: $scope.newBtn.room_id,
					device_id: $scope.newBtn.device_id
				};

				var device_id = parseInt($scope.deviceData.id, 10);
				var macro = [{type: 1, device_id: device_id}];

				var btn = {
					image_name: '',
					press_hold: func.press_hold ? true:false,
					device_id: func.device_id,
					room_id: func.room_id,
					hidden_option: 0,
					activity: '',
					popup: 0,
					func: func,
					macro: macro
				};

				_.assign($scope.newBtn, btn);

				$scope.deviceData.dbCon.push(func);
				//console.log('btn=', btn);
				//console.log('$scope.newBtn=', $scope.newBtn);
				//console.log('$scope.deviceData=', $scope.deviceData);
			}   

			function saveFromDevice() {
				var macro = [{ 
					type: 6,
					device_id: $scope.alias.device.id,
				}];

				_.assign($scope.newBtn, {display_text: $scope.alias.func.name});
				_.assign($scope.newBtn, {func: $scope.alias.func});
				_.assign($scope.newBtn, {macro: macro});

				//console.log('btn=', btn);
				//console.log('$scope.newBtn=', $scope.newBtn);
			}   


			function showModal() {
				$scope.newBtn = angular.copy($scope.selectedBtn);
				//console.log('showModal - $scope.newBtn=', $scope.newBtn);
				if($scope.newBtn.func)
				{
					$scope.ipCmd.dispString = '';
					$scope.ipCmd.dispType = 'dec';
					$scope.ipCmd.dispType_prev = $scope.ipCmd.dispType;
					$scope.switchDispType($scope.ipCmd.dispType);
				}
				else if('add-from-navi' == $attrs.content)
				{
					$scope.device.brand = null;
					$scope.device.model = null;
					$scope.device.func = null;
					$scope.models = null;
					$scope.deviceinfo = null;
				}

				editModal.$promise.then(editModal.show);
			}
			function hideModal() {
				editModal.$promise.then(editModal.hide);
			}

			$scope.showModal = showModal;

			$scope.edit = function(oldValue, newValue) {
				//console 에 oldValue와 newValue가 동일한 값이 출력됨. 아래의 _.assign(oldValue, newValue);의 영향인 것 같음.
				//console.log('edit - oldValue=',oldValue);
				//console.log('edit - newValue=',newValue);


				
				if('add-from-navi' == $attrs.content)				///function navigator를 통한 add button
				{
					 saveFromFunction();
				}
				else if('add-from-device' == $attrs.content)				///device navigator를 통한 add button
				{
					 saveFromDevice();
				}
				else if ($scope.deviceData.type == 2 && newValue.macro[0].type == 1)				///device data type이 ip type인 경우
				{
					var byteData =  angular.copy(transferToData($scope.ipCmd.dispString, $scope.ipCmd.dispType));
					//console.log('edit - newValue.func.data=', newValue.func.data);
					newValue.func.data = toHexString(byteData);
					//console.log('edit - newValue.func.data=', newValue.func.data);

					var dbCommand = _.find($scope.deviceData.dbCon, {id: newValue.func.id });

					if (dbCommand) {
						//console.log('edit-dbCommand=', dbCommand);
						_.assign(dbCommand, { data: newValue.func.data });
					}
				}
				
				if(newValue.func) {
					if (!newValue.hasOwnProperty('press_hold')) {
						newValue.press_hold = newValue.func.press_hold ? true:false;
					}

					if (!newValue.hasOwnProperty('image_name')) {
						newValue.image_name = '';
					}

					if (!newValue.hasOwnProperty('device_id')) {
						newValue.device_id = newValue.func.device_id;
					}

					if (!newValue.hasOwnProperty('room_id')) {
						newValue.room_id = newValue.func.room_id;
					}

					if (!newValue.hasOwnProperty('hidden_option')) {
						newValue.hidden_option = 0;
						newValue.activity = '';
						newValue.popup = 0;
					}
				}
				
				_.assign(oldValue, newValue);

				hideModal();
			};
			
		}
	};
});