/*-
 * #%L
 * thinkbig-ui-feed-manager
 * %%
 * Copyright (C) 2017 ThinkBig Analytics
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
(function () {

    var directive = function () {
        return {
            restrict: "EA",
            bindToController: {
                stepIndex: '@'
            },
            scope: {},
            controllerAs: 'vm',
            templateUrl: 'js/register-template/register-template/register-template-step.html',
            controller: "RegisterCompleteRegistrationController",
            link: function ($scope, element, attrs, controller) {
            }
        };
    };

    function RegisterCompleteRegistrationController($scope, $http, $mdToast, $rootScope, $mdPanel, $mdDialog, RestUrlService, StateService, RegisterTemplateService) {

        /**
         * ref back to this controller
         * @type {RegisterCompleteRegistrationController}
         */
        var self = this;

        /**
         * Order of the templates via the dndLists
         * @type {Array}
         */
        this.templateOrder = [];

        /**
         * the angular form
         */
        self.registerTemplateForm = {};

        /**
         * Indicates if the edit form is valid.
         * @type {boolean}
         */
        self.isValid = false;

        /**
         * The Source/Destination Datasources assigned to this template
         * @type {Array}
         */
        self.processorDatasourceDefinitions = [];

        /**
         * flag to tell when the system is loading datasources
         * @type {boolean}
         */
        self.loadingFlowData = true;

        /**
         * The Template Model
         */
        this.model = RegisterTemplateService.model;

        this.message = null;

        /**
         * Flag indicating if the template succeeded registration
         * @type {boolean}
         */
        this.registrationSuccess = false;
        /**
         * The Step number
         * @type {number}
         */
        this.stepNumber = parseInt(this.stepIndex) + 1

        /**
         * The possible options to choose how this template should be displayed in the Feed Stepper
         * @type {[*]}
         */
        this.templateTableOptions =
            [{type: 'NO_TABLE', displayName: 'No table customization', description: 'User will not be given option to customize destination table'},
                {type: 'DEFINE_TABLE', displayName: 'Customize destination table', description: 'Allow users to define and customize the destination data table.'}, {
                type: 'DATA_TRANSFORMATION',
                displayName: 'Data Transformation',
                description: 'Users pick and choose different data tables and columns and apply functions to transform the data to their desired destination table'
            }]

        /**
         * the selected option for the template
         * @type {*}
         */
        this.templateTableOption = this.model.templateTableOption;

        /**
         * A map of the port names to the port Object
         * used for the connections from the outputs to input ports
         * @type {{}}
         */
        self.connectionMap = {};

        /**
         * The available options in the list of possible inputPorts to connect to
         * @type {Array} of {label: port.name, value: port.name}
         */
        self.inputPortList = [];

        // setup the Stepper types
        var initTemplateTableOptions = function () {
            if (self.templateTableOption == undefined) {

                if (self.model.defineTable) {
                    self.templateTableOption = 'DEFINE_TABLE'
                }
                else if (self.model.dataTransformation) {
                    self.templateTableOption = 'DATA_TRANSFORMATION'
                }
                else if (self.model.reusableTemplate) {
                    self.templateTableOption = 'COMMON_REUSABLE_TEMPLATE'
                }
                else {
                    self.templateTableOption = 'NO_TABLE'
                }
            }
        }

        /**
         * Calls the server to get all the Datasources and the Flow processors and flow types
         * Caled initially when the page loads and then any time a user changes a input port connection
         */
        function buildTemplateFlowData() {
            self.loadingFlowData = true;
            var assignedPortIds = [];

            _.each(self.model.reusableTemplateConnections, function (conn) {
                var inputPort = conn.inputPortDisplayName;
                var port = self.connectionMap[inputPort];
                if (port != undefined) {
                    assignedPortIds.push(port.id);
                }
            });
            var selectedPortIds = '';
            if (assignedPortIds.length > 0) {
                selectedPortIds = assignedPortIds.join(",");
            }
            //only attempt to query if we have connections set
            var hasPortConnections = (self.model.reusableTemplateConnections == null || self.model.reusableTemplateConnections.length ==0 )|| (self.model.reusableTemplateConnections != null && self.model.reusableTemplateConnections.length >0 && assignedPortIds.length ==self.model.reusableTemplateConnections.length);
             if(hasPortConnections) {
                 RegisterTemplateService.getNiFiTemplateFlowInformation(self.model.nifiTemplateId, self.model.reusableTemplateConnections).then(function (response) {
                     var map = {};

                     if (response && response.data) {

                         var datasourceDefinitions = response.data.templateProcessorDatasourceDefinitions;
                         self.allowUserDefinedFailureProcessors = response.data.userDefinedFailureProcessors;

                         //merge in those already selected/saved on this template
                         _.each(datasourceDefinitions, function (def) {
                             def.selectedDatasource = false;
                             if (self.model.registeredDatasourceDefinitions.length == 0) {
                                 def.selectedDatasource = true;
                             }
                             else {

                                 var matchingTypes = _.filter(self.model.registeredDatasourceDefinitions, function (ds) {
                                     return (def.processorType == ds.processorType && ( ds.processorId == def.processorId || ds.processorName == def.processorName));
                                 });
                                 if (matchingTypes.length > 0) {
                                     def.selectedDatasource = true;
                                 }
                             }
                         });
                         //sort with SOURCE's first
                         self.processorDatasourceDefinitions = _.sortBy(datasourceDefinitions, function (def) {
                             if (def.datasourceDefinition.connectionType == 'SOURCE') {
                                 return 1;
                             }
                             else {
                                 return 2;
                             }
                         });

                     }
                     self.loadingFlowData = false;
                 });
             }
             else {
                 self.loadingFlowData = false;
             }

        };

        /**
         * Fetches the output/input ports and walks the flow to build the processor graph for the Data sources and the flow types
         */
        var initTemplateFlowData = function () {
            if (self.model.needsReusableTemplate) {
                RegisterTemplateService.fetchRegisteredReusableFeedInputPorts().then(function (response) {
                    // Update connectionMap and inputPortList
                    self.inputPortList = [];
                    if (response.data) {
                        angular.forEach(response.data, function (port, i) {
                            self.inputPortList.push({label: port.name, value: port.name});
                            self.connectionMap[port.name] = port;
                        });
                    }

                    // Check for invalid connections
                    angular.forEach(self.model.reusableTemplateConnections, function (connection) {
                        //initially mark as valid
                        self.registerTemplateForm["port-" + connection.feedOutputPortName].$setValidity("invalidConnection", true);
                        if (!angular.isDefined(self.connectionMap[connection.inputPortDisplayName])) {
                            connection.inputPortDisplayName = null;
                            //mark as invalid
                            self.registerTemplateForm["port-" + connection.feedOutputPortName].$setValidity("invalidConnection", false);
                        }
                    });

                    buildTemplateFlowData();
                });
            }
            else {
                buildTemplateFlowData();
            }
        }

        /**
         * Initialze the template options
         */
        initTemplateTableOptions();

        /**
         * Initialize the connections and flow data
         */
        initTemplateFlowData();

        /**
         * Called when the user changes the radio buttons
         */
        this.onTableOptionChange = function () {

            if (self.templateTableOption == 'DEFINE_TABLE') {
                self.model.defineTable = true;
                self.model.dataTransformation = false;
            }
            else if (self.templateTableOption == 'DATA_TRANSFORMATION') {
                self.model.defineTable = false;
                self.model.dataTransformation = true;
            }
            else if (self.templateTableOption == 'NO_TABLE') {
                self.model.defineTable = false;
                self.model.dataTransformation = false;
            }
        }

        /**
         * Called when the user changes the output port connections
         * @param connection
         */
        self.onReusableTemplateConnectionChange = function (connection) {
            var port = self.connectionMap[connection.inputPortDisplayName];
            connection.reusableTemplateInputPortName = port.name;
            //mark as valid
            self.registerTemplateForm["port-" + connection.feedOutputPortName].$setValidity("invalidConnection", true);
            buildTemplateFlowData();
        };

        /**
         * Called when the user clicks to change the icon
         */
        this.showIconPicker = function () {
            var iconModel = {icon: self.model.icon.title, iconColor: self.model.icon.color};
            iconModel.name = self.model.templateName;

            $mdDialog.show({
                controller: 'IconPickerDialog',
                templateUrl: 'js/shared/icon-picker-dialog/icon-picker-dialog.html',
                parent: angular.element(document.body),
                clickOutsideToClose: false,
                fullscreen: true,
                locals: {
                    iconModel: iconModel
                }
            }).then(function (msg) {
                if (msg) {
                    self.model.icon.title = msg.icon;
                    self.model.icon.color = msg.color;
                }

            }, function () {

            });
        };

        /**
         * Called when the user clicks Register
         * @returns {*}
         */
        this.registerTemplate = function () {

            showRegistrationInProgressDialog();
            var successFn = function (response) {
                $mdDialog.hide();
                var message = 'Template Registered with ' + response.data.properties.length + ' properties';
                self.registrationSuccess = true;

                $mdToast.show(
                    $mdToast.simple()
                        .textContent(message)
                        .hideDelay(3000)
                );
                StateService.navigateToRegisterTemplateComplete(message, self.model, null);
            }
            var errorFn = function (err) {
                $mdDialog.hide();
                var message = 'Error Registering Template ' + err;
                self.registrationSuccess = false;
                $mdToast.show(
                    $mdToast.simple()
                        .textContent(message)
                        .hideDelay(3000)
                );
                showErrorDialog(message);
            }

            //get all properties that are selected
            var savedTemplate = RegisterTemplateService.getModelForSave();
            //get template order
            var order = [];
            _.each(self.templateOrder, function (template) {
                order.push(template.id);
            });
            savedTemplate.templateOrder = order;

            var thisOrder = order.length - 1;
            if (self.model.id != undefined) {
                thisOrder = _.indexOf(order, self.model.id)
            }
            else {
                thisOrder = _.indexOf(order, 'NEW');
            }
            savedTemplate.order = thisOrder

            //add in the datasources
            var selectedDatasourceDefinitions = _.filter(self.processorDatasourceDefinitions, function (ds) {
                return ds.selectedDatasource == true;
            })

            savedTemplate.registeredDatasourceDefinitions = selectedDatasourceDefinitions;

            var promise = $http({
                url: RestUrlService.REGISTER_TEMPLATE_URL(),
                method: "POST",
                data: angular.toJson(savedTemplate),
                headers: {
                    'Content-Type': 'application/json; charset=UTF-8'
                }
            }).then(successFn, errorFn);
            return promise;
        }

        $scope.$watch(function () {
            return self.model.nifiTemplateId;
        }, function (newVal) {
            if (newVal != null) {
                self.registrationSuccess = false;
            }
        });

        /**
         * Shows a dialog with a progress when the registration is in progress
         */
        var showRegistrationInProgressDialog = function () {
            //hide any dialogs
            $mdDialog.hide();
            $mdDialog.show({
                controller: RegistrationInProgressDialogController,
                templateUrl: 'js/register-template/register-template/register-template-inprogress-dialog.html',
                parent: angular.element(document.body),
                clickOutsideToClose: false,
                fullscreen: true,
                locals: {
                    templateName: self.model.templateName
                }
            })

        }

        /**
         * Shows an Error dialog with a message
         * @param message
         */
        var showErrorDialog = function (message) {

            $mdDialog.show({
                controller: RegistrationErrorDialogController,
                templateUrl: 'js/register-template/register-template/register-template-error-dialog.html',
                parent: angular.element(document.body),
                clickOutsideToClose: true,
                fullscreen: true,
                locals: {
                    nifiTemplateId: self.model.nifiTemplateId,
                    templateName: self.model.templateName,
                    message: message
                }
            });
        };


    }

    angular.module(MODULE_FEED_MGR).controller("RegisterCompleteRegistrationController", RegisterCompleteRegistrationController);
    angular.module(MODULE_FEED_MGR).controller("RegisterTemplateCompleteController", RegisterTemplateCompleteController);

    angular.module(MODULE_FEED_MGR).directive("thinkbigRegisterCompleteRegistration", directive);
})();

function RegistrationErrorDialogController($scope, $mdDialog, $mdToast, $http, StateService, nifiTemplateId, templateName, message) {
    $scope.nifiTemplateId = nifiTemplateId;
    $scope.templateName = templateName;
    $scope.message = message;

    $scope.gotIt = function () {
        $mdDialog.cancel();
    };
}

function RegistrationInProgressDialogController($scope, $mdDialog, templateName) {

    $scope.templateName = templateName;
}

function RegisterTemplateCompleteController(StateService, $rootScope, $state, $stateParams) {

    var self = this;
    self.message = $stateParams.message;
    self.model = $stateParams.templateModel;

    this.gotIt = function () {
        StateService.navigateToRegisteredTemplates();
    }

}

function FlowTypeOptionsHelpPanelMenuCtrl(mdPanelRef, $timeout) {
    this._mdPanelRef = mdPanelRef;

}
