import {ng, ngDeps} from './vendor';
import {camelToKebab} from './lib/string';

/**
 * Extended component options.
 *
 * @property {Boolean} installClassses Whether to install CSS classes equivalent to the component's and parents name
 * @property {String} slotTemplate HTML template used to fill component transclude slots
 */
const defaultOptions = {
    installClasses: true
};

/**
 * Acts like native Module.component() function but merging component options
 * with parent component options. This method establishes the $options property
 * to the component controller class with the merged component options. To
 * retrieve parent options, it reads the same property of the parent class, so
 * for the parent options to be copied, it must have been declared using this
 * same function. If any of the options (template, transclude, bindings...) is
 * redeclared in the child component, the last has preference.
 *
 * @param {String} name Coponent name in camelCase
 * @param {Object} options The component options
 * @return {angularModule} The same angular module
 */
function vnComponent(name, options) {
    let controller = options.controller;
    let parent = Object.getPrototypeOf(controller);
    let parentOptions = parent.$options || defaultOptions;

    let parentTransclude = parentOptions.transclude;
    let transclude = parentTransclude instanceof Object
        ? Object.assign({}, parentTransclude)
        : parentTransclude;

    if (options.transclude instanceof Object) {
        if (transclude instanceof Object)
            Object.assign(transclude, options.transclude);
        else
            transclude = options.transclude;
    } else if (options.transclude !== undefined)
        transclude = options.transclude;

    let $options = Object.assign({},
        parentOptions,
        options,
        {
            name,
            transclude,
            bindings: Object.assign({},
                parentOptions.bindings,
                options.bindings
            ),
            require: Object.assign({},
                parentOptions.require,
                options.require
            )
        }
    );

    let parentSlotTemplates = parent.slotTemplates || [];
    if (options.slotTemplate)
        controller.slotTemplates = parentSlotTemplates.concat([options.slotTemplate]);

    let classNames = [camelToKebab(name)];
    if (parent.$classNames) classNames = classNames.concat(parent.$classNames);
    controller.$classNames = classNames;

    controller.$options = $options;
    return this.component(name, $options);
}

const ngModuleFn = ng.module;

ng.module = function(...args) {
    let ngModule = ngModuleFn.apply(this, args);
    ngModule.vnComponent = vnComponent;
    return ngModule;
};

const ngModule = ng.module('vnCore', ngDeps);
export default ngModule;

config.$inject = ['$translateProvider', '$translatePartialLoaderProvider', '$animateProvider'];
export function config($translateProvider, $translatePartialLoaderProvider, $animateProvider) {
    // For CSS browser targeting
    document.documentElement.setAttribute('data-browser', navigator.userAgent);

    $translateProvider
        .useSanitizeValueStrategy('escape')
        .useLoader('$translatePartialLoader', {
            urlTemplate: '/locale/{part}/{lang}.json'
        });
    $translatePartialLoaderProvider.addPart('core');

    $animateProvider.customFilter(
        node => node.tagName == 'UI-VIEW');
}
ngModule.config(config);