import {Injectable} from '@angular/core';
import {TreeNode} from 'angular2-tree-component';
import {MetadataEditorService} from '../shared/metadata-editor.service';
import {AppUtility} from '../shared/app.utility';
import {AppConstants} from '../shared/app.constants';
var _ = require('lodash');
import {template} from 'metadata-editor-repository';

@Injectable()

/*
* Service for managing the treeview data
*************************************************************/
export class ProjectManagerService {
    //Editor mapping schema - Contains the field information
    mappingSchema : any;

    //Editor virtual form schema - contains virtual grouping info for tree
    formSchema : any;
    
    constructor() {}

    /*
    * Method for retrieve the selected template schema
    ***************************************************************/
    public getTreeViewSchema(templateType : string, templateFile: string, afterSchemaGenerated : (result : Object) => any) : any {
        //#. First tree required editor map schema
        template.getEditorSectionMappingSchema((response : any) => {
            if (response.result == 'ok') {
                let editorMapSchema = _.find(response.schema.mappings, function (item : any) {
                    return item.type === templateType;
                });

                template.getTemplateSchema(templateFile, (tResponce : any) => {
                    if (tResponce.result == 'ok') {
                        let formSchema = tResponce.schema.form;
                        let templateSchema = tResponce.schema.schema;
                        
                        let sd = this.createDataSchema(templateSchema);
                        this.createTreeViewSchema(editorMapSchema, templateSchema, formSchema, (schemaResponce : any) => {
                            if(schemaResponce) {
                                schemaResponce.schemaData = sd;
                            }
                            afterSchemaGenerated(schemaResponce);
                        });
                    }
                });
            }

        })
    }

    dataSchema: any = {};
    createDataSchema(templateSchema : any, currentSchema?: any, dataKey?: any, isArrayPart?: boolean) {
        let self = this;
        let dataSchema = currentSchema || {};        
        if(templateSchema.type == 'object' || templateSchema.type == 'array'  || templateSchema.type == 'table') {
            let props = (templateSchema.type == 'array' || templateSchema.type =='table') ? templateSchema.items.properties : templateSchema.properties;
            _.forEach(props, (item : any, key: any) => {              
                 if(item.type == 'object') {
                     dataSchema[key] = {};
                     self.createDataSchema(item, dataSchema[key]);  
                 } else if(item.type == 'array'  || item.type == 'table') {                     
                     dataSchema[key] = {};
                     self.createDataSchema(item.items, dataSchema[key], key, true);
                     dataSchema[key] = [dataSchema[key]];
                 } else {                                                   
                     self.createDataSchema(item, dataSchema, key, isArrayPart);
                 }
            })
        } else {            
             dataSchema[dataKey] =  templateSchema.default || '';
        }
 
        if(currentSchema) {
            return true;
        }

        return dataSchema;
    }

    /*
  * Create the tree view schema based on the template
  ***************************************************************/
    rootobj : any;
    createTreeViewSchema(editorMapSchema : any, templateSchema : any, formSchema : any, afterSchemaGenerated : (result : Object) => any, parentItem?: any, nodeArray?: Array < any >) {

        if (!nodeArray) {          
            this.rootobj = templateSchema;
        }

        //#. Declarations
        let self = this,
            treeviewSchema = nodeArray || new Array < any > ();

        //#. Iterate the editor mapitems, vary beacuse its a recursive call
        _.forEach(editorMapSchema.items, (mapItem : any) => {
            let node = {};

            //#. Props 'll be declared as array of strings
            if (typeof mapItem === 'string') {

                //#. Get prop name from prop eg: docDscr.propname
                if (mapItem.indexOf('.') != -1) {
                    mapItem = mapItem;
                }

                //#. Get the corresponding template schema
                let tempItem = self.getPropDetailsFromEditorMapSchema(mapItem, templateSchema);                
            } else { // Managing theobject type items

                //#. Managing the virtual items
                if (mapItem.isVirtual === true) {
                    // #. Set the bsic node props  self.assignNodeProps(node, mapItem,
                    //#. If have siblings create nodes array
                    if (mapItem.items) {
                        node['nodes'] = new Array < any > ();
                        let tempItem = self.getPropDetailsFromEditorMapSchema(mapItem.key, templateSchema);
                        if (tempItem) {
                            templateSchema = tempItem;
                        }

                        //#. Recursive call for manage the siblings
                        self.createTreeViewSchema(mapItem, templateSchema, formSchema, undefined, mapItem, node['nodes'])
                    }
                } else if (mapItem.useTemplate === true) { // Resolve use template items

                    //#. Get form schemaitem and consider as a new editor schema item
                    editorMapSchema = _.find(formSchema, (uItem : any) => {
                        return uItem.key === mapItem.key;
                    })

                    this.resolveUseTemplate(mapItem, formSchema);

                    //#. If item have no form data, then resolve it from the schema
                    if (!editorMapSchema) {
                        let tempItem = self.getPropDetailsFromEditorMapSchema(mapItem.key, templateSchema);
                        if (tempItem) {                     
                            self.setJsonSchemaFormData(node, templateSchema, mapItem, nodeArray);
                            treeviewSchema.push(node);
                        }

                        return true;
                    }

                    //#. Create new nodes array for items
                    if (editorMapSchema.isVirtual || editorMapSchema.items) {
                        node['nodes'] = new Array < any > ();
                    }

                    //#. Recursive call for siblings
                    if (editorMapSchema.items) {
                        let tempItem = self.getPropDetailsFromEditorMapSchema(editorMapSchema.key, templateSchema);
                        self.createTreeViewSchema(editorMapSchema, tempItem, formSchema, undefined, editorMapSchema, node['nodes'])
                    }
                } else if (!mapItem.useTemplate) { //#. Manage usetemplate false items
                    //#. Array consider as end point
                    let tempItem = self.getPropDetailsFromEditorMapSchema(mapItem.key, templateSchema);
                    if (mapItem.items && mapItem.type !== 'array' && mapItem.type !== 'table') {
                        node['nodes'] = new Array < any > ();
                        self.createTreeViewSchema(mapItem, tempItem, formSchema, undefined, mapItem, node['nodes'])
                    }
                }
            }

            // #. Set the schema for data props            
            self.setJsonSchemaFormData(node, templateSchema, mapItem, nodeArray);            
            
            //#. Set the tree node hierarchy
            treeviewSchema.push(node);
        })

        //Recursive returns the true
        if (nodeArray) {
            return true;
        }

        //#. Trigger  the callback
        afterSchemaGenerated(treeviewSchema);
    }

