

/**
*   @description   "FormComponent" is a Portal form base component.
*   @inputs        componentLabel, 
*                  componentPath, 
*                  businesAccount, 
*                  userAccount, 
*                  loan, 
*                  deposit, 
*                  dataMask, 
*
*   @author       Robert Bloh
*/
function FormComponent(
    componentLabel, 
    componentPath,
    userObject,
    businessAccount,
    userAccount,
    loan,
    deposit
) {

    /**
     * Debug settings
     * @type {Boolean}
     */
    this.enableDebug = true;

    /**
     * Tab 
     * @type {String}
     */
    this.tab;

    /**
     * Component Label
     * @type {String}
     */
    this.componentLabel = componentLabel;

    /**
     * Component Path
     * @type {String}
     */
    this.componentPath = componentPath;

    /**
     * Associated User object
     * @type {Object}
     */
    this.userObject = userObject;

    /**
     * Associated Business Account
     * @type {Object}
     */
    this.businessAccount = businessAccount;

    /**
     * Associated User Account
     * @type {Object}
     */
    this.userAccount = userAccount;

	/**
     * Associated Loan
     * @type {Object}
     */
    this.loan = loan;

    /**
     * Associated Deposit
     * @type {Object}
     */
    this.deposit = deposit;

    /**
     * Component Data Properties
     * @type {String}
     */

    this.dataMask = '';
    this.dataIcon = '';
    this.dataReadOnly = '';
    this.dataDisabled = '';
    this.levelOverride = '';
    this.copyToPath = '';

    /**
     * Component Date Properties
     * @type {String}
     */

    this.dateFormat = '';
    this.dateStart = '';
    this.dateEnd = '';
    this.dateTodayButton = '';
    this.dateAutoClose = '';

    /**
     * Associated Service
     * @type {Object}
     */
    this.service = InfoService;

    /**
     * Attribute used for component path
     * @type {String}
     */
    this.pathAttribute = 'path';

    /**
     * Save on Navigation Enabled indicator
     * @type {Boolean}
     */
    this.saveOnNavigationEnabled = true;

    /**
     * Save on Blur Enabled indicator
     * @type {Boolean}
     */
    this.saveOnBlurEnabled = true;

    /**
     * Admin or setup indicator
     * @type {Boolean}
     */
    this.enableAdmin = true;


    /**
     * If we should attempt to display debug information.
     * @param {string} type     type of debug to do
     * @param {object} obj      an object or string to output
     * @param {array} tableCols An array used when rendering a table to select what fields to display
     * @return {void}
     */
    this.debug = function (type, obj, tableCols) {
        // allow Errors to "punch" through even if debug is disabled.
        if (this.enableDebug || type === 'error') {
            try {
                switch(type) {
                    case 'start':
                        console.group(obj);
                        break;
                    case 'end':
                        console.groupEnd();
                        break;
                    case 'log':
                        console.log(obj);
                        break;
                    case 'info':
                        console.info(obj);
                        break;
                    case 'error':
                        console.error(obj);
                        break;
                    case 'warn':
                        console.warn(obj);
                        break;
                    case 'dir':
                        console.dir(obj);
                        break;
                    case 'trace':
                        console.trace();
                        break;
                    case 'table':
                        try {
                            console.table(obj, tableCols);
                        } catch (e1) {
                            // if Table not supported output standard object notation.
                            console.dir(obj);
                        }
                        break;
                    case 'debugger':
                        // force a break point
                        console.debugger();
                        break;
                    default:
                        console.log(type);
                        break;
                }
            } catch (e) {
                // fail silently....
            }
        }
    };

 	/**
    *   @description    Set Tab.
    *   @input          tab
    *   @outputs        none
    */
    this.setTab = function(tab) {
        this.tab = tab;

        return this;
    }

    /**
    *   @description    Get Tab.
    *   @input          none
    *   @outputs        tab
    */
    this.getTab = function() {
        return this.tab;
    }    

    /**
    *   @description    Set Component label.
    *   @input          componentLabel
    *   @outputs        none
    */
    this.setComponentLabel = function(componentLabel) {
        this.componentLabel = componentLabel;

        return this;
    }

    /**
    *   @description    Get Component label.
    *   @input          none
    *   @outputs        componentLabel
    */
    this.getComponentLabel = function() {
        return this.componentLabel;
    }

    /**
    *   @description    Set Component path.
    *   @input          componentPath
    *   @outputs        none
    */
    this.setComponentPath = function(componentPath) {
        this.componentPath = componentPath;

        return this;
    }

    /**
    *   @description    Get Component path.
    *   @input          none
    *   @outputs        componentPath
    */
    this.getComponentPath = function() {
        return this.componentPath;
    }

    /**
    *   @description    Set Component Data Mask.
    *   @input          dataMask
    *   @outputs        none
    */
    this.setDataMask = function(dataMask) {
        this.dataMask = dataMask;

        return this;
    }

    /**
    *   @description    Get Component Data Mask.
    *   @input          none
    *   @outputs        dataMask
    */
    this.getDataMask = function() {
        return this.dataMask;
    }

    /**
    *   @description    Set Component Data ReadOnly.
    *   @input          dataReadOnly
    *   @outputs        none
    */
    this.setDataReadOnly = function(dataReadOnly) {
        this.dataReadOnly = dataReadOnly;

        return this;
    }

    /**
    *   @description    Get Component Data ReadOnly.
    *   @input          none
    *   @outputs        dataReadOnly
    */
    this.getDataReadOnly = function() {
        return this.dataReadOnly;
    }

    /**
    *   @description    Set Component Data Disabled.
    *   @input          dataDisabled
    *   @outputs        none
    */
    this.setDataDisabled = function(dataDisabled) {
        this.dataDisabled = dataDisabled;

        return this;
    }

    /**
    *   @description    Get Component Data Disabled.
    *   @input          none
    *   @outputs        dataDisabled
    */
    this.getDataDisabled = function() {
        return this.dataDisabled;
    }

    /**
    *   @description    Set Business Account.
    *   @input          businessAccount
    *   @outputs        none
    */
    this.setBusinessAccount = function(businessAccount) {
        this.businessAccount = businessAccount;

        return this;
    }

    /**
    *   @description    Get Business Account.
    *   @input          none
    *   @outputs        businessAccount
    */
    this.getBusinessAccount = function() {
        return this.businessAccount;
    }

    /**
    *   @description    Set User Object.
    *   @input          userObject
    *   @outputs        none
    */
    this.setUserObject = function(userObject) {
        this.userObject = userObject;
        return this;
    }

    /**
    *   @description    Get User Object.
    *   @input          none
    *   @outputs        userObject
    */
    this.getUserObject = function() {
        return this.userObject;
    }

    /**
    *   @description    Set User Account.
    *   @input          userAccount
    *   @outputs        none
    */
    this.setUserAccount = function(userAccount) {
        this.userAccount = userAccount;

        return this;
    }

    /**
    *   @description    Get User Account.
    *   @input          none
    *   @outputs        userAccount
    */
    this.getUserAccount = function() {
        return this.userAccount;
    }

    /**
    *   @description    Set Loan.
    *   @input          loan
    *   @outputs        none
    */
    this.setLoan = function(loan) {
        this.loan = loan;

        return this;
    }

    /**
    *   @description    Get Loan.
    *   @input          none
    *   @outputs        loan
    */
    this.getLoan = function() {
        return this.loan;
    }

    /**
    *   @description    Set Deposit.
    *   @input          deposit
    *   @outputs        none
    */
    this.setDeposit = function(deposit) {
        this.deposit = deposit;

        return this;
    }

    /**
    *   @description    Get Deposit.
    *   @input          none
    *   @outputs        deposit
    */
    this.getDeposit = function() {
        return this.deposit;
    }

    /**
    *   @description    Set Service.
    *   @input          service
    *   @outputs        none
    */
    this.setService = function(service) {
        this.service = service;

        return this;
    }

    /**
    *   @description    Get Service.
    *   @input          none
    *   @outputs        service
    */
    this.getService = function() {
        return this.service;
    }

    /**
    *   @description    Set Path attribute.
    *   @input          pathAttribute
    *   @outputs        none
    */
    this.setPathAttribute = function(pathAttribute) {
        this.pathAttribute = pathAttribute;

        return this;
    }

    /**
    *   @description    Get Path attribute.
    *   @input          none
    *   @outputs        pathAttribute
    */
    this.getPathAttribute = function() {
        return this.pathAttribute;
    }

    /**
    *   @description    Initialize the FormComponent instance.
    *   @input          none
    *   @outputs        none
    */
    this.init = function() {

        this.debug('start', 'FormComponent.init');

        this.renderComponent()

        this.initEvents();

        this.debug('end');

        return this;
    }

    /**
    *   @description    Render the Component by injecting markup into the associated container.
    *   @input          none
    *   @outputs        none
    */
    this.renderComponent = function() {

        this.debug('start', 'FormComponent.renderComponent');
        
        this.debug('end');

    }
    
    /**
    *   @description    Set the Component data into the DOM Element.
    *   @input          none
    *   @outputs        none
    */
    this.setComponentData = function() {

        this.debug('start', 'FormComponent.setComponentData');

        this.debug('end');

    }

    /**
    *   @description    Get the Component data from the DOM Element.
    *   @input          element data
    *   @outputs        none
    */
    this.getComponentData = function() {

        this.debug('start', 'FormComponent.getComponentData');

        this.debug('end');

    }

    /**
    *   @description    Save the Component data using the Service.
    *   @input          element data
    *   @outputs        none
    */
    this.saveComponentData = function() {

        this.debug('start', 'FormComponent.saveComponentData');

        // Extract Component Model
        var componentModel = this.getComponentData();  

        // Save Component Model
        this.saveModel(componentModel, this.getService());

        this.debug('end');

    }

    /**
    *   @description    Query the Form models, constrained by the specified filter, using the Service.
    *   @input          filter, service
    *   @outputs        model
    */
    this.queryModels = function(filter, service) {

        this.debug('start', 'FormComponent.queryModels');
        
        var service = service || InfoService;

        service.queryList(filter, null, null, this.queryModelsCallback);

        this.debug('end');

    }

    this.queryModelsCallback = function(frameworkData) {

        this.debug('start', 'FormComponent.queryModelsCallback');
        
        this.debug('end');

    }

    /**
    *   @description    Converts the json list back to app matrix style for saving.
    *   @input          json values list
    *   @outputs        none
    */
    this.convertToMatrixSaveToAppData = function(valuesList) {

		this.debug('start', 'FormComponent.convertToMatrix');
        var matrixValuesList = [];
		
		$.each(valuesList, function(key,obj) {
			matrixValuesList.push({
				name       : obj.field.metaInfo.name,
				value      : obj.field.value,
				isComplete : obj.field.isCompleted,
				isRequired : obj.field.metaInfo.requirementType
			});
			
		});//End of each

		//Here we make the call to cp2_controller to save to the application data old matrix framework as well.
		CP2_Controller.upsertAppData(matrixValuesList, this.getLoan().id, this.getUserAccount().id, this.getBusinessAccount().id, this.getUserObject().contact.id, function(results, status) {
			
			if (status.status) {
				console.log('success');
			} else if (status.type === 'exception') {
				// error
				console.log('error' + status);
			} else {
				// error
				console.log('error' +  status);
			}
		});

		return matrixValuesList;
        this.debug('end');
    }


    /**
    *   @description    Save the specified Form model using the Service.
    *   @input          model, service
    *   @outputs        callback
    */
    this.saveModel = function(model, service) {

        this.debug('start', 'FormComponent.saveModel');
        
        var service = service || InfoService;
        
        var modelJson = JSON.stringify(model);
        service.saveInstance(modelJson, this.saveModelCallback);

        //Here we need to convert to matrix style and save to app map objects as well.
        var modelArray = []
        modelArray.push(model);
        this.convertToMatrixSaveToAppData(modelArray);
        this.debug('end');

    }

    this.saveModelCallback = function() {

        this.debug('start', 'FormComponent.saveModelCallback');
        this.debug('end');

    }

    /**
    *   @description    Save the Form model list using the Service.
    *   @input          modelList, service
    *   @outputs        callback
    */
    this.saveModelList = function(modelList, service) {

        this.debug('start', 'FormComponent.saveModelList');
        
        var service = service || InfoService;
        
        var modelListJson = JSON.stringify(modelList);
        service.saveList(modelListJson, this.saveModelListCallback);

        //ToDo translate to model list.

        this.debug('end');

    }

    this.saveModelListCallback = function() {

        this.debug('start', 'FormComponent.saveModelListCallback');
        
        this.debug('end');

    }

    this.adjustIfBusinessField = function(model) {

        // Adjust Business Field(s)
        var path = model.field.metaInfo.path;
        var businessPath = '/Business/';
        if (path && (path.toLowerCase().indexOf(businessPath.toLowerCase()) > 0)) {

            // Remove User Account Relationship
            delete model.userAccount;
        }

    }

    /**
    *   @description    Lookup the Form model specified by the MetaInfo path.
    *   @input          none
    *   @outputs        model
    */
    this.lookupModel = function() {

        this.debug('start', 'FormComponent.lookupModel');
        
        var modelMap = this.getService().getModelMap();

        var metaInfoPath = this.getComponentPath();

        var model;

        // Lookup existing Model
        for (var id in modelMap) {
            var currentModel = modelMap[id];

            // Inspect MetaInfo path for match
            var path = currentModel.field.metaInfo.path;
            if (path && (path === metaInfoPath)) {
                model = currentModel;
                break;
            }
        };

        if (model === undefined) {

            // Create a new Model
            model = this.createNewModel(metaInfoPath);
            this.setFieldsOnModel(model, '', false);
        }
        
        this.debug('end');

        return model;
    }  


    this.createNewModel = function(metaInfoPath) {

        var metaInfo = { path: metaInfoPath };
        var field    = { metaInfo: metaInfo };
        var info     = { field: field }; 

        if (this.getBusinessAccount()) info.businessAccount = this.getBusinessAccount();
        if (this.getUserAccount()) info.userAccount = this.getUserAccount();
        if (this.getLoan()) info.loan = this.getLoan();
        if (this.getDeposit()) info.deposit = this.getDeposit();

        return info;
    }

    this.setFieldsOnModel = function(model, value, isCompleted) {

        model.field.value = value;
        model.field.isCompleted = isCompleted;

        return model;
    }

    this.getNameFromPath = function(path) {
        var name = path;

        var separatorIndex = path.lastIndexOf('/');
        if (separatorIndex >= 0) {
            if (separatorIndex < (path.length - 1)) {
                name = path.substring(separatorIndex + 1);
            } else {
                name = '';
            }
        }

        return name;
    }


    /**
    *   @description    Initialize the FormComponent eventing.
    *   @input          none
    *   @outputs        none
    */
    this.initEvents = function() {

        this.debug('start', 'FormComponent.initEvents');

        var self = this;
        var componentElement;

        // UI Event: Input blur.action
        componentElement = $('[' + this.getPathAttribute() + '="' + this.getComponentPath() + '"]');
        var inputElement = componentElement.find('input');
        inputElement.off('blur.action');
        inputElement.on('blur.action', 
            function(event) {
                // If Save On Blur Enabled
                if (self.saveOnBlurEnabled) {
                    self.onComponentBlur.call(self, event);
                }
            }
        );

        // UI Event: TextArea blur.action
        componentElement = $('[' + this.getPathAttribute() + '="' + this.getComponentPath() + '"]');
        var textAreaElement = componentElement.find('textarea');
        textAreaElement.off('blur.action');
        textAreaElement.on('blur.action', 
            function(event) {
                // If Save On Blur Enabled
                if (self.saveOnBlurEnabled) {
                    self.onComponentBlur.call(self, event);
                }
            }
        );

        // UI Event: select.action
        componentElement = $('[' + this.getPathAttribute() + '="' + this.getComponentPath() + '"]');
        var selectElement = componentElement.find('select');
        selectElement.off('change.action');
        selectElement.on('change.action', 
            function(event) {
                self.onSelectChange.call(self, event);
            }
        );

        // Event: query.list.finished
        var queryListFinishedEvent = 'query.list.finished';
        $('body').on(queryListFinishedEvent + '.action', 
            function(event, serviceName) {
                if (serviceName === 'InfoService') {
                    self.onInfoServiceQueryFinished.call(self, event, serviceName);
                }
            }
        );

        // Event: service.exception
        var serviceExceptionEvent = 'service.exception';
        $('body').on(serviceExceptionEvent + '.action', 
            function(event, serviceName) {
                self.onServiceException.call(self, event, serviceName);
            }
        );
        
        this.debug('end');

    }

    /**
    *   @description    Handler for Component blur event.
    *   @input          event
    *   @outputs        none
    */
    this.onComponentBlur = function (event) {

        this.debug('start', 'FormComponent.onComponentBlur');

        console.log('Blur Component: ' + this.getComponentPath());

        this.saveComponentData();

        this.debug('end');

    }

    /**
    *   @description    Handler for Component select change event.
    *   @input          event
    *   @outputs        none
    */
    this.onSelectChange = function (event) {

        this.debug('start', 'FormComponent.onSelectChange');

        console.log('Select Component: ' + this.getComponentPath());

        this.saveComponentData();

        this.debug('end');

    }

    /**
    *   @description    Handler for InfoService query list finished event.
    *   @input          event, serviceName, componentName
    *   @outputs        none
    */
    this.onInfoServiceQueryFinished = function (event, serviceName, componentName) {
        this.debug('start', 'FormComponent.onInfoServiceQueryFinished');
        this.setComponentData();
        this.debug('end');
    }


   
    /**
    *   @description    Handler for Service exception event.
    *   @input          none
    *   @outputs        none
    */
    this.onServiceException = function (event, serviceName) {

        this.debug('start', 'FormComponent.onServiceException');

        this.debug('end');

    }

}


