# source : crud_controller.js

    /**
     * @license Ulakbus-UI
     * Copyright (C) 2015 ZetaOps Inc.
     *
     * This file is licensed under the GNU General Public License v3
     * (GPLv3).  See LICENSE.txt for details.
     */
    'use strict';
    /**
     * @ngdoc module
     * @name ulakbus.crud
     * @module ulakbus.crud
     * @description
     * ulakbus.crud module is the main module for ui. It interacts with backend and manipulate data to screen
     * generically.
     *
     * @requires ui.bootstrap
     * @requires schemaForm
     * @requires ulakbus.formService
     * @type {ng.$compileProvider|*}
     */
    angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formService'])
        .config(function (sfErrorMessageProvider) {
            sfErrorMessageProvider.setDefaultMessage(302, 'Bu alan zorunludur.');
            sfErrorMessageProvider.setDefaultMessage(200, 'En az {{schema.minLength}} değer giriniz.');
            sfErrorMessageProvider.setDefaultMessage(201, 'En fazla {{schema.minLength}} değer giriniz.');
        })
        /**
         * @memberof ulakbus.crud
         * @ngdoc service
         * @name CrudUtility
         * @description Crud Utility is a service to provide generic functions for Crud controllers to format data and
         * scope object.
         * @returns {service}
         */
        .service('CrudUtility', function ($log, $rootScope) {
            return {
                /**
                 * @memberof ulakbus.crud
                 * @ngdoc function
                 * @name generateParam
                 * @description generateParam is a function to generate required params to post backend api.
                 * @param {object} scope
                 * @param {object} routeParams
                 * @param {string} cmd
                 * @returns {object} scope
                 */
                generateParam: function (scope, routeParams, cmd) {
                    scope.url = routeParams.wf;
                    angular.forEach(routeParams, function (value, key) {
                        if (key.indexOf('_id') > -1 && key !== 'param_id') {
                            scope.param = key;
                            scope.param_id = value;
                        }
                    });
                    scope.form_params = {
                        //cmd: cmd,
                        model: routeParams.model,
                        param: scope.param || routeParams.param,
                        id: scope.param_id || routeParams.param_id,
                        wf: routeParams.wf,
                        object_id: routeParams.key,
                        filters: {}
                    };
                    if (scope.param_id) {
                        scope.form_params.filters[scope.param] = {values: [scope.param_id], type: 'check'};
                        // do not use selected user, get and broadcast data of user in param_id
                        //$rootScope.$broadcast('selectedUserTrigger', [scope.param, scope.param_id]);
                    }
                    scope.model = scope.form_params.model;
                    scope.wf = scope.form_params.wf;
                    scope.param = scope.form_params.param;
                    scope.param_id = scope.form_params.id;
                    return scope;
                },
                /**
                 * @memberof ulakbus.crud
                 * @ngdoc function
                 * @name listPageItems
                 * @description listPageItems is a function to prepare objects to list in the list page.
                 *
                 * @param {object} scope
                 * @param {object} pageData
                 */
                listPageItems: function (scope, pageData) {
                    angular.forEach(pageData, function (value, key) {
                        scope[key] = value;
                    });
                    angular.forEach(scope.objects, function (value, key) {
                        if (key > 0) {
                            var linkIndexes = {};
                            angular.forEach(value.actions, function (v, k) {
                                if (v.show_as === 'link') {linkIndexes = v}
                            });
                            angular.forEach(value.fields, function (v, k) {
                                if (value.actions.length > 0 && linkIndexes.fields){
                                    scope.objects[key].fields[k] = {
                                        type: linkIndexes.fields.indexOf(k) > -1 ? 'link' : 'str',
                                        content: v,
                                        cmd: linkIndexes.cmd,
                                        mode: linkIndexes.mode
                                    };
                                }
                                else {
                                    scope.objects[key].fields[k] = {type: 'str', content: v};
                                }
                            });
                        }
                    });
                    $log.debug(scope.objects);
                }
            }
        })
        /**
         * @memberof ulakbus.crud
         * @ngdoc controller
         * @name CRUDCtrl
         * @description CRUDCtrl controller is base controller for crud module to redirect to related controller
         * This controller play an empty role for api calls.
         * With response data, location path change to related controller
         *
         * @returns {object}
         */
        .controller('CRUDCtrl', function ($scope, $routeParams, Generator, CrudUtility) {
            // get required params by calling CrudUtility.generateParam function
            CrudUtility.generateParam($scope, $routeParams);
            Generator.get_wf($scope);
        })
        /**
         * @memberof ulakbus.crud
         * @ngdoc controller
         * @name CRUDListFormCtrl
         * @description CRUDListFormCtrl is the main controller for crud module
         * Based on the client_cmd parameter it generates its scope items.
         * client_cmd can be in ['show', 'list', 'form', 'reload', 'refresh']
         * There are 3 directives to manipulate controllers scope objects in crud.html
         * <br>
         * The controller works in 2 ways, with and without pageData.
         * pageData is generated by formService.Generator and it contains data to manipulate page.
         * If pageData has set, using Generator's getPageData() function, sets its scope items. After getting pageData
         * pageData must be set to `{pageData: false}` for clear scope of next job.
         * <br>
         * If pageData has not set using Generator's get_wf() function gets scope items from api call.
         *
         * @returns {object}
         */
        .controller('CRUDListFormCtrl', function ($scope, $rootScope, $location, $http, $log, $uibModal, $timeout, Generator, $routeParams, CrudUtility) {
            // reloadData must be a json object
            $scope.reload = function (reloadData) {
                $scope.form_params.cmd = $scope.reload_cmd;
                $scope.form_params = angular.extend($scope.form_params, reloadData);
                $log.debug('reload data', $scope);
                Generator.get_wf($scope);
            };
            $scope.$on('reload_cmd', function(event, data){
                $scope.reload_cmd = data;
                $scope.reload({});
            });
            // search directive updates objects after search results
            $scope.$on('updateObjects', function ($event, data) {
                $scope.objects = data;
                CrudUtility.listPageItems($scope, {objects: $scope.objects});
            });
            // we use form generator for generic forms. this makes form's scope to confuse on the path to generate form
            // object by its name. to manage to locate the form to controllers scope we use a directive called form locator
            // a bit dirty way to find form working on but solves our problem
            $scope.$on('formLocator', function (event) {
                $scope.formgenerated = event.targetScope.formgenerated;
            });
            // remove function removes node or listnode item from model data
            $scope.remove = function (item, type, index) {
                $scope[type][item.title].model.splice(index, 1);
                $scope[type][item.title].items.splice(index, 1);
            }
            $scope.onSubmit = function (form) {
                $scope.$broadcast('schemaFormValidate');
                if (form.$valid) {
                    Generator.submit($scope);
                }
            };
            $scope.do_action = function (key, todo) {
                //Generator.doItemAction($scope, key, todo.cmd, todo.wf, todo.mode || 'normal');
                Generator.doItemAction($scope, key, todo, todo.mode || 'normal');
            };
            $scope.getNumber = function (num) {
                return new Array(num);
            };
            $scope.createListObjects = function () {
                if ($scope.object.constructor === Array) {
                    $log.debug('new type show object')
                } else {
                    if ($scope.object.type) {
                        $scope.object = [$scope.object];
                    } else {
                        $scope.object = [{type: 'table', fields: angular.copy($scope.object)}];
                    }
                }
            };
            $scope.showCmd = function () {
                CrudUtility.generateParam($scope, $routeParams, $routeParams.cmd);
                // todo: refactor createListObjects func
                var pageData = Generator.getPageData();
                if (pageData.pageData === true) {
                    $scope.object = pageData.object;
                    Generator.setPageData({pageData: false});
                }
                else {
                    // call generator's get_single_item func
                    Generator.get_wf($scope).then(function (res) {
                        $scope.object = res.data.object;
                        $scope.model = $routeParams.model;
                    });
                }
                $scope.createListObjects();
            };
            $scope.listFormCmd = function () {
                // function to set scope objects
                var setpageobjects = function (data) {
                    CrudUtility.listPageItems($scope, data);
                    Generator.generate($scope, data);
                    Generator.setPageData({pageData: false});
                };
                // get pageData from service
                var pageData = Generator.getPageData();
                // if pageData exists do not call get_wf function and manipulate page with pageData
                if (pageData.pageData === true) {
                    $log.debug('pagedata', pageData.pageData);
                    CrudUtility.generateParam($scope, pageData, $routeParams.cmd);
                    setpageobjects(pageData, pageData);
                    if ($scope.second_client_cmd) {
                        $scope.createListObjects();
                    }
                }
                // if pageData didn't defined or is {pageData: false} go get data from api with get_wf function
                if (pageData.pageData === undefined || pageData.pageData === false) {
                    CrudUtility.generateParam($scope, $routeParams, $routeParams.cmd);
                    Generator.get_wf($scope);
                }
                if ($scope.object) {
                    $scope.createListObjects();
                }
            };
            $scope.reloadCmd = function () {
                $scope.reload({});
            };
            $scope.resetCmd = function () {
                delete $scope.token;
                $scope.cmd = 'reset';
                Generator.get_wf($scope);
            };
            var executeCmd = {
                show: $scope.showCmd,
                list: $scope.listFormCmd,
                form: $scope.listFormCmd,
                reload: $scope.reloadCmd,
                reset: $scope.resetCmd
            };
            return executeCmd[$routeParams.cmd]();
        })
        /**
         * @memberof ulakbus.crud
         * @ngdoc directive
         * @name crudListDirective
         * @description directive for listing objects.
         * provides template for `scope.objects` object.
         */
        .directive('crudListDirective', function () {
            return {
                templateUrl: 'components/crud/templates/list.html',
                restrict: 'E',
                replace: true
            };
        })
        /**
         * @memberof ulakbus.crud
         * @ngdoc directive
         * @name crudFormDirective
         * @description directive for form generation.
         * provides template for `scope.forms` object.
         */
        .directive('crudFormDirective', function () {
            return {
                templateUrl: 'components/crud/templates/form.html',
                restrict: 'E',
                replace: true
            };
        })
        /**
         * @memberof ulakbus.crud
         * @ngdoc directive
         * @name crudShowDirective
         * @description directive for single object or detail of an object.
         * provides template for `scope.object` object.
         */
        .directive('crudShowDirective', function () {
            return {
                templateUrl: 'components/crud/templates/show.html',
                restrict: 'E',
                replace: true
            };
        })
        /**
         * @memberof ulakbus.crud
         * @ngdoc directive
         * @name formLocator
         * @description directive for finding form element. we use this directive because when form dynamically generated using
         * schemaform it belongs to a scope which is hard to reach. This makes it easy to locate form object.
         */
        .directive('formLocator', function () {
            return {
                link: function (scope) {
                    scope.$emit('formLocator');
                }
            }
        })
        /**
         * @memberof ulakbus.crud
         * @ngdoc directive
         * @name crudFilters
         * @description directive for filtering functionality. There are three types of filters; `check`, `select`, and `date`.
         * @todo filter items returns unselected in response object
         */
        .directive('crudFilters', function(Generator) {
            return {
                templateUrl: 'components/crud/templates/filter.html',
                restrict: 'E',
                replace: true,
                link: function ($scope) {
                    $scope.form_params.filters = $scope.form_params.filters || {};
                    $scope.filterList = {};
                    $scope.filterCollapsed = {};
                    $scope.$watch('list_filters', function () {
                        angular.forEach($scope.list_filters, function (value, key) {
                            $scope.filterList[value.field] = {values: value.values || [], type: value.type};
                            $scope.filterCollapsed[value.field] = Object.keys($scope.filterCollapsed).length > 0 ? true : false;
                        });
                    });
                    $scope.collapseFilter = function (field) {
                        $scope.filterCollapsed[field] = !$scope.filterCollapsed[field];
                    };
                    $scope.status = {startOpened: false, endOpened: false};
                    $scope.dateFilterOpen = function ($event, which) {
                        this.status[which] = true;
                    };
                    $scope.format = 'dd.MM.yyyy';
                    $scope.filterSubmit = function () {
                        angular.forEach($scope.filterList, function (value, key) {
                            if (value.model) {
                                if (value.type === 'date') {
                                    var dateValues = [null, null];
                                    angular.forEach(value.model, function (v, k) {
                                        dateValues[k] = Generator.dateformatter(v);
                                    });
                                    $scope.form_params.filters[key] = {values: dateValues, type: value.type};
                                } else {
                                    $scope.form_params.filters[key] = {values: Object.keys(value.model), type: value.type || 'check'};
                                }
                            }
                        });
                        Generator.get_wf($scope);
                    }
                }
            };
        });