/*global angular*/

/*
 * This is an example ng-admin configuration for a blog administration composed
 * of three entities: post, comment, and tag. Reading the code and the comments
 * will help you understand how a typical ng-admin application works.
 *
 * The remote REST API is simulated in the browser, using FakeRest
 * (https://github.com/marmelab/FakeRest). Look at the JSON responses in the
 * browser console to see the data used by ng-admin.
 *
 * For simplicity's sake, the entire configuration is written in a single file,
 * but in a real world situation, you would probably split that configuration
 * into one file per entity. For another example configuration on a larger set
 * of entities, and using the best development practices, check out the
 * Posters Galore demo (http://marmelab.com/ng-admin-demo/).
 */
(function () {
    "use strict";

    var app = angular.module('myApp', ['ng-admin']);

    // API Mapping
    app.config(['RestangularProvider', function (RestangularProvider) {

        // use the custom query parameters function to format the API request correctly
        RestangularProvider.addFullRequestInterceptor(function(element, operation, what, url, headers, params) {
            if (operation === 'getList') {
                // custom pagination params
                if (params._page) {
                    var start = (params._page - 1) * params._perPage;
                    var end = params._page * params._perPage - 1;
                    params.range = "[" + start + "," + end + "]";
                    delete params._page;
                    delete params._perPage;
                }
                // custom sort params
                if (params._sortField) {
                    params.sort = '["' + params._sortField + '","' + params._sortDir + '"]';
                    delete params._sortField;
                    delete params._sortDir;
                }
                // custom filters
                if (params._filters) {
                    params.filter = params._filters;
                    delete params._filters;
                }
            }
            return { params: params };
        });

        RestangularProvider.addResponseInterceptor(function(data, operation, what, url, response) {
            if (operation === "getList") {
                var headers = response.headers();
                if (headers['content-range']) {
                    response.totalCount = headers['content-range'].split('/').pop();
                }
            }

            return data;
        });
    }]);

    // Admin definition
    app.config(['NgAdminConfigurationProvider', function (NgAdminConfigurationProvider) {
        var nga = NgAdminConfigurationProvider;

        function truncate(value) {
            if (!value) {
                return '';
            }

            return value.length > 50 ? value.substr(0, 50) + '...' : value;
        }

        var admin = nga.application('ng-admin blog demo') // application main title
            .debug(false) // debug disabled
            .baseApiUrl('http://localhost:3000/'); // main API endpoint

        // define all entities at the top to allow references between them
        var post = nga.entity('posts'); // the API endpoint for posts will be http://localhost:3000/posts/:id

        var comment = nga.entity('comments')
            .baseApiUrl('http://localhost:3000/') // The base API endpoint can be customized by entity
            .identifier(nga.field('id')); // you can optionally customize the identifier used in the api ('id' by default)

        var tag = nga.entity('tags');

        var subCategories = [
            { category: 'tech', label: 'Computers', value: 'computers' },
            { category: 'tech', label: 'Gadgets', value: 'gadgets' },
            { category: 'lifestyle', label: 'Travel', value: 'travel' },
            { category: 'lifestyle', label: 'Fitness', value: 'fitness' }
        ];

        // set the application entities
        admin
            .addEntity(post)
            .addEntity(tag)
            .addEntity(comment);

        // customize entities and views

        /*****************************
         * post entity customization *
         *****************************/
        post.listView()
            .title('All posts') // default title is "[Entity_name] list"
            .description('List of posts with infinite pagination') // description appears under the title
            .infinitePagination(true) // load pages as the user scrolls
            .fields([
                nga.field('id').label('id'), // The default displayed name is the camelCase field name. label() overrides id
                nga.field('title'), // the default list field type is "string", and displays as a string
                nga.field('published_at', 'date'),  // Date field type allows date formatting
                nga.field('average_note', 'float') // Float type also displays decimal digits
                    .cssClasses('hidden-xs'),
                nga.field('views', 'number')
                    .cssClasses('hidden-xs'),
                nga.field('backlinks', 'embedded_list') // display list of related comments
                    .label('Links')
                    .map(links => links ? links.length : '')
                    .template('{{ value }}'),
                nga.field('tags', 'reference_many') // a Reference is a particular type of field that references another entity
                    .targetEntity(tag) // the tag entity is defined later in this file
                    .targetField(nga.field('name')) // the field to be displayed in this list
                    .cssClasses('hidden-xs')
                    .singleApiCall(ids => { return {'id': ids }; })
            ])
            .filters([
                nga.field('category', 'choice').choices([
                    { label: 'Tech', value: 'tech' },
                    { label: 'Lifestyle', value: 'lifestyle' }
                ]).label('Category'),
                nga.field('subcategory', 'choice').choices(subCategories).label('Subcategory')
            ])
            .listActions(['show', 'edit', 'delete'])
            .entryCssClasses(function(entry) { // set row class according to entry
                return (entry.views > 300) ? 'is-popular' : '';
            })
            .exportFields([
                post.listView().fields(), // fields() without arguments returns the list of fields. That way you can reuse fields from another view to avoid repetition
                nga.field('category', 'choice') // a choice field is rendered as a dropdown in the edition view
                    .choices([ // List the choice as object literals
                        { label: 'Tech', value: 'tech' },
                        { label: 'Lifestyle', value: 'lifestyle' }
                    ]),
                nga.field('subcategory', 'choice')
                    .choices(function(entry) { // choices also accepts a function to return a list of choices based on the current entry
                        return subCategories.filter(function (c) {
                            return c.category === entry.values.category;
                        });
                    }),
            ])
            .exportOptions({
                quotes: true,
                delimiter: ';'
            });

        post.creationView()
            .fields([
                nga.field('title') // the default edit field type is "string", and displays as a text input
                    .attributes({ placeholder: 'the post title' }) // you can add custom attributes, too
                    .validation({ required: true, minlength: 3, maxlength: 100 }), // add validation rules for fields
                nga.field('teaser', 'text'), // text field type translates to a textarea
                nga.field('body', 'wysiwyg'), // overriding the type allows rich text editing for the body
                nga.field('published_at', 'date') // Date field type translates to a datepicker
            ]);

        post.editionView()
            .title('Edit post "{{ entry.values.title }}"') // title() accepts a template string, which has access to the entry
            .actions(['list', 'show', 'delete']) // choose which buttons appear in the top action bar. Show is disabled by default
            .fields([
                post.creationView().fields(), // fields() without arguments returns the list of fields. That way you can reuse fields from another view to avoid repetition
                nga.field('category', 'choice') // a choice field is rendered as a dropdown in the edition view
                    .choices([ // List the choice as object literals
                        { label: 'Tech', value: 'tech' },
                        { label: 'Lifestyle', value: 'lifestyle' }
                    ]),
                nga.field('subcategory', 'choice')
                    .choices(function(entry) { // choices also accepts a function to return a list of choices based on the current entry
                        return subCategories.filter(function (c) {
                            return c.category === entry.values.category;
                        });
                    })
                    .template('<ma-field ng-if="entry.values.category" field="::field" value="entry.values[field.name()]" entry="entry" entity="::entity" form="formController.form" datastore="::formController.dataStore"></ma-field>', true),
                nga.field('tags', 'reference_many') // ReferenceMany translates to a select multiple
                    .targetEntity(tag)
                    .targetField(nga.field('name'))
                    .attributes({ placeholder: 'Select some tags...' })
                    .remoteComplete(true, {
                        refreshDelay: 300 ,
                        searchQuery: function(search) { return { q: search }; }
                    })
                    .singleApiCall(ids => { return {'id': ids }; })
                    .cssClasses('col-sm-4'), // customize look and feel through CSS classes
                nga.field('pictures', 'json'),
                nga.field('views', 'number')
                    .cssClasses('col-sm-4'),
                nga.field('average_note', 'float')
                    .cssClasses('col-sm-4'),
                nga.field('backlinks', 'embedded_list') // display embedded list
                    .targetFields([
                        nga.field('date', 'datetime'),
                        nga.field('url')
                            .cssClasses('col-lg-10')
                    ])
                    .sortField('date')
                    .sortDir('DESC'),
                nga.field('comments', 'referenced_list') // display list of related comments
                    .targetEntity(nga.entity('comments'))
                    .targetReferenceField('post_id')
                    .targetFields([
                        nga.field('id').isDetailLink(true),
                        nga.field('created_at').label('Posted'),
                        nga.field('body').label('Comment')
                    ])
                    .sortField('created_at')
                    .sortDir('DESC')
                    .listActions(['edit']),
                nga.field('').label('')
                    .template('<span class="pull-right"><ma-filtered-list-button entity-name="comments" filter="{ post_id: entry.values.id }" size="sm"></ma-filtered-list-button><ma-create-button entity-name="comments" size="sm" label="Create related comment" default-values="{ post_id: entry.values.id }"></ma-create-button></span>')
            ]);

        post.showView() // a showView displays one entry in full page - allows to display more data than in a a list
            .fields([
                nga.field('id'),
                nga.field('title'),
                nga.field('teaser'),
                nga.field('body', 'wysiwyg'),
                nga.field('published_at', 'date'),
                nga.field('category', 'choice') // a choice field is rendered as a dropdown in the edition view
                    .choices([ // List the choice as object literals
                        { label: 'Tech', value: 'tech' },
                        { label: 'Lifestyle', value: 'lifestyle' }
                    ]),
                nga.field('subcategory', 'choice')
                    .choices(subCategories),
                nga.field('tags', 'reference_many') // ReferenceMany translates to a select multiple
                    .targetEntity(tag)
                    .targetField(nga.field('name')),
                nga.field('pictures', 'json'),
                nga.field('views', 'number'),
                nga.field('average_note', 'float'),
                nga.field('backlinks', 'embedded_list') // display embedded list
                    .targetFields([
                        nga.field('date', 'datetime'),
                        nga.field('url')
                    ])
                    .sortField('date')
                    .sortDir('DESC'),
                nga.field('comments', 'referenced_list') // display list of related comments
                    .targetEntity(nga.entity('comments'))
                    .targetReferenceField('post_id')
                    .targetFields([
                        nga.field('id').isDetailLink(true),
                        nga.field('created_at').label('Posted'),
                        nga.field('body').label('Comment')
                    ])
                    .sortField('created_at')
                    .sortDir('DESC')
                    .listActions(['edit']),
                nga.field('').label('')
                    .template('<span class="pull-right"><ma-filtered-list-button entity-name="comments" filter="{ post_id: entry.values.id }" size="sm"></ma-filtered-list-button><ma-create-button entity-name="comments" size="sm" label="Create related comment" default-values="{ post_id: entry.values.id }"></ma-create-button></span>'),
                nga.field('custom_action').label('')
                    .template('<send-email post="entry"></send-email>')
            ]);

        /********************************
         * comment entity customization *
         ********************************/
        comment.listView()
            .title('Comments')
            .perPage(10) // limit the number of elements displayed per page. Default is 30.
            .fields([
                nga.field('created_at', 'date')
                    .label('Posted'),
                nga.field('author.name')
                    .label('Author')
                    .cssClasses('hidden-xs'),
                nga.field('body', 'wysiwyg')
                    .stripTags(true)
                    .map(truncate),
                nga.field('post_id', 'reference')
                    .label('Post')
                    .targetEntity(post)
                    .targetField(nga.field('title').map(truncate))
                    .cssClasses('hidden-xs')
                    .singleApiCall(ids => { return {'id': ids }; })
            ])
            .filters([
                nga.field('q')
                    .label('')
                    .pinned(true)
                    .template('<div class="input-group"><input type="text" ng-model="value" placeholder="Search" class="form-control"></input><span class="input-group-addon"><i class="glyphicon glyphicon-search"></i></span></div>')
                    .transform(v => v && v.toUpperCase()) // transform the entered value before sending it as a query parameter
                    .map(v => v && v.toLowerCase()), // map the query parameter to a displayed value in the filter form
                nga.field('created_at', 'date')
                    .label('Posted')
                    .attributes({'placeholder': 'Filter by date'}),
                nga.field('post_id', 'reference')
                    .label('Post')
                    .targetEntity(post)
                    .targetField(nga.field('title'))
                    .remoteComplete(true, {
                        refreshDelay: 200,
                        searchQuery: function(search) { return { q: search }; }
                    })
            ])
            .listActions(['edit', 'delete']);

        comment.creationView()
            .fields([
                nga.field('created_at', 'date')
                    .label('Posted')
                    .defaultValue(new Date()), // preset fields in creation view with defaultValue
                nga.field('author.name')
                    .label('Author'),
                nga.field('body', 'wysiwyg'),
                nga.field('post_id', 'reference')
                    .label('Post')
                    .targetEntity(post)
                    .targetField(nga.field('title').map(truncate))
                    .sortField('title')
                    .sortDir('ASC')
                    .validation({ required: true })
                    .remoteComplete(true, {
                        refreshDelay: 200,
                        searchQuery: function(search) { return { q: search }; }
                    })
            ]);

        comment.editionView()
            .fields(comment.creationView().fields())
            .fields([
                nga.field('').label('')
                    .template('<post-link entry="entry"></post-link>') // template() can take a function or a string
            ]);

        comment.deletionView()
            .title('Deletion confirmation'); // customize the deletion confirmation message

        /****************************
         * tag entity customization *
         ****************************/
        tag.listView()
            .infinitePagination(false) // by default, the list view uses infinite pagination. Set to false to use regulat pagination
            .fields([
                nga.field('id').label('ID'),
                nga.field('name'),
                nga.field('published', 'boolean').cssClasses(function(entry) { // add custom CSS classes to inputs and columns
                    if (entry && entry.values){
                        if (entry.values.published) {
                            return 'bg-success text-center';
                        }
                        return 'bg-warning text-center';
                    }
                }),
                nga.field('custom')
                    .label('Upper name')
                    .template('{{ entry.values.name.toUpperCase() }}')
                    .cssClasses('hidden-xs'),
                nga.field('nb_posts')
            ])
            .filters([
                nga.field('published')
                    .label('Not yet published')
                    .template(' ')
                    .defaultValue(false)
            ])
            .batchActions([]) // disable checkbox column and batch delete
            .listActions(['show', 'edit']);

        // define custom controller logic for the tag listView
        tag.listView().prepare(['Restangular', 'entries', function(Restangular, entries) {
            // fetch the number of posts for each tag
            return Restangular.allUrl('posts').getList()
                .then(function(response) {
                    const nbPostsByTag = {};
                    response.data.forEach(function(post) {
                        post.tags.forEach(function(tagId) {
                            if (!nbPostsByTag[tagId]) {
                                nbPostsByTag[tagId] = 0;
                            }
                            nbPostsByTag[tagId]++;
                        });
                    });
                    entries.map(function(tag) {
                        tag.values.nb_posts = nbPostsByTag[tag.identifierValue];
                    });
                });
        }]);

        tag.editionView()
            .fields([
                nga.field('name'),
                nga.field('published', 'boolean').validation({
                    required: true // as this boolean is required, ng-admin will use a checkbox instead of a dropdown
                })
            ]);

        tag.showView()
            .fields([
                nga.field('name'),
                nga.field('published', 'boolean')
            ]);

        // customize header
        var customHeaderTemplate =
        '<div class="navbar-header">' +
            '<button type="button" class="navbar-toggle" ng-click="isCollapsed = !isCollapsed">' +
              '<span class="icon-bar"></span>' +
              '<span class="icon-bar"></span>' +
              '<span class="icon-bar"></span>' +
            '</button>' +
            '<a class="navbar-brand" href="#" ng-click="appController.displayHome()">ng-admin backend demo</a>' +
        '</div>' +
        '<p class="navbar-text navbar-right hidden-xs">' +
            '<a href="https://github.com/marmelab/ng-admin/blob/master/examples/blog/config.js"><span class="glyphicon glyphicon-sunglasses"></span>&nbsp;View Source</a>' +
        '</p>';
        admin.header(customHeaderTemplate);

        // customize menu
        admin.menu(nga.menu()
            .addChild(nga.menu(post).icon('<span class="glyphicon glyphicon-file"></span>')) // customize the entity menu icon
            .addChild(nga.menu(comment).icon('<strong style="font-size:1.3em;line-height:1em">✉</strong>')) // you can even use utf-8 symbols!
            .addChild(nga.menu(tag).icon('<span class="glyphicon glyphicon-tags"></span>'))
            .addChild(nga.menu().title('Other')
                .addChild(nga.menu().title('Stats').icon('').link('/stats'))
            )
        );

        // customize dashboard
        var customDashboardTemplate =
        '<div class="row dashboard-starter"></div>' +
        '<div class="row dashboard-content"><div class="col-lg-12"><div class="alert alert-info">' +
            'Welcome to the demo! Fell free to explore and modify the data. We reset it every few minutes.' +
        '</div></div></div>' +
        '<div class="row dashboard-content">' +
            '<div class="col-lg-12">' +
                '<div class="panel panel-default">' +
                    '<ma-dashboard-panel collection="dashboardController.collections.comments" entries="dashboardController.entries.comments" datastore="dashboardController.datastore"></ma-dashboard-panel>' +
                '</div>' +
            '</div>' +
        '</div>' +
        '<div class="row dashboard-content">' +
            '<div class="col-lg-6">' +
                '<div class="panel panel-green">' +
                    '<ma-dashboard-panel collection="dashboardController.collections.recent_posts" entries="dashboardController.entries.recent_posts" datastore="dashboardController.datastore"></ma-dashboard-panel>' +
                '</div>' +
                '<div class="panel panel-green">' +
                    '<ma-dashboard-panel collection="dashboardController.collections.popular_posts" entries="dashboardController.entries.popular_posts" datastore="dashboardController.datastore"></ma-dashboard-panel>' +
                '</div>' +
            '</div>' +
            '<div class="col-lg-6">' +
                '<div class="panel panel-yellow">' +
                    '<ma-dashboard-panel collection="dashboardController.collections.tags" entries="dashboardController.entries.tags" datastore="dashboardController.datastore"></ma-dashboard-panel>' +
                '</div>' +
            '</div>' +
        '</div>';
        admin.dashboard(nga.dashboard()
            .addCollection(nga.collection(post)
                .name('recent_posts')
                .title('Recent posts')
                .perPage(5) // limit the panel to the 5 latest posts
                .fields([
                    nga.field('published_at', 'date').label('Published').format('MMM d'),
                    nga.field('title').isDetailLink(true).map(truncate),
                    nga.field('views', 'number')
                ])
                .sortField('published_at')
                .sortDir('DESC')
                .order(1)
            )
            .addCollection(nga.collection(post)
                .name('popular_posts')
                .title('Popular posts')
                .perPage(5) // limit the panel to the 5 latest posts
                .fields([
                    nga.field('published_at', 'date').label('Published').format('MMM d'),
                    nga.field('title').isDetailLink(true).map(truncate),
                    nga.field('views', 'number')
                ])
                .sortField('views')
                .sortDir('DESC')
                .order(3)
            )
            .addCollection(nga.collection(comment)
                .title('Last comments')
                .perPage(10)
                .fields([
                    nga.field('created_at', 'date')
                        .label('Posted'),
                    nga.field('body', 'wysiwyg')
                        .label('Comment')
                        .stripTags(true)
                        .map(truncate)
                        .isDetailLink(true),
                    nga.field('post_id', 'reference')
                        .label('Post')
                        .targetEntity(post)
                        .targetField(nga.field('title').map(truncate))
                ])
                .sortField('created_at')
                .sortDir('DESC')
                .order(2)
            )
            .addCollection(nga.collection(tag)
                .title('Tags publication status')
                .perPage(10)
                .fields([
                    nga.field('name'),
                    nga.field('published', 'boolean').label('Is published ?')
                ])
                .listActions(['show'])
                .order(4)
            )
            .template(customDashboardTemplate)
        );

        nga.configure(admin);
    }]);

    app.directive('postLink', ['$location', function ($location) {
        return {
            restrict: 'E',
            scope: { entry: '&' },
            template: '<p class="form-control-static"><a ng-click="displayPost()">View&nbsp;post</a></p>',
            link: function (scope) {
                scope.displayPost = function () {
                    $location.path('/posts/show/' + scope.entry().values.post_id); // jshint ignore:line
                };
            }
        };
    }]);

    app.directive('sendEmail', ['$location', function ($location) {
        return {
            restrict: 'E',
            scope: { post: '&' },
            template: '<a class="btn btn-default" ng-click="send()">Send post by email</a>',
            link: function (scope) {
                scope.send = function () {
                    $location.path('/sendPost/' + scope.post().values.id);
                };
            }
        };
    }]);

    // custom 'send post by email' page

    function sendPostController($stateParams, notification) {
        this.postId = $stateParams.id;
        // notification is the service used to display notifications on the top of the screen
        this.notification = notification;
    }
    sendPostController.prototype.sendEmail = function() {
        if (this.email) {
            this.notification.log('Email successfully sent to ' + this.email, {addnCls: 'humane-flatty-success'});
        } else {
            this.notification.log('Email is undefined', {addnCls: 'humane-flatty-error'});
        }
    };
    sendPostController.$inject = ['$stateParams', 'notification'];

    var sendPostControllerTemplate =
        '<div class="row"><div class="col-lg-12">' +
            '<ma-view-actions><ma-back-button></ma-back-button></ma-view-actions>' +
            '<div class="page-header">' +
                '<h1>Send post #{{ controller.postId }} by email</h1>' +
                '<p class="lead">You can add custom pages, too</p>' +
            '</div>' +
        '</div></div>' +
        '<div class="row">' +
            '<div class="col-lg-5"><input type="text" size="10" ng-model="controller.email" class="form-control" placeholder="name@example.com"/></div>' +
            '<div class="col-lg-5"><a class="btn btn-default" ng-click="controller.sendEmail()">Send</a></div>' +
        '</div>';

    app.config(['$stateProvider', function ($stateProvider) {
        $stateProvider.state('send-post', {
            parent: 'ng-admin',
            url: '/sendPost/:id',
            params: { id: null },
            controller: sendPostController,
            controllerAs: 'controller',
            template: sendPostControllerTemplate
        });
    }]);

    // custom page with menu item
    var customPageTemplate = '<div class="row"><div class="col-lg-12">' +
            '<div class="page-header">' +
                '<ma-view-actions><ma-back-button></ma-back-button></ma-view-actions>' +
                '<h1>Stats</h1>' +
                '<p class="lead">You can add custom pages, too</p>' +
            '</div>' +
        '</div></div>';
    app.config(['$stateProvider', function ($stateProvider) {
        $stateProvider.state('stats', {
            parent: 'ng-admin',
            url: '/stats',
            template: customPageTemplate
        });
    }]);

}());