/**
*   @description   "TileComponent" is a Portal form tile component.
*   @inputs        componentLabel, 
*                  componentPath, 
*                  businesAccount, 
*                  userAccount, 
*                  loan, 
*                  deposit, 
*
*   @author       Robert Bloh
*/
function TileComponent(
    componentLabel, 
    componentPath,
    userObject,
    businessAccount,
    userAccount,
    loan,
    deposit
) {

    // Call superclass
    FormComponent.call(this, componentLabel, componentPath, userObject, businessAccount, userAccount, loan, deposit);

    /**
     * Tile Components Map
     * @type {Map}
     */
    this.components = {};

    /**
    *   @description    Set Tile Components.
    *   @input          components
    *   @outputs        none
    */
    this.setComponents = function(components) {
        this.components = components;

        return this;
    }

    /**
    *   @description    Get Tile Components.
    *   @input          none
    *   @outputs        components
    */
    this.getComponents = function() {
        return this.components;
    }


    /**
    *   @description    Add the Form Component to the Tile field map.
    *   @input          component
    *   @outputs        none
    */
    this.addComponent = function(component) {
        var componentPath = component.getComponentPath();
        this.getComponents()[componentPath] = component;

        // Register Tile Portal Information with Component
        if (this.getUserObject()) component.setUserObject(userObject);
        if (this.getBusinessAccount()) component.setBusinessAccount(businessAccount);
        if (this.getUserAccount()) component.setUserAccount(userAccount);
        if (this.getLoan()) component.setLoan(loan);
        if (this.getDeposit()) component.setDeposit(deposit);

        return this;
    }

    /**
    *   @description    Remove the Form Component from the Tile field map.
    *   @input          component
    *   @outputs        none
    */
    this.removeComponent = function(component) {
        var componentPath = component.getComponentPath();
        delete this.getComponents()[componentPath];

        return this;
    }

    /**
    *   @description    Initialize the FormComponent eventing.
    *   @input          none
    *   @outputs        none
    */
    this.initEvents = function() {

        this.debug('start', 'TileComponent.initEvents');

        var self = this;

        // Event: tile.query.components
        var tileQueryComponentsEvent = 'tile.query.components';
        $('body').on(tileQueryComponentsEvent + '.action', 
            function(event, tileName) {
                self.onQueryComponents.call(self, event, tileName);
            }
        );
        
        // Event: tile.save.components
        var tileSaveComponentsEvent = 'tile.save.components';
        $('body').on(tileSaveComponentsEvent + '.action', 
            function(event, tileName) {
                self.onSaveComponents.call(self, event, tileName);
            }
        );


        // Event: query.list.finished
        var queryListFinishedEvent = 'query.list.finished';
        $('body').on(queryListFinishedEvent + '.action', 
            function(event, serviceName) {
                if (serviceName === 'InfoService') {
                    self.onInfoServiceQueryFinished.call(self, event, serviceName);
                }
            }
        );
        
        // Event: save.instance.finished
        var saveInstanceFinishedEvent = 'save.instance.finished';
        $('body').on(saveInstanceFinishedEvent + '.action', 
            function(event, serviceName) {
                if (serviceName === 'InfoService') {
                    self.onInfoServiceSaveFinished.call(self, event, serviceName);
                }
            }
        );
        
        // Event: save.list.finished
        var saveListFinishedEvent = 'save.list.finished';
        $('body').on(saveListFinishedEvent + '.action', 
            function(event, serviceName) {
                if (serviceName === 'InfoService') {
                    self.onInfoServiceSaveFinished.call(self, event, serviceName);
                }
            }
        );

        this.debug('end');

    }

    /**
    *   @description    Handler for Tile Query Components.
    *   @input          event, tileName
    *   @outputs        none
    */
    this.onQueryComponents = function(event, tileName) {

        this.debug('start', 'TileComponent.onQueryComponents');

        var self = this;

        this.queryComponents();

        this.debug('end');

    }

     /**
    *   @description    Handler for InfoService query list finished event.
    *   @input          event, serviceName, componentName
    *   @outputs        none
    */
    this.onInfoServiceQueryFinished = function (event, serviceName, componentName) {
        this.debug('start', 'TileComponent.onInfoServiceQueryFinished');
        this.setComponentData();
        this.setBadging();
        this.debug('end');
    }



    /**
    *   @description    Handler for InfoService save instance or list finished event.
    *   @input          event, serviceName, componentName
    *   @outputs        none
    */
    this.onInfoServiceSaveFinished = function (event, serviceName, componentName) {
        this.debug('start', 'FormComponent.onInfoServiceSaveFinished');
        this.setBadging();
        this.debug('end');
   	}


    /**
    *   @description    Handler for Tile Save Components.
    *   @input          event, tileName
    *   @outputs        none
    */
    this.onSaveComponents = function(event, tileName) {

        this.debug('start', 'TileComponent.onSaveComponents');

        var self = this;

        this.saveComponents();

        this.debug('end');

    }

    /**
    *   @description    Query the Tile Field Components using the InfoService.
    *   @input          none
    *   @outputs        callback
    */
    this.queryComponents = function() {

        this.debug('start', 'TileComponent.queryComponents');

        var self = this;

        var service = InfoService;

        var userFieldsFilter = '[' +
            '{"filterBy":"Loan.Id","filterOperation":"=","filterExpression":"\'' + this.getLoan().id + '\'"},' +
            '{"filterBy":"BusinessAccount.Id","filterOperation":"=","filterExpression":"\'' + this.getBusinessAccount().id + '\'"},' + 
            '{"filterBy":"UserAccount.Id","filterOperation":"=","filterExpression":"\'' + this.getUserAccount().id + '\'"}' + 
            ']';
        var businessFieldsFilter = '[' +
            '{"filterBy":"Loan.Id","filterOperation":"=","filterExpression":"\'' + this.getLoan().id + '\'"},' +
            '{"filterBy":"BusinessAccount.Id","filterOperation":"=","filterExpression":"\'' + this.getBusinessAccount().id + '\'"},' + 
            '{"filterBy":"UserAccount.Id","filterOperation":"=","filterExpression":"null"}' + 
            ']';

        // Query Tile Field Components
        service.queryList(userFieldsFilter, null, null, this.queryComponentsCallback);
        service.queryList(businessFieldsFilter, null, null, this.queryComponentsCallback);

        this.debug('end');

    }

    this.queryComponentsCallback = function() {

        this.debug('start', 'TileComponent.queryComponentsCallback');

        var self = this;
        this.debug('end');

    }

    /**
    *   @description    Save the Tile Field Components using the Service.
    *   @input          modelList, service
    *   @outputs        callback
    */
    this.saveComponents = function() {

        this.debug('start', 'TileComponent.saveComponents');

        var self = this;

        var service = InfoService;
        
        // Gather Tile Field Component Models
        var modelList = [];
        for (var componentPath in this.getComponents()) {
            var component = this.getComponents()[componentPath];

            var model = component.getComponentData();
            if (model && (model != null)) {
                modelList.push(model);
            }
        }

        // Save Tile Field Component Model List
        var modelListJson = JSON.stringify(modelList);
        service.saveList(modelListJson, this.saveComponentsCallback);

        this.debug('end');

    }

    this.saveComponentsCallback = function() {

        this.debug('start', 'TileComponent.saveComponentsCallback');

        var self = this;

        this.debug('end');

    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////
    // @Description : This method is called after onInfoServiceSaveFinished on the tile component. Will
    //                get all tabs from every component on page & call setBadgingOnTab method to display
    //                badge count on each appropriate tab DOM element.
    // @Parameter   : None
    // @Returns     : None
    // @Author      : bF@lk
    /////////////////////////////////////////////////////////////////////////////////////////////////////
    this.setBadging = function () {
    	
    	//Variables for method
    	var tabArray = [];
		var componentTab;

		//Loop through each component and get tab
		for (var componentPath in this.getComponents()) {

			//Get component tab
            componentTab = this.getComponents()[componentPath].getTab();

            //Add the tab to array if not in there.
            if (tabArray.indexOf(componentTab) < 0) {
            	tabArray.push(componentTab);
            }

         }//End of loop through each component

    	//Loop through the tab array and call badging for each tab.
    	for (var i = 0; i < tabArray.length; i++) {
		    this.setBadgingOnTab(tabArray[i]);
		}//End of loop through all tabs on tab array.

    }


    /////////////////////////////////////////////////////////////////////////////////////////////////////
    // @Description : Sets badging on the tab. This will be called from the tab component or from the set
    //                badging method while iterating over every tab from setBadging method.
    // @Parameter   : tabName - The tab that we want to set badging on.
    // @Returns     : None
    // @Author      : bF@lk
    /////////////////////////////////////////////////////////////////////////////////////////////////////
    this.setBadgingOnTab = function (tabName) {
    	console.log('in set bading on tab : ' + tabName);
    	//Variables used throughout method
    	var modelMap   = this.getService().getModelMap();
	 	var badgeCount = 0;

    	//Iterate over model map anything noted as required and not completed should increment badge count. We need the concept of a tab here too..
    	$.each(this.getComponents(), function(key,component) {
    		
    		//wont work until we have getmodelmap indexed by path
    		if (component.getTab() == tabName) {
    		
    			//This returns the model based on the component path.
    			var model = component.lookupModel();
    			console.log('the modellll');
    			console.log(model);
    			//If the meta info for the field is required and the field is not completed we count it.
				if (model.field.metaInfo.requirementType == "True" && model.field.isCompleted == false) {
					badgeCount++;
				}
    		}//End if the component tab matches the tab name sent into method
		});//End of each
    	
    	//Now we add necessary classes to the DOM with badge count.
    	$('a[href="#'+ tabName +'"]').parent('li').find('span.dev-badge-container').html('<i class="fa fa-circle fa-stack-2x tag-red"></i><i class="number fa-stack-1x"> ' + badgeCount + '</i>');
    }

}


/**
*   @description   "TextComponent" is a Portal form text component.
*   @inputs        componentLabel, 
*                  componentPath, 
*                  businesAccount, 
*                  userAccount, 
*                  loan, 
*                  deposit, 
*
*   @author       Robert Bloh
*/
function TextComponent(
    componentLabel, 
    componentPath,
    userObject,
    businessAccount,
    userAccount,
    loan,
    deposit
) {

    // Call superclass
    FormComponent.call(this, componentLabel, componentPath, userObject, businessAccount, userAccount, loan, deposit);

    /**
    *   @description    Render the Component by injecting markup into the associated container.
    *   @input          none
    *   @outputs        none
    */
    this.renderComponent = function() {

        this.debug('start', 'TextComponent.renderComponent');
        
        this.debug('info', 'Path: ' + this.getComponentPath());

        var self = this;

        var componentElement = $('[' + this.getPathAttribute() + '="' + this.getComponentPath() + '"]');

        var componentName = this.getNameFromPath(this.getComponentPath());

        // Generate Component Markup
        var componentMarkup = '';
        componentMarkup += '<div class="portal-field" ' + this.getPathAttribute() + '="' + this.getComponentPath() + '" >' + '\n';
        componentMarkup += '<label>' + this.getComponentLabel() + '</label>' + '\n';
        componentMarkup += '<input type="text"';
        componentMarkup += ' class=""';
        componentMarkup += ' value=""';
        componentMarkup += ' id="' + componentName + '"';
        componentMarkup += ' name="' + componentName + '"';
        componentMarkup += ' copytoname="' + this.copyToPath + '"';

        if (this.dataReadOnly) componentMarkup += ' readonly="' + this.dataReadOnly + '"';
        if (this.dataDisabled) componentMarkup += ' disabled="' + this.dataDisabled + '"';

//        componentMarkup += ' data-dateformat="' + this.dateFormat + '"';
//        componentMarkup += ' data-datestart="' + this.dateStart + '"';
//        componentMarkup += ' data-dateend="' + this.dateEnd + '"';
//        componentMarkup += ' data-datetodaybtn="' + this.dateTodayButton + '"';
//        componentMarkup += ' data-dateautoclose="' + this.dateAutoClose + '"';

        componentMarkup += ' />' + '\n';
        componentMarkup += '</div>' + '\n';

        // Append Component Markup
        componentElement.replaceWith(componentMarkup);

        // Setup Data Masking
        componentElement = $('[' + this.getPathAttribute() + '="' + this.getComponentPath() + '"]');
        var inputElement = componentElement.find('input');
        var dataMask = this.getDataMask();
        if ((inputElement.length > 0) && dataMask) {
            this.setupDataMasking(inputElement, dataMask);
        }

        this.debug('end');

    }
    
    /**
    *   @description    Setup the Input Element Masking.
    *   @input          none
    *   @outputs        none
    */
    this.setupDataMasking = function(fieldElement, maskName) {

        this.debug('start', 'TextComponent.setupDataMasking');

        var maskName = maskName.toLowerCase();

        if (maskName === 'money') {
            fieldElement.maskMoney(
                {
                    precision: 0,
                    allowZero: true
                }
            );
        } else if(maskName === 'cents'){
            fieldElement.maskMoney(
                {
                    precision: 2,
                    allowZero: true
                }
            );
        } else if (maskName === 'number') {
            fieldElement.maskMoney(
                {
                    precision: 0,
                    allowZero: true
                }
            );
        } else if (maskName === 'year') {
            fieldElement.maskMoney(
                {
                    precision: 0,
                    allowZero: true,
                    thousands: ''
                }
            );
        } else if (maskName === 'decimal') {
            fieldElement.maskMoney(
                {
                    precision: 3,
                    allowZero: true
                }
            );
        } else if (maskName === 'ssn') {
            fieldElement.inputmask('999-99-9999');

        } else if (maskName === 'phone') {
            fieldElement.inputmask('(999) 999-9999');

        } else if (maskName === 'zip') {
            fieldElement.inputmask('99999 - 9999', { placeholder : ' ' });
        } else if (maskName === 'percent') {
            fieldElement.maskMoney(
                {
                    precision: 0,
                    allowZero: true
                }
            );
        } else if (maskName === 'year') {
            fieldElement.inputmask('9999', { placeholder : ' ' });
        } else if (maskName === 'taxid') {
            fieldElement.inputmask('999999999', { placeholder : ' ' });
        }

        this.debug('end');

    }

    /**
    *   @description    Set the Component data into the DOM Element.
    *   @input          none
    *   @outputs        none
    */
    this.setComponentData = function() {

        this.debug('start', 'TextComponent.setComponentData');

        var self = this;

        var componentModel = this.lookupModel();

        var componentElement = $('[' + this.getPathAttribute() + '="' + this.getComponentPath() + '"]');
        var inputElement = componentElement.find('input');
        if (inputElement.length > 0) {
            inputElement.val(componentModel.field.value);

            // Required Fields
            var requirementType = componentModel.field.metaInfo.requirementType;
            if (requirementType && (requirementType.toLowerCase() === 'true')) {
                inputElement.addClass('required'); 
            }
        }    

        this.debug('end');

    }

    /**
    *   @description    Get the Component data from the DOM Element.
    *   @input          none
    *   @outputs        componentModel
    */
    this.getComponentData = function() {

        this.debug('start', 'TextComponent.getComponentData');

        var self = this;

        var componentModel = this.lookupModel();

        var componentElement = $('[' + this.getPathAttribute() + '="' + this.getComponentPath() + '"]');
        var inputElement = componentElement.find('input');
        if (inputElement.length > 0) {

            var fieldValue = inputElement.val();
            var isCompleted = true;
            this.setFieldsOnModel(componentModel, fieldValue, isCompleted);

            this.adjustIfBusinessField(componentModel);
        }    

        this.debug('end');

        return componentModel;
    }

}

/**
*   @description   "TextAreaComponent" is a Portal form text area component.
*   @inputs        componentLabel, 
*                  componentPath, 
*                  businesAccount, 
*                  userAccount, 
*                  loan, 
*                  deposit, 
*
*   @author       Robert Bloh
*/
function TextAreaComponent(
    componentLabel, 
    componentPath,
    userObject,
    businessAccount,
    userAccount,
    loan,
    deposit
) {

    // Call superclass
    FormComponent.call(this, componentLabel, componentPath, userObject, businessAccount, userAccount, loan, deposit);

    /**
    *   @description    Render the Component by injecting markup into the associated container.
    *   @input          none
    *   @outputs        none
    */
    this.renderComponent = function() {

        this.debug('start', 'TextAreaComponent.renderComponent');
        
        this.debug('info', 'Path: ' + this.getComponentPath());

        var self = this;

        var componentElement = $('[' + this.getPathAttribute() + '="' + this.getComponentPath() + '"]');

        var componentName = this.getNameFromPath(this.getComponentPath());

        // Generate Component Markup
        var componentMarkup = '';
        componentMarkup += '<div class="portal-field" ' + this.getPathAttribute() + '="' + this.getComponentPath() + '" >' + '\n';
        componentMarkup += '<label>' + this.getComponentLabel() + '</label>' + '\n';
        componentMarkup += '<textarea';
        componentMarkup += ' class=""';
        componentMarkup += ' rows="5"';
        componentMarkup += ' cols="50"';
        componentMarkup += ' maxlength="255"';
        componentMarkup += ' value=""';
        componentMarkup += ' id="' + componentName + '"';
        componentMarkup += ' name="' + componentName + '"';
        componentMarkup += ' copytoname="' + this.copyToPath + '"';

        if (this.dataReadOnly) componentMarkup += ' readonly="' + this.dataReadOnly + '"';
        if (this.dataDisabled) componentMarkup += ' disabled="' + this.dataDisabled + '"';

        componentMarkup += ' />' + '\n';
        componentMarkup += '</div>' + '\n';

        // Append Component Markup
        componentElement.replaceWith(componentMarkup);

        this.debug('end');

    }
    
    /**
    *   @description    Set the Component data into the DOM Element.
    *   @input          none
    *   @outputs        none
    */
    this.setComponentData = function() {

        this.debug('start', 'TextAreaComponent.setComponentData');

        var self = this;

        var componentModel = this.lookupModel();

        var componentElement = $('[' + this.getPathAttribute() + '="' + this.getComponentPath() + '"]');
        var inputElement = componentElement.find('textarea');
        if (inputElement.length > 0) {
            inputElement.val(componentModel.field.value);

            // Required Fields
            var requirementType = componentModel.field.metaInfo.requirementType;
            if (requirementType && (requirementType.toLowerCase() === 'true')) {
                inputElement.addClass('required'); 
            }
        }    

        this.debug('end');

    }

    /**
    *   @description    Get the Component data from the DOM Element.
    *   @input          none
    *   @outputs        componentModel
    */
    this.getComponentData = function() {

        this.debug('start', 'TextAreaComponent.getComponentData');

        var self = this;

        var componentModel = this.lookupModel();

        var componentElement = $('[' + this.getPathAttribute() + '="' + this.getComponentPath() + '"]');
        var inputElement = componentElement.find('textarea');
        if (inputElement.length > 0) {

            var fieldValue = inputElement.val();
            var isCompleted = true;
            this.setFieldsOnModel(componentModel, fieldValue, isCompleted);

            this.adjustIfBusinessField(componentModel);
        }    

        this.debug('end');

        return componentModel;
    }

}


/**
*   @description   "CheckboxComponent" is a Portal form checkbox component.
*   @inputs        componentLabel, 
*                  componentPath, 
*                  businesAccount, 
*                  userAccount, 
*                  loan, 
*                  deposit, 
*
*   @author       Robert Bloh
*/
function CheckboxComponent(
    componentLabel, 
    componentPath,
    userObject,
    businessAccount,
    userAccount,
    loan,
    deposit
) {

    // Call superclass
    FormComponent.call(this, componentLabel, componentPath, userObject, businessAccount, userAccount, loan, deposit);

    /**
    *   @description    Render the Component by injecting markup into the associated container.
    *   @input          none
    *   @outputs        none
    */
    this.renderComponent = function() {

        this.debug('start', 'CheckboxComponent.renderComponent');
        
        this.debug('info', 'Path: ' + this.getComponentPath());

        var self = this;

        var componentElement = $('[' + this.getPathAttribute() + '="' + this.getComponentPath() + '"]');

        var componentName = this.getNameFromPath(this.getComponentPath());

        // Generate Component Markup
        var componentMarkup = '';
        componentMarkup += '<div class="portal-field" ' + this.getPathAttribute() + '="' + this.getComponentPath() + '" >' + '\n';
        componentMarkup += '<label>' + this.getComponentLabel() + '</label>' + '\n';
        componentMarkup += '<input type="checkbox"';
        componentMarkup += ' class=""';
        componentMarkup += ' id="' + componentName + '"';
        componentMarkup += ' name="' + componentName + '"';
        componentMarkup += ' copytoname="' + this.copyToPath + '"';

        if (this.dataReadOnly) componentMarkup += ' readonly="' + this.dataReadOnly + '"';
        if (this.dataDisabled) componentMarkup += ' disabled="' + this.dataDisabled + '"';

        componentMarkup += ' />' + '\n';
        componentMarkup += '</div>' + '\n';

        // Append Component Markup
        componentElement.replaceWith(componentMarkup);

        this.debug('end');

    }
    
    /**
    *   @description    Set the Component data into the DOM Element.
    *   @input          none
    *   @outputs        none
    */
    this.setComponentData = function() {

        this.debug('start', 'CheckboxComponent.setComponentData');

        var self = this;

        var componentModel = this.lookupModel();

        var componentElement = $('[' + this.getPathAttribute() + '="' + this.getComponentPath() + '"]');
        var inputElement = componentElement.find('input');
        if (inputElement.length > 0) {
            var isChecked = false;
            if (componentModel.field.value && (componentModel.field.value.toLowerCase() === 'true')) {
                isChecked = true;
            }
            inputElement.prop('checked', isChecked);

            // Required Fields
            var requirementType = componentModel.field.metaInfo.requirementType;
            if (requirementType && (requirementType.toLowerCase() === 'true')) {
                inputElement.addClass('required'); 
            }
        }    

        this.debug('end');

    }

    /**
    *   @description    Get the Component data from the DOM Element.
    *   @input          element data
    *   @outputs        none
    */
    this.getComponentData = function() {

        this.debug('start', 'CheckboxComponent.getComponentData');

        var self = this;

        var componentModel = this.lookupModel();

        var componentElement = $('[' + this.getPathAttribute() + '="' + this.getComponentPath() + '"]');
        var inputElement = componentElement.find('input');
        if (inputElement.length > 0) {
            
            var fieldValue = inputElement.prop('checked');
            var isCompleted = true;
            this.setFieldsOnModel(componentModel, fieldValue, isCompleted);

            this.adjustIfBusinessField(componentModel);
        }    

        this.debug('end');

        return componentModel;
    }

}


/**
*   @description   "ToggleComponent" is a Portal form toggle (Yes/No) component.
*   @inputs        componentLabel, 
*                  componentPath, 
*                  businesAccount, 
*                  userAccount, 
*                  loan, 
*                  deposit, 
*
*   @author       Robert Bloh
*/
function ToggleComponent(
    componentLabel, 
    componentPath,
    userObject,
    businessAccount,
    userAccount,
    loan,
    deposit
) {

    // Call superclass
    FormComponent.call(this, componentLabel, componentPath, userObject, businessAccount, userAccount, loan, deposit);

    /**
    *   @description    Render the Component by injecting markup into the associated container.
    *   @input          none
    *   @outputs        none
    */
    this.renderComponent = function() {

        this.debug('start', 'ToggleComponent.renderComponent');
        
        this.debug('info', 'Path: ' + this.getComponentPath());

        var self = this;

        var componentElement = $('[' + this.getPathAttribute() + '="' + this.getComponentPath() + '"]');

        var componentName = this.getNameFromPath(this.getComponentPath());

        // Generate Component Markup
        var componentMarkup = '';
        componentMarkup += '<div class="portal-field" ' + this.getPathAttribute() + '="' + this.getComponentPath() + '" >' + '\n';
        componentMarkup += '<label>' + this.getComponentLabel() + '</label>' + '\n';
        componentMarkup += '<ul>' + '\n';
        componentMarkup += '<li>' + '\n';
        componentMarkup += '<input type="radio"';
        componentMarkup += ' class="toggle"';
        componentMarkup += ' value="Yes"';
        componentMarkup += ' id="' + componentName + '-Yes' + '"';
        componentMarkup += ' name="' + componentName + '"';

        if (this.dataReadOnly) componentMarkup += ' readonly="' + this.dataReadOnly + '"';
        if (this.dataDisabled) componentMarkup += ' disabled="' + this.dataDisabled + '"';

        componentMarkup += ' />' + '\n';
        componentMarkup += '<label for="' + componentName + '-Yes' + '" >Yes</label>' + '\n';
        componentMarkup += '</li>' + '\n';
        componentMarkup += '<li>' + '\n';
        componentMarkup += '<input type="radio"';
        componentMarkup += ' class="toggle"';
        componentMarkup += ' value="No"';
        componentMarkup += ' id="' + componentName + '-No' + '"';
        componentMarkup += ' name="' + componentName + '"';

        if (this.dataReadOnly) componentMarkup += ' readonly="' + this.dataReadOnly + '"';
        if (this.dataDisabled) componentMarkup += ' disabled="' + this.dataDisabled + '"';

        componentMarkup += ' />' + '\n';
        componentMarkup += '<label for="' + componentName + '-No' + '" >No</label>' + '\n';
        componentMarkup += '</li>' + '\n';
        componentMarkup += '</ul>' + '\n';
        componentMarkup += '</div>' + '\n';

        // Append Component Markup
        componentElement.replaceWith(componentMarkup);

        this.debug('end');

    }
    
    /**
    *   @description    Set the Component data into the DOM Element.
    *   @input          none
    *   @outputs        none
    */
    this.setComponentData = function() {

        this.debug('start', 'ToggleComponent.setComponentData');

        var self = this;

        var componentModel = this.lookupModel();

        var componentElement = $('[' + this.getPathAttribute() + '="' + this.getComponentPath() + '"]');
        var toggleGroupElement = componentElement.find('ul');
        var yesElement = componentElement.find('input[value=Yes]');
        var noElement = componentElement.find('input[value=No]');
        if ((yesElement.length > 0) && (noElement.length > 0)) {
            if (componentModel.field.value && (componentModel.field.value.toLowerCase() === 'yes')) {
                yesElement.prop('checked', true);
                noElement.prop('checked', false);
            }
            if (componentModel.field.value && (componentModel.field.value.toLowerCase() === 'no')) {
                yesElement.prop('checked', false);
                noElement.prop('checked', true);
            }

            // Required Fields
            var requirementType = componentModel.field.metaInfo.requirementType;
            if (requirementType && (requirementType.toLowerCase() === 'true')) {
                toggleGroupElement.addClass('required'); 
            }
        }    

        this.debug('end');

    }

    /**
    *   @description    Get the Component data from the DOM Element.
    *   @input          element data
    *   @outputs        none
    */
    this.getComponentData = function() {

        this.debug('start', 'ToggleComponent.getComponentData');

        var self = this;

        var componentModel = this.lookupModel();

        var componentElement = $('[' + this.getPathAttribute() + '="' + this.getComponentPath() + '"]');
        var checkedInputElement = componentElement.find('input:checked');
        if (checkedInputElement.length > 0) {
            
            var fieldValue = checkedInputElement.val();
            var isCompleted = true;
            this.setFieldsOnModel(componentModel, fieldValue, isCompleted);

            this.adjustIfBusinessField(componentModel);
        }    

        this.debug('end');

        return componentModel;
    }

}


/**
*   @description   "SelectComponent" is a Portal form select component.
*   @inputs        componentLabel, 
*                  componentPath, 
*                  businesAccount, 
*                  userAccount, 
*                  loan, 
*                  deposit, 
*
*   @author       Robert Bloh
*/
function SelectComponent(
    componentLabel, 
    componentPath,
    userObject,
    businessAccount,
    userAccount,
    loan,
    deposit
) {

    // Call superclass
    FormComponent.call(this, componentLabel, componentPath, userObject, businessAccount, userAccount, loan, deposit);

    /**
     * Select Options
     * @type {Map}
     */
    this.options = {};

    /**
     * Currently Selected Option
     * @type {String}
     */
    this.selectedOption;

    /**
    *   @description    Set Select Options.
    *   @input          options
    *   @outputs        none
    */
    this.setOptions = function(options) {
        this.options = options;

        return this;
    }

    /**
    *   @description    Get Select Options.
    *   @input          none
    *   @outputs        options
    */
    this.getOptions = function() {
        return this.options;
    }

    /**
    *   @description    Set Selected Option.
    *   @input          selectedOption
    *   @outputs        none
    */
    this.setSelectedOption = function(selectedOption) {
        this.selectedOption = selectedOption;

        return this;
    }

    /**
    *   @description    Get Selected Option.
    *   @input          none
    *   @outputs        selectedOption
    */
    this.getSelectedOption = function() {
        return this.selectedOption;
    }

    /**
    *   @description    Render the Component by injecting markup into the associated container.
    *   @input          none
    *   @outputs        none
    */
    this.renderComponent = function() {

        this.debug('start', 'SelectComponent.renderComponent');
        
        this.debug('info', 'Path: ' + this.getComponentPath());

        var self = this;

        var componentElement = $('[' + this.getPathAttribute() + '="' + this.getComponentPath() + '"]');

        var componentName = this.getNameFromPath(this.getComponentPath());

        // Generate Component Markup
        var componentMarkup = '';
        componentMarkup += '<div class="portal-field" ' + this.getPathAttribute() + '="' + this.getComponentPath() + '" >' + '\n';
        componentMarkup += '<label>' + this.getComponentLabel() + '</label>' + '\n';
        componentMarkup += '<select';

        if (this.dataReadOnly) componentMarkup += ' readonly="' + this.dataReadOnly + '"';
        if (this.dataDisabled) componentMarkup += ' disabled="' + this.dataDisabled + '"';

        componentMarkup += ' >' + '\n';

        for (var optionValue in this.getOptions()) {
            var optionLabel = this.getOptions()[optionValue];

            componentMarkup += '<option value="' + optionValue + '"';
            if (optionValue === this.getSelectedOption()) {
                componentMarkup += 'selected';
            }
            componentMarkup += ' >';
            componentMarkup += optionLabel;
            componentMarkup += '</option>' + '\n';
        }

        componentMarkup += '</select>' + '\n';
        componentMarkup += '</div>' + '\n';

        // Append Component Markup
        componentElement.replaceWith(componentMarkup);

        this.debug('end');

    }
    
    /**
    *   @description    Set the Component data into the DOM Element.
    *   @input          none
    *   @outputs        none
    */
    this.setComponentData = function() {

        this.debug('start', 'SelectComponent.setComponentData');

        var self = this;

        var componentModel = this.lookupModel();

        var componentElement = $('[' + this.getPathAttribute() + '="' + this.getComponentPath() + '"]');
        var selectElement = componentElement.find('select');
        if (selectElement.length > 0) {
            if (componentModel.field.value) {
                selectElement.val(componentModel.field.value);
            }

            // Required Fields
            var requirementType = componentModel.field.metaInfo.requirementType;
            if (requirementType && (requirementType.toLowerCase() === 'true')) {
                selectElement.addClass('required'); 
            }
        }    

        this.debug('end');

    }

    /**
    *   @description    Get the Component data from the DOM Element.
    *   @input          element data
    *   @outputs        none
    */
    this.getComponentData = function() {

        this.debug('start', 'SelectComponent.getComponentData');

        var self = this;

        var componentModel = this.lookupModel();

        var componentElement = $('[' + this.getPathAttribute() + '="' + this.getComponentPath() + '"]');
        var selectElement = componentElement.find('select');
        if (selectElement.length > 0) {
            
            var fieldValue = selectElement.val();
            var isCompleted = true;
            this.setFieldsOnModel(componentModel, fieldValue, isCompleted);

            this.adjustIfBusinessField(componentModel);
        }    

        this.debug('end');

        return componentModel;
    }

}