    resolveUseTemplate(mapItem : any, formSchema : any, item?: Array < any >, isRec?: boolean) {
        let self = this,
            it = item
                ? item
                : new Array < any > ();
        _.forEach(formSchema, (sItem : any) => {
            if (sItem.key == mapItem.key) {
                it.push(sItem);
                return true;
            }

            if (sItem.items) {
                self.resolveUseTemplate(mapItem, sItem.items, it, true);
            }
        })

        if (isRec) {
            return true
        }

        if (it.length > 0) {
            _.assign(mapItem, it[0]);
        }
    }
  

    /*
  * Set json schema form data for tree nodes
  * virtualStore - For keep the virtual store items
  ***************************************************************/
    virtualStore : any = {};
    setJsonSchemaFormData(node : any, templateSchema : any, formSchema : any, nodeArray : any) {

        let key = formSchema.key;
        let title = formSchema.title || key;
        let sdata = {};
        node['key'] = key;
        node['title'] = title;

        if (formSchema.isVirtual === true) {
            let y = _.findKey(this.rootobj.properties, templateSchema)
            sdata[y] = templateSchema;
            node['schema-data'] = sdata;
            node['schema-layout'] = [formSchema];
            if (y === undefined) {
                node['schema-data'] = templateSchema.properties;
                node['schema-layout'] = formSchema.items;
            }
        } else {
            let prop;
            if (key && key.indexOf('.') !== -1) {
                key = key.split('.')[0];
                prop = templateSchema;
            } else {
                prop = this.getActiveSchemaProps(templateSchema, key);
            }
            if (prop) {
                sdata[key] = prop;
                node['schema-data'] = sdata;
                node['schema-layout'] = [formSchema];
            }
        }

        if (!nodeArray) {
            delete node['schema-data'];
            delete node['schema-layout'];
        }
    }

    /*
  * Get active schema props from the template schema
  ***************************************************************/
    getActiveSchemaProps(templateSchema : any, propName : string) {
        let property;
        if (templateSchema.type == 'object') {
            property = templateSchema.properties[propName];
        } else if (templateSchema.type == 'array'  || templateSchema.type == 'table') {
            property = templateSchema.items.properties[propName];
        }

        return property;
    }
   

    /*
    * Method returns the current mapping schema
    ***************************************************************/
    private getPropDetailsFromEditorMapSchema(keyName : string, editorMapSchema : any) {
        if (editorMapSchema.type == 'object') {
            return editorMapSchema.properties[keyName];
        } else if (editorMapSchema.type == 'array'  || editorMapSchema.type == 'table') {
            return editorMapSchema.items.properties[keyName];
        } else {
            return _.find(editorMapSchema.items, function (item : any, index : number) {
                return item.key == keyName;
            })
        }
    }

    /*
    * Get the default tree view methods
    * todo - move to config
    ***************************************************************/
    public defaultTreeOptions() {
        return {
            idField: 'key',
            displayField: 'title',
            childrenField: 'nodes',
            isExpandedField: 'expandable',
            allowDrag: true,
            nodeClass: (node : TreeNode) => {
                if (node.isCollapsed) {
                    return 'ast-treeview-folder-collapsed';
                } else {
                    return 'ast-treeview-folder-expanded';
                }
            }
        }
    }
}