'use strict';

/**
 *
 * @param {*} componentDocument
 */

var errMsg = "Error on parsing custom component";
var lodashLang = require('lodash/lang');
var lodashString = require('lodash/string');

var loadComponent = function(componentDocument) {
    if (!componentDocument) {
        throw new Error("Component not specified in loadComponent");
    }

    // load the component into an object representing an AngularJS directive. This will be returned as the directive script
    var directive = {};

    // add each of the standard elements that make up a directive. See the Angular 1 directive documentation for details
    directive.restrict = 'E'; // restrict to element. We are only adding these components as element directives
    directive.require = '?^form';
    directive.scope ={
        tplItem: '=',
        fieldValue: '=',
        fieldName: '=',
        isNew: '=',
        formParameters: '=',
        key: '=',
        doc: '=',
        tpl: '=',
        account: '=',
        responsiveLayouts: '='
    };
    // load the html for the component:
    if (componentDocument.componentHtml) {
        directive.template = componentDocument.componentHtml;
    }
    return JSON.stringify(directive);
};


/**
 * get link function
 */

var getLinkFunction  = function(componentDocument, libraryDocuments){


    var defFuncStr = 'function(scope, element, attrs, formCtrl){ \n ' +
        'var SharedConstants = SharedConstantsService; \n' +
        'var SearchResultsProcessor = SearchResultsProcessorService; \n' +
        'DirectiveSetupService.setupDirective(scope, formCtrl); \n\n';
    defFuncStr += getFieldWatchFunction(componentDocument);
    defFuncStr += getCleanupFunction(componentDocument);
    defFuncStr += loadLibraryFunctions(libraryDocuments);

    var linkFunc = ', "link" : ' + defFuncStr + " \n }";


    var func = lodashString.trim(componentDocument.componentLoadFunction);
    if (!lodashLang.isEmpty(func)) {
        try{
            //adding component load function as link function  and replacing load function
            //starting with "function () {"  to include function argument like scope, element,
            // attrs, formCtrl and DirectiveSetupService.setupDirective function to initialise directive.

             func = func.replace(/^(.*function.*)\{+/, defFuncStr);

            var loadFunc = eval("(" + func + ")");
            linkFunc = ', "link" : ' +  loadFunc ;
        }
        catch (err){
            logger.error(errMsg + " load function :" + err);
        }
    }

    return linkFunc;

};


var getFieldWatchFunction  = function(componentDocument){

    var watchFunc = "";

    var func = lodashString.trim(componentDocument.fieldWatchFunction);
    if (!lodashLang.isEmpty(func)) {

        try{
            var fieldWatchFunction = eval("(" + func + ")");
            watchFunc = "scope.$watch('doc[\"' + scope.fieldName + '\"]'," + fieldWatchFunction + ",  true);\n";
        }
        catch (err){
            logger.error(errMsg + " watch function :" + err);
        }
    }

    return watchFunc;

};

var getCleanupFunction  = function(componentDocument){

    var destroyFunc = "";

    var func = lodashString.trim(componentDocument.componentCleanupFunction);
    if (!lodashLang.isEmpty(func)) {

        try{
            var cleanupFunc = eval("(" + func + ")");
            destroyFunc = "scope.$on('$destroy'," + cleanupFunc + ");\n";
        }
        catch (err){
            logger.error(errMsg + " watch function :" + err);
        }
    }

    return destroyFunc;

};


var loadLibraryFunctions = function (libDocs) {

     var libFunctions = "";

    if (!lodashLang.isEmpty(libDocs)){
        for (var i=0; i<libDocs.length; i++){
            var doc = libDocs[i];
            var func = doc.componentServiceSnippet;
            try{
                if (!lodashLang.isEmpty(func)){
                    libFunctions += "scope." + lodashString.camelCase(doc.serviceName) + " =" + func + " \n";
                }
            }
            catch (err){
                logger.error(errMsg + " library document code :" + err);
            }
        }
    }
    return libFunctions;

};

/**
 * get the component script for the directive
 */
var getComponentDirectiveScript = function(componentDocument, libraryDocuments) {
    var componentJSON = loadComponent(componentDocument);

    var componentScript;

    if (componentJSON) {
        var directiveName = lodashString.camelCase(componentDocument.name);
        componentScript = "angular.module('ft.core').directive('" + directiveName +
            "',[ '$compile', 'DirectiveSetupService', 'SearchService','$ocLazyLoad',  " +
            "'$injector','$timeout','DataService', '$q', 'SharedConstantsService', 'SearchResultsProcessorService', " +
            "function ($compile, DirectiveSetupService,  SearchService, $ocLazyLoad, $injector, " +
            "$timeout, DataService, $q, SharedConstantsService, SearchResultsProcessorService) { return ";

        componentScript += componentJSON.substr(0, componentJSON.length - 1);
        componentScript += getLinkFunction(componentDocument, libraryDocuments);
        componentScript += '\n }';
        componentScript += "; }]);";

        // define a custom element that wraps the AngularJS component. This will be used to load the
        // AngularJS components in the Angular Only version while the components are being upgraded to Angular
        componentScript += `
        (function() {
          // Define the new element
          window.FormbirdServiceInjector.AngularJSWrapperService.registerAngularJSWrapperElement('${componentDocument.name}');
          })();`;
    } else {
        throw new Error("Component not found");
    }

    return componentScript;
};

var getComponentLibraryServiceScript = function(serviceName, libraryDocuments) {
    var componentScript;

    var getFunctions = function (libDocs) {
        var libFunctions = "";
        if (!lodashLang.isEmpty(libDocs)){
            for (var i=0; i<libDocs.length; i++){
                var doc = libDocs[i];
                var func = doc.componentServiceSnippet;
                try{
                    if (!lodashLang.isEmpty(func)){
                        if (!lodashLang.isEmpty(libFunctions)){
                            libFunctions += "," + " \n";
                        }
                        libFunctions +=  func ;
                    }
                }
                catch (err){
                    logger.error(errMsg + " library document code :" + err);
                }
            }
        }
        return libFunctions;
    };


    if (libraryDocuments) {
        var serviceName = getComponentLibraryScriptServiceName(serviceName);

        componentScript = "angular.module('ft.core').service('" + serviceName +
            "',[ '$compile', 'SearchService','$ocLazyLoad',  " +
            "'$injector','$timeout','DataService', '$q', 'SharedConstantsService', 'SearchResultsProcessorService', " +
            "function ($compile, SearchService, $ocLazyLoad, $injector, " +
            "$timeout, DataService, $q, SharedConstantsService, SearchResultsProcessorService) { return ";
        componentScript +=  getFunctions(libraryDocuments);
        componentScript += '\n }';
        componentScript += " ]);";


    } else {
        throw new Error("Component library not found");
    }

    return componentScript;
};

function getComponentLibraryScriptServiceName (serviceName){
    return lodashString.camelCase(serviceName) + "Service";
}

module.exports = {
    loadComponent: loadComponent,

    getComponentDirectiveScript: getComponentDirectiveScript,

    getComponentLibraryServiceScript: getComponentLibraryServiceScript,

    getComponentLibraryScriptServiceName: getComponentLibraryScriptServiceName
};
