(function () {

	'use strict';

	angular.module('uniflash').directive('ufProgramsList', programsList);

	function programsList() {

		let directive = {
			templateUrl: 'programs/programs_list.html',
			restrict: 'E',
			controller: ProgramsListController,
			controllerAs: 'vm',
			scope: {}
		};

		return directive;
	}

	let headings = [
		{
			name: 'File Name',
			sortProperty: 'fd.name',
			colSize: 4
		},
		{
			name: 'Size',
			sortProperty: 'fd.size',
			colSize: 1
		},
		{
			name: 'Binary',
			colSize: 1
		},
		{
			name: 'Load Address',
			colSize: 2
		},
		{
			name: 'Actions',
			colSize: 3
		},
		{
			name: '',
			colSize: 1
		}
	];

	ProgramsListController.$inject = ['ufPrograms', 'ufResets', 'ufProgramProviders', 'ufDsProgressDialog', 'ufContext', 'ufMainView', 'ticAnalyticsSrv', 'ufSession', 'ufConsole', 'ufDS'];
	function ProgramsListController(ufPrograms, ufResets, ufProgramProviders, ufDsProgressDialog, ufContext, ufMainView: uniflash.views.MainViewService, ticAnalyticsSrv, ufSession, ufConsole, ufDS) {

		let vm = this;
		let coreName = ufContext.getCurrentCore().name;
		vm.ufDS = ufDS;
		vm.resets = ufResets.getReset();
		vm.headings = headings;
		vm.programs = ufPrograms.getPrograms();
		vm.programProviders = ufProgramProviders;
		vm.connectionProperties = ufSession.queryConfig().connectionProperties;
		vm.deviceProperties = ufSession.queryConfig().deviceProperties;
		vm.numDefaultImageSelection = 1;
		vm.imageSelectionNames = [];

		// do not show reset actions for serial connection (update rules as necessary)
		vm.showResetActions = (ufContext.$stateParams.connectionXMLFile !== "Serial_Connection"); 

		vm.queryResets = () => {
			let dsCore = ufDsProgressDialog.getDSCore(coreName);
			return dsCore.run('getResets')
				.then((ret) => {
                    vm.resets.availableResetOptions = ret;
                    if ( vm.resets.availableResetOptions.length > 0 ) {
                        vm.resets.selectedResetOption = vm.resets.availableResetOptions[0];
                    }
				});
		};
		vm.performReset = () => {
            ufConsole.addMessage('INFO', 'Executing Reset: ' + vm.resets.selectedResetOption);
			let dsCore = ufDsProgressDialog.getDSCore(coreName);
			return dsCore.run('performReset', vm.resets.selectedResetOption);
		};

		vm.fillDefaultImageSelection = function () {
			if (vm.connectionProperties.ufSupportMultipleImageSelect && vm.connectionProperties.ufSupportMultipleImageSelect.Value === 'true') {
				if (vm.deviceProperties.ufNumImageSelection) {
					vm.numDefaultImageSelection = parseInt(vm.deviceProperties.ufNumImageSelection.Value);

					for (let i = 0; i < vm.numDefaultImageSelection; i++) {
						vm.imageSelectionNames[i] = vm.deviceProperties['ufImageType' + i.toString()].Value;
					}
				}
			}
		};
		this.fillDefaultImageSelection();

		// program list ordering
		vm.reverse = false;
		vm.predicate = "";
		vm.order = function (predicate) {
			vm.predicate = predicate;
		};

		vm.goToUtilitiesAndSettings = function () {
			ufMainView.go(uniflash.RegisteredViews.UtilitiesAndSettings, coreName);
		};

		vm.hasBinary = function () {
			let rtnVal = false;
			_.each(vm.programs, function (program) {
				if (program.isBinary) {
					rtnVal = true;
					return;
				}
			});
			return rtnVal;
		};

		vm.performDSAction = function (action, param) {
			let dsCore = ufDsProgressDialog.getDSCore(coreName);

			ticAnalyticsSrv.record("PerformSingle", {
				"action": action,
				"isBinary": param[0].isBinary
			});

			return dsCore.run(action, param);
		};

		vm.selectClicked = function (programProvider: uniflash.programs.ProgramProvider, order: number) {
			programProvider.selectProgramFile(vm.getFileExtensions(order)).then(function (selections) {
				_.each(selections, function (selection) {
					if (order !== undefined) {
						// remove the entry first before adding
						let program = vm.findImageByIndex(order);
						if (program.file) {
							vm.removeClicked(vm.findImageByIndex(order));
						}
					}
					ufPrograms.addProgram(selection, programProvider, order);
				});
			}).catch(programFileSelectError);
		};

		vm.browseClicked = function (program: uniflash.programs.Program) {
			program.provider.selectProgramFile(vm.getFileExtensions(0)).then((selections: ti_common.file.File[]) => {
				// just change the file descriptor
				// if multiple selections just use the first one
				program.file = selections[0];
			}).catch(programFileSelectError);

		};

		vm.getFileExtensions = function(index:number) : string {
			if ( index > 1 ) {
				// look up file filter for when we have multiple files defined
				var fileExtensionObj = vm.deviceProperties["supportedFileExtensions"+(index-1).toString()];
				if ( fileExtensionObj ) {
					return fileExtensionObj.Value;
				}
			}
				
			return vm.deviceProperties.supportedFileExtensions ?
				vm.deviceProperties.supportedFileExtensions.Value : '.out,.bin,.hex,.txt';
		}

		vm.removeClicked = function (program: uniflash.programs.Program) {
			ufPrograms.removeProgram(program);
		};

		vm.removeAll = function () {
			while (vm.programs.length > 0) {
				ufPrograms.removeProgram(vm.programs[0]);
			}
		}

		vm.loadSelectedClicked = performAllSelected.bind(this, 'program');
		vm.verifySelectedClicked = performAllSelected.bind(this, 'verify');

		// Three state sorting
		// 1) no predicate -> un sorted
		// 2) predicate , sort asending
		// 3) predicate , sort descending
		// 1 -> 2 
		// 2 -> 3 | 2 ( where the predicate changes)
		// 3 -> 1 | 3 ( where the predicate changes)
		//
		// Thus if we keep clicking on the same column it goes 
		//  sort ascending, sort descending, unsorted
		//
		vm.order = function (predicate) {
			if (vm.predicate === predicate) {
				if (vm.reverse) {
					// no sort
					vm.predicate = undefined;
					vm.reverse = undefined;
				} else {
					vm.reverse = true;
				}
			} else {
				vm.predicate = predicate;
				vm.reverse = false;
			}
		};

		vm.selectedActionsDisabled = function () {
			return vm.numProgramsSelected() < 2 || vm.allSelectedActionInProgress;
		};

		vm.numProgramsSelected = function () {
			return _.reduce(vm.programs, function (totalSelected, program: any) {
				return program.isSelected ? ++totalSelected : totalSelected;
			}, 0);
		};

		function performAllSelected(action) {
			vm.allSelectedActionInProgress = true;
			let curPrograms = vm.sortedPrograms;
			if (!curPrograms) { curPrograms = vm.programs; }

			let programsToLoad = _.filter(curPrograms, { isSelected: true });


			ticAnalyticsSrv.record("PerformAll", {
				"action": action,
				"numPrograms": programsToLoad.length,
				"hasBinary": vm.hasBinary()
			});

			let dsCore = ufDsProgressDialog.getDSCore(coreName);
			return dsCore.run(action, programsToLoad)
				.finally(function () {
					vm.allSelectedActionInProgress = false;
				});
		}

		vm.programRowClass = function (program: uniflash.programs.Program) {
			return {
				disabled: !program.file.isReady,
				highlight_hover_light2: vm.programs.length > 1
			};
		};

		vm.checkHex = function (program) {
			program.loadAddress = program.loadAddress.replace(/[^A-Fa-f0-9xX]/g, '');
		};

		vm.findImageByIndex = function (index) {
			let program = _.find(vm.programs, function (program: any) {
				return (program.loadAddress === index.toString());
			});
			if (program) {
				return program;
			} else {
				return { isSelected: false };
			}
		};

		vm.verifySupported = function () {
			if (vm.connectionProperties.ufSupportVerify && vm.connectionProperties.ufSupportVerify.Value === 'false') {
				return false;
			}
			return true;
		};
	}

	function programFileSelectError(e) {
		console.log(e);
	}
}());