declare function saveAs(param1: any, param2: any): void;

(function () {
    /*global saveAs, TICloudAgent*/
    'use strict';

    angular.module('uniflash').directive('ufDownloadPackage', downloadPackage);

    function downloadPackage() {

        let directive = {
            restrict: 'E',
            controller: StandaloneDownload,
            controllerAs: 'vm',
            templateUrl: 'standalone_dl/download_package.template.html',
            scope: {}
        };
        return directive;
    }

    StandaloneDownload.$inject = ['$q', '$scope', '$state', '$log',
        'ufFilePackageCreator', 'ufPropertiesValue', 'ufTargetConfig', 'ufPrograms', 'ufMainView', 'ticAlerts', 'ufSession', 'ufProgess', 'ticExecutionPlatform', 'ticAnalyticsSrv'];

    function StandaloneDownload($q, $scope, $state, $log,
        ufFilePackageCreator, ufPropertiesValue, ufTargetConfig, ufPrograms, ufMainView, ticAlerts, ufSession, ufProgess, ticExecutionPlatform, ticAnalyticsSrv) {
        let vm = this;
        vm.isRunningCloud = ticExecutionPlatform.getPlatform() === ti_common.PlatformType.CLOUD;
        vm.ufProgramList = ufPrograms.getPrograms();
        vm.selectedPrograms = 0;

        vm.cliScriptName = [];
        vm.cliScriptName['Windows'] = 'dslite.bat';
        vm.cliScriptName['Linux'] = 'dslite.sh';
        vm.cliScriptName['OSX'] = 'dslite.sh';

        if (!vm.ufProgramList) {
            vm.ufProgramList = [];
        }
        _.each(vm.ufProgramList, (image) => {
            if (image.isSelected) {
                vm.selectedPrograms++;
            }
        });

        vm.includeSettings = true;
        vm.includeImages = (vm.selectedPrograms > 0);
        vm.includeDrivers = false;
        vm.includeSessions = false;

        ufTargetConfig.getDevice($state.params.deviceXMLFile)
            .then((device) => {
                vm.deviceName = device.id;
                return ufTargetConfig.getConnection(device.connectionIndices, $state.params.connectionXMLFile);
            })
            .then((connection) => {
                vm.connectionName = connection.id;
            });

        let osDesc = {
            'Windows': 'win',
            'OSX': 'osx',
            'Linux': 'linux'
        };

        vm.osTypes = ['Windows', 'OSX', 'Linux'];

        switch (ufFilePackageCreator.getOSType()) {
            case 'win':
                vm.choosenOsType = vm.osTypes[0];
                break;
            case 'osx':
                vm.choosenOsType = vm.osTypes[1];
                break;
            case 'linux':
                vm.choosenOsType = vm.osTypes[2];
                break;
        }

        vm.packageName = 'uniflash_' + vm.choosenOsType.toLowerCase();
        vm.updatePackageName = function () {
            if (vm.packageName.substring(0, 9) === 'uniflash_') {
                vm.packageName = 'uniflash_' + vm.choosenOsType.toLowerCase();
            }
        };

        function isSafari() {
            return 'safari' === TICloudAgent.getBrowser();
        }

        function b64toBlob(b64Data, contentType, sliceSize?) {
            contentType = contentType || '';
            sliceSize = sliceSize || 512;

            let byteCharacters = atob(b64Data);
            let byteArrays = [];

            for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
                let slice = byteCharacters.slice(offset, offset + sliceSize);

                let byteNumbers = new Array(slice.length);
                for (let i = 0; i < slice.length; i++) {
                    byteNumbers[i] = slice.charCodeAt(i);
                }

                let byteArray = new Uint8Array(byteNumbers);

                byteArrays.push(byteArray);
            }

            let blob = new Blob(byteArrays, { type: contentType });
            return blob;
        }

        function generateDownloadLink(name, abContent) {
            if (isSafari()) {
                let base64data = arrayBufferToBase64(abContent);
                window.location.href = 'data:application/zip;base64,' + base64data;
            } else {
                let byteArray = new Uint8Array(abContent);
                let textFileAsBlob = new Blob([byteArray], { type: 'application/zip' });
                saveAs(textFileAsBlob, name);
            }
        }

        function arrayBufferToBase64(buffer) {
            let binary = '';
            let bytes = new Uint8Array(buffer);
            let len = bytes.byteLength;
            for (let i = 0; i < len; i++) {
                binary += String.fromCharCode(bytes[i]);
            }
            return window.btoa(binary);
        }

        vm.download = () => {
            let choosenOptions = {
                'includeImages': vm.includeImages,
                'includeSettings': vm.includeSettings,
                'os': vm.choosenOsType
            };
            ticAnalyticsSrv.record('DownloadPackage', choosenOptions);
            $log.debug('DownloadPackage: ' + JSON.stringify(choosenOptions));

            let progressDialog, zipFileContents;
            ufFilePackageCreator.setOSType(osDesc[vm.choosenOsType]);
            ufFilePackageCreator.setPackageOptions(vm.includeImages, vm.includeSettings, vm.includeDrivers, vm.includeSessions);
            ufFilePackageCreator.setDevice(vm.deviceName);

            ufFilePackageCreator.getFilePackage()
                .then((contents) => {
                    zipFileContents = contents;
                    $log.debug('Fetching package files successful.');
                    return ufFilePackageCreator.getProgess();
                })
                .then((newProgressDialog) => {
                    progressDialog = newProgressDialog;
                    let platform = (vm.choosenOsType === 'Windows') ? 'DOS' : 'UNIX';
                    let type = 'arraybuffer';


                    let deferred = $q.defer();

                    let totalFiles = zipFileContents.length;

                    let myWorker = new Worker('standalone_dl/jszip.worker.js');
                    myWorker.addEventListener('message', (msg) => {

                        if (msg.data.isDone) {
                            progressDialog.handleEvent({
                                name: 'Zip Package created.',
                                subActivity: 'You may need to check for a file dialog if to save the zip file.',
                                isCancellable: false,
                            }, null);
                            deferred.resolve(msg.data.output);
                        } else {
                            let p = msg.data.percent / 2 + 50;
                            let progressMsg = 'Creating Zip Package: ' + msg.data.currentFile;
                            if (p === 100 && msg.data.currentFile === null) {
                                progressMsg = 'Done';
                            }
                            progressDialog.handleEvent({

                                name: 'Creating Zip Package...',
                                percent: p,

                                subActivity: progressMsg,
                                isCancellable: false,
                            }, null);
                        }
                    });

                    myWorker.postMessage(
                        {
                            action: 'start'
                        }
                    );


                    angular.forEach(zipFileContents, (file) => {
                        if (typeof file.contents === 'string') {
                            myWorker.postMessage(
                                {
                                    action: 'addFile',
                                    filename: file.fileName,
                                    contents: file.contents,
                                    options: JSON.stringify(file.options)
                                }
                            );
                        } else { //arraybuffer
                            myWorker.postMessage(
                                {
                                    action: 'addFile',
                                    filename: file.fileName,
                                    contents: file.contents,
                                    options: JSON.stringify(file.options)
                                },
                                [
                                    file.contents
                                ]
                            );
                        }
                    });
                    //  console.log('generate zip...');
                    myWorker.postMessage(
                        {
                            action: 'generate',
                            type: type,
                            platform: platform
                        }
                    );

                    return deferred.promise;
                })
                .then((content) => {
                    if (!vm.packageName) {
                        vm.packageName = 'uniflash-' + vm.choosenOsType;
                    }

                    generateDownloadLink(vm.packageName + '.zip', content);
                })
                .catch((error) => {
                    return displayError(error);
                })
                .finally(() => {
                    progressDialog.close();
                });
        };

        function displayError(e) {
            if (typeof e === 'string') {
                return ticAlerts.showError(e);
            } else if (e && e.message && typeof e.message === 'string') {
                return ticAlerts.showError(e.message);
            } else {
                $log.error(JSON.stringify(e));
            }
        }

        //download value-xml string for the current core as a file
        vm.dlCurrentSettings = function () {
            let filename = 'settings.ufsettings';
            let blob = new Blob([ufPropertiesValue.saveValuesAsJson(true)], {
                type: 'application/json;charset=utf-8'
            });
            saveAs(blob, filename);
            $log.info('Fetching settings for ' + filename);
        };

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

        vm.goToPrograms = function () {
            ufMainView.go(uniflash.RegisteredViews.Program
                , $state.params.coreName);
        };
    }
} ());

